Python SMS scripting

4 minute read Published: 2015-06-11


Foreword from the future :magic-hands:

This post is a simple summary of how you can accomplish SMS text messaging via web APIs. Services exist today like Twilio that are massively popular, but a decade ago these were not as stable or accessible. This post is based on source code from my py2sms repository, which showcased how you could do this. This was forked from another project that was based on another SMS API service.

The goal

We're going to build a simple script showcasing how you can send text messages with Python. The service I'm going to utilize for this is eztexting. This will utilize a popular HTTP library and be implemented for Python 3.

The API

The API for sending SMS messages with eztexting allows you to POST data to an endpoint with your authentication info (username/password), a list of numbers, and the message content. The format is optional, and in this case we're going to prefer JSON since it's straightforward to define Python dictionaries and serialize them to JSON with the json package.

HTTP requests

While Python has standard libraries for working with HTTP, they can feel clunky in regards to developer experience. You have to handle a lot of defaults and calls and objects to do this yourself. Due to this, I'm going to rely on [requests], a popular HTTP request library for Python. requests touts itself as "HTTP for Humans. An elegant and simple HTTP library for Python, built for human beings." I would request this for anyone not doing low-level networking type of work with Python, and even then consider whether you really need to subject yourself to the world of urllib`` and http`.

Coding it up

API Credentials

This is just a proof of concept, so in this solution I'm going to have a very basic approach to secrets management and the overall script safety. To start off, we're going to need a way to load credentials without embedding them in our version control. In my case, I define a credentials file which I configure git to ignore with a .gitignore entry:

# .gitignore:
/credentials

Now I can throw my username and password for eztexting in there

# /credentials
a_username
def1n1t3lyMyP@ssword

Dependencies

Now let's make sure we have our dependencies. In my case I'm using requests, pprint, and json. The first two need to be installed in your system. There are better ways to do this than global installs, like a virtualenv. You would run this inside there:

pip install requests pprint

And then you can import these with

import json
import pprint
import requests

HTTP Requests

Next, we'll create an HTTP request with the necessary URL and body using my credentials:

cred = open('credentials', 'r').readlines()
addr = "https://app.eztexting.com/sending/messages?format=json"
number = str(pnumber)
message= str(msg)
content = {
    'User': cred[0].strip(), 
    'Password': cred[1].strip(),
    'PhoneNumbers[]': '555-123-4567,
    'Message': 'Hello world'
}

r = requests.post(addr,data=content)

This technically works as is, other than eztexting blowing up about the number. A successful response is going to be indicated with a 204, 'No Content', HTTP status code.

Wrapping it all up

Let's check the status and log errors, and finally parameterize the logic so it can be called as a function by other modules. Here's the final code afterward:

#  _____   __     __  ___     _____   __  __    _____ 
# |  __ \  \ \   / / |__ \   / ____| |  \/  |  / ____|
# | |__) |  \ \_/ /     ) | | (___   | \  / | | (___  
# |  ___/    \   /     / /   \___ \  | |\/| |  \___ \ 
# | |         | |     / /_   ____) | | |  | |  ____) |
# |_|         |_|    |____| |_____/  |_|  |_| |_____/ 
#                                                     


import json
import pprint
import requests
# 'pip install requests' to install this library


with open('credentials','r') as c:
		cred = c.readlines()

def sms(pnumber,msg):
	addr = "https://app.eztexting.com/sending/messages?format=json"
	number = str(pnumber)
	message= str(msg)
	content = {
		'User': cred[0].strip(), 
		'Password': cred[1].strip(),
		'PhoneNumbers[]': number,
		'Message': message}
	pprint.pprint(content)
	r = requests.post(addr,data=content)
	if r.status_code != 204:
		pprint.pprint(r.json())
	else:
		print("Status code 204: No content returned")

# To send a text message call the function with
# sms(phonenumber,'sending this text message')
# sms(5551235555,'Hello World!')

Documentation!

A project can always use a README. It helps people get started in your codebase and understand further context behind decisions, design, and more.

# About

Fork of the py2sms project which was based off the <b>textbelt</b> service.

Due to limited functionality and inconsistent service, this implementation will utilize the <b>eztexting</b> service instead.

# How To Use

You will need to create a <b>free</b> account at <a href="https://www.eztexting.com/start?pid=free">eztexting.com</a>, and add your username/password to the credentials file.

The script pulls this info to make requests to the RESTful API. 

You are alotted a total of 500 messages per month with this service. 

# API Documentation

https://www.eztexting.com/developers/sms-api-documentation/rest