Building a Bulk SMS Service with Python, Flask and Twilio Notify

April 01, 2020
Written by
Philip Obosi
Contributor
Opinions expressed by Twilio contributors are their own

Building a Bulk SMS Service with Python, Flask and Twilio Notify

As of October 24, 2022, the Twilio Notify API is no longer for sale. Please refer to our Help Center Article for more information. 

Very often, large companies use SMS to communicate or send broadcast messages to their users. This is because SMS is reliable and usually has more reach and engagement than most other forms of bulk messaging. In addition, it enables companies to communicate with users who do not have smartphones.

In this article, we are going to use the Twilio Notify service, along with Python and the Flask framework to build a Bulk SMS service.

User journey

The user creates a message, inputs the phone numbers of the recipients of the message, and then sends them an SMS as shown in the video GIF below.

bulk sms demo

Tutorial requirements

To follow this tutorial, you are expected to:

  • Have sufficient understanding of Python and Flask.
  • Have Python 3 installed on your machine
  • Have a Twilio Account. If you are new to Twilio, create a free account now.

Setting up your Twilio account

To follow this tutorial, you need your Twilio Account SID, Auth Token  and Twilio phone number. You can get the Account SID and Auth Token here:

twilio account credentials

Twilio Notify

Twilio Notify enables you to send notifications to any number of recipients with one API request. To use Twilio Notify, you must first create a Messaging Service. From the Twilio console go to the messaging service section under Programmable SMS and create a new messaging service. Give the messaging service any name of your choice. For the use case section, choose “Notifications, Outbound only”.

create a new messaging service

Next, select “Services” in the Notify section of the Twilio console. Click on the red plus button and choose a name for your Notify service. 

create a new notify service

Now select the messaging service your created earlier in the “Messaging Service SID” dropdown: 

notify service configuration

Press the “Save” button at the bottom to apply this change.

Take note of the “SERVICE SID” that appears below the friendly name, as we are going to use it later to send our SMS. 

Buying a Twilio phone number

Now you need to purchase a Twilio phone number for your app here on your Twilio console.  Select your country from the dropdown and search for available numbers. If you wish to get a number containing specific digits, you could enter them in the field provided as shown below.


buy a twilio phone number

After searching, you will be shown a list of available numbers from which you can make your purchase.

To configure your messaging service to use the phone number you have purchased, go to your Twilio SMS service section on the console and click on the messaging service you created earlier. You’d see a screen like the one below:

add phone number to messaging service

Click on “Add an Existing Number” and select the phone number you purchased.

Application setup

As mentioned earlier, we are going to be using the Flask framework for this project.

Creating the application directory and virtual environment

Make sure you have Python 3 installed on your computer. Run the following commands in your terminal to create the project directory and virtual environment for this project.

- Create project directory named twilio_bulk_sms

    mkdir twilio_bulk_sms

- Enter into the project directory

    cd twilio_bulk_sms

- Create a virtual environment for the project

    python -m venv venv

- Activate the virtual environment

    For macOS and Linux users:

    source venv/bin/activate

    For windows users:

    venv\Scripts\activate

The virtual environment helps create an isolated environment to run our project.

Structuring the project

Next, we are going to set up the project’s directory structure. In the application directory, run the command below to create a directory where we are going to put utility functions our application will need:

    mkdir utils

Installing project dependencies

Finally, let’s install all the dependencies we are going to use in this project.

- Flask: This library will be used to run our web server.

- Twilio Python Helper Library: This library will be used to help send sms.

- Flask Cors - This flask extension handles Cross Origin Resource Sharing (CORS), making cross-origin AJAX requests possible.

- Python-dotenv - Reads the key-value pair from your .env file and adds them as environment variables.

You may run the command below to install the above dependencies:

    pip install flask twilio flask_cors python-dotenv

Building the API

In this section, we are going to build an API to send SMS messages in bulk to the supplied phone numbers. First of all, we are going to write the function to send SMS messages to users. Create a file called sms.py in the utils directory and paste the code snippet below in it.

import os
import json
from twilio.rest import Client

ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID')
AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN')
NOTIFY_SERVICE_SID = os.getenv('TWILIO_NOTIFY_SERVICE_SID')

client = Client(ACCOUNT_SID, AUTH_TOKEN)


def send_bulk_sms(numbers, body):
    bindings = list(map(lambda number: json.dumps({'binding_type': 'sms', 'address': number}), numbers))
    print("=====> To Bindings :>", bindings, "<: =====")
    notification = client.notify.services(NOTIFY_SERVICE_SID).notifications.create(
        to_binding=bindings,
        body=body
    )
    print(notification.body)

In the snippet above, we set the ACCOUNT_SID, AUTH_TOKEN and the NOTIFY_SERVICE_SID from environment variables.

The send_bulk_sms function accepts the list of users we want to send the SMS to as a list of dictionaries, each having at least a phone key. As a second argument the function takes the message body we want to send.

We use Python’s lambda function with map() to convert the list of users to the Twilio binding format. Each phone number is turned into a dictionary in the format shown below:

{"binding_type": "sms", "address": "<number>"} 

The dictionary is then converted into a string because the to_binding param accepts a list of strings.

Next, we are going to write utility functions for validating our request body and sending API responses. Create a file called request.py in the utils folder and paste the following snippet inside:

def validate_body(data, required_fields):
    for field in required_fields:
        if field not in data:
            return False, field
    return True, None

Create a file called response.py in utils folder and paste the code below in it. The code below helps format the responses that we’d be sending back to the client.

import json
import time

from flask import jsonify


def stringify_objectid(data):
    str_data = json.dumps(data, default=str)
    return json.loads(str_data)


def response(status, message, data, status_code=200):
    """
    :param status : Boolean Status of the request
    :param status_code: Status Code of response
    :param message : String message to be sent out as description of the message
    :param data : dictionary representing extra data
    """
    if data:
        data = stringify_objectid(data)
    res = {'status': status, 'message': message, 'data': data, 'timestamp': timestamp()}
    return jsonify(res), status_code


def error_response(message, status='error', code='R0', status_code=400):
    res = {'message': message, 'status': status, 'code': code}
    return jsonify(res), status_code


def timestamp():
    """
    Helper Function to generate the current time
    """
    return time.time()

Finally, we need to create a app.py file in the main directory with the code snippet below:

from flask import Flask, request
from flask_cors import CORS

from dotenv import load_dotenv
load_dotenv()

from utils.request import validate_body
from utils.response import response, error_response
from utils.sms import send_bulk_sms

app = Flask(__name__)

CORS(app)

@app.route('/message', methods=['POST'])
def message_audience():
    body = request.get_json()
    status, missing_field = validate_body(body, ['message', 'phones'])
    if not status:
        return error_response(f'{missing_field} is missing')
    send_bulk_sms(body['phones'], body['message'])
    return response(True, 'Success', None)


if __name__ == '__main__':
    app.run()

The snippet above creates an endpoint with the /message URL that accepts the message and phones parameters. It then validates them using the utility functions created above, and finally sends the message via Twilio to the supplied numbers using the send_bulk_sms utility function.

Testing the API

To run the application, make sure you set the TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN and TWILIO_NOTIFY_SERVICE_SID in a .env file at the root of the project:

TWILIO_ACCOUNT_SID="<your-twilio-account-sid>"
TWILIO_AUTH_TOKEN="<your-twilio-auth-token>"
TWILIO_NOTIFY_SERVICE_SID="<your-twilio-notify-service-sid>"

Then execute the command below in your terminal:

    python app.py

You should see something like the image below displayed in your terminal:

running flask web application

For the sake of testing this API, I have gone ahead to build a demo client application in React JS. The code for this application can be found here on GitHub. You may follow the steps below to set it up locally:

  • Install Node JS on your machine following the instructions here.
  • Clone the repository by executing the command below in a new terminal:
git clone https://github.com/worldclassdev/twilio_bulk_sms_client.git
  • Next, enter the project directory:
cd  twilio_bulk_sms_client
  • Install the project’s dependencies by executing the command below:
npm i
  • I have added a proxy to the project’s  package.json to help us send all unknown requests to our API which is hosted on port 5000.
  • Now start up the application using the command below:
npm start

Conclusion

We have now come to the end of the tutorial. We have successfully built a bulk SMS service with Python, Flask and Twilio. Make sure to explore the Twilio Programmable SMS API to see more ways it can be applied to build amazing software.

You will find the source code for this tutorial here on GitHub.

See you in the next one!✌🏿

Philip Obosi is a Software Engineer based in Lagos, Nigeria who loves to  build scalable web applications with JavaScript and Python. He is passionate about web performance, data visualization and the blockchain.