How to Export a CSV file with Message Resources Using Twilio Programmable SMS

June 17, 2020
Written by
Diane Phan
Twilion
Reviewed by
Paul Kamp
Twilion

header- How to Export a CSV file with Message Resources Using Twilio Programmable SMS

If you’re utilizing SMS text messaging to interact with an audience of subscribers or consumers, it can be difficult to keep track of the frequency (and message content) you’ve sent out.

One way for you to look at message volume and content is to utilize the Twilio CLI to find what you need. However, sometimes you just need a quick way to export message history as you build out your Python app and start to improve your customer engagement. Completing this tutorial will allow you to export a .csv file with a history of messages you’ve sent out to clients, as well as a file of their responses for you to analyze.

Follow along in this post to learn how to fetch filtered message resources using Twilio Programmable SMS, Python, and Flask.

Tutorial Requirements

In order to build this project, you will need to have the following items ready:

  • Python 3.6 or newer. If your operating system does not provide a Python interpreter, you can go to python.org to download an installer.
  • ngrok. We will use this handy utility to connect the development version of our Python application running on your system to a public URL. This is necessary for the development version of the application because your computer is likely behind a router or firewall, so it isn’t directly reachable on the Internet. If you don’t have ngrok installed, you can download a copy for Windows, MacOS or Linux.
  • A free or paid Twilio account. If you are new to Twilio get your free account now! (If you sign up through this link will give you $10 credit when you upgrade.)

After you have downloaded the requirements, we can move forward with the coding portion.

Configuration

We’ll start off by creating a directory to store our project files. Inside your favorite terminal, enter:

bash
$ mkdir msg-resource
$ cd msg-resource

Since we will be installing some Python packages for this specific project, let’s create a virtual environment.

If you are using a Unix or MacOS system, open a terminal and enter the following commands:

bash
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip install flask python-dotenv twilio

Depending on what version of Python you are on, you might have to specify Python3.

 

If you are on a Windows machine, enter the following commands in a prompt window:

text
$ python -m venv venv
$ venv\bin\activate
(venv) $ pip install flask python-dotenv twilio

If you are curious to learn more about the packages, you can check them out here:

  • The Flask framework, to create the web application that will receive message notifications from Twilio
  • The python-dotenv package, to load the environment variables created
  • The python-twilio package, to send messages through the Twilio service

Configure Twilio SMS

This is where we make sure you have a Twilio number activated.

Log onto the Twilio Dashboard to view your Active Numbers. Click on the number you want to use to view the details. If you haven’t purchased a number yet, learn how to search for and buy a Twilio phone number.

Receive and send messages with Twilio

The goal of our app is to track the history of messages from you and your clients which utilize a Twilio number. We also need to make sure that all of the responses from your audience are received properly. We’ll go more into depth on how your audience should be using this program.

Send messages

Let’s start by sending out some text messages from your app.

We will have to create a .env file to safely store some important credentials that will be used to authenticate against the Twilio service. Here is what the .env file should look like:    

text
TWILIO_ACCOUNT_SID="<your account SID>"
TWILIO_AUTH_TOKEN="<your auth token>"
TWILIO_NUMBER= #use your Twilio Number here 
RECIPIENT_NUMBER= #your number here   

For the TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN variables, you can obtain the values that apply to your Twilio account from the Twilio Console:

Twilio account SID and auth token

For the purpose of this tutorial, use your personal phone number as the RECIPIENT_NUMBER so you can view the progress as we build out the app. Make sure that both TWILIO_NUMBER and RECIPIENT_NUMBER are in the E.164 phone number representation.

After the authentication process, we will send a message to ourselves from Python. Create a Python file called app.py and add the following lines:

python
import os
from dotenv import load_dotenv
from flask import Flask, request, url_for
from twilio.twiml.messaging_response import MessagingResponse
from twilio.rest import Client
from datetime import datetime

load_dotenv()
app = Flask(__name__)
TWILIO_ACCOUNT_SID =  os.environ.get('TWILIO_ACCOUNT_SID')
TWILIO_AUTH_TOKEN =  os.environ.get('TWILIO_AUTH_TOKEN')
TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER')
RECIPIENT_NUMBER = os.environ.get('RECIPIENT_NUMBER')

client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)

message = client.messages.create(
                              from_=TWILIO_NUMBER,
                              body='body',
                              to=RECIPIENT_NUMBER
                          )
print(message.sid)

Type python3 app.py on your console to run this file.

Now, check your phone – you should have received a text message from your TWILIO_NUMBER with the message “body”.

In your console, you should see a print statement that starts with an “SM” and looks something like SMxxxxxxxxxxxx. The “x” letters here are a unique juxtaposition of alphanumeric characters. This is an sid, also known as a Twilio-provided string that uniquely identifies the Message resource.

Depending on what else you would like to see in your .csv file, this unique sid will gather other pieces of information that you might need to analyze your messages. You can view other keys in the JSON API Response on the Twilio Docs.

Receive messages

The Twilio API for Programmable SMS uses a webhook (web callback) to allow real-time data to be delivered to other applications. This is especially important, since we want to record what our audience is saying back to us.

Here’s some code to help you write your first webhook handler. Add the following route and function to your app.py Python file:

python
from flask import Flask, request

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    recipient = request.form.get('From')
    message = request.form.get('Body').lower()
     #TODO: Add a response 

We have a few things going on with the code above. The @app.route is a decorator from the Flask framework, which instructs Flask to serve a route at our chosen location (in our case, /webhook). This decorator will work with our webhook() function so that we can receive and react to incoming messages from any user.

We also created a recipient variable which receives a value from Flask’s request.form function. When we look at the From number, Flask is able to parse the phone number of the sender in E.164 phone number representation.

Creating the recipient variable is essential for our case – we will need to keep track of the users and numbers who are in the directory. You can play around and parse other variables in a text message, but for now, we’ll move on to the next part of our project.

Reply to a message

Next, we have to handle confirming with a recipient that we received their text message. The webhook allows us to issue a response to the recipient, the one who sent the message, by providing a TwiML payload in response to the webhook. TwiML is short for Twilio Markup Language, an XML-based syntax that the webhook can use to provide instructions to Twilio regarding how to handle the message.

The Twilio Helper Library for Python allows us to generate TwiML responses using classes and objects, and pairs perfectly with Flask.

For our project, we will utilize best programming practices by writing the definition for a respond() function so that we can call it throughout our project to generate a response that is sent back to the sender.

python
from twilio.twiml.messaging_response import MessagingResponse

def respond(message):
    response = MessagingResponse()
    response.message(message)
    return str(response)

Add the new import line to the top of the app.py file and the new respond() function above or below the webhook.

Don’t forget to call the newly created function in the webhook, too. Here’s an example of what your starter code might look like:

python
@app.route('/webhook', methods=['POST'])
def webhook():
    recipient = request.form.get('From')
    return respond(f'Hi {recipient}!\nyour message was received')

If you are curious to see how TwiML looks, start a Python shell and enter the following code to generate an example response:

python
>>> from app import respond
>>> respond('this is my response')
'<?xml version="1.0" encoding="UTF-8"?><Response><Message>this is my response</Message></Response>'

Message response TwiML for prototyping an Animal Crossing team collaboration App

Set up a webhook with Twilio

By now, we’ll have our code for our first webhook function.

However, to make sure it works, we must test it out and make sure it’s running properly by sending and receiving a few text messages.

Add a .flaskenv file (make sure you have the leading dot) to your project with the following lines:

bash
FLASK_APP=app.py
FLASK_ENV=development

These incredibly helpful lines will save you time when it comes to testing and debugging        your project.

  • FLASK_APP tells the Flask framework where our application is located
  • FLASK_ENV configures Flask to run in debug mode

These lines are convenient because the server will automatically reload when changes are made to the code, and you will not have to restart the server while you are adding more code to your application. That is: every time you save the source file, the server will reload and reflect the changes. Neat huh?

So, we’ll move forward by starting our Flask application with the following command:

bash
(venv) $ flask run

Image depicts the console output for the "flask run" command

The screenshot above displays what your console will look like after running the command flask run. The service is running privately on your computer’s port 5000 and will wait for incoming connections. You will also notice that debugging mode is active, and that my flask server restarted to reflect my changes.

While flask is running in one terminal window, open up a second tab or terminal window. Start ngrok with the following command:

$ ngrok http 5000

Great, you have now enabled your Flask service publicly over the Internet!

Ngrok is a great tool because it allows you to create a temporary public domain that redirects HTTP requests to our local port 5000.

Note that if you are unable to install ngrok system-wide, try to locate the executable ngrok file in order to call it in your terminal using its full path.

Make sure to return to this step and make sure ngrok is located and executable in the correct directory.

Example ngrok run tunneling your app on port 5000

Your ngrok terminal will now look like the picture above. As you can see, there are URLs in the two “Forwarding” lines. These are public URLs that ngrok uses to redirect requests into our flask server.

Copy the URL starting with https:// and return to the Twilio Console, where we will tell Twilio to send incoming message notifications with this URL.

In the Twilio Console, click on the (...) on the left sidebar to scroll down and find Phone Numbers. Click on the active phone number that you want to use for this project and scroll down to “Messaging”.

Paste the URL copied from the ngrok session into the “A MESSAGE COMES IN” field and append /webhook, since that is the endpoint we defined with the app decorator above.

Here is my example for reference:

Messaging callback or webhook inside the Twilio console

The URL from ngrok is https://ad7e4814affe.ngrok.io/webhook 

Before you click on the “Save” button, make sure that the request method is set to HTTP POST.

Time to test things out! Grab your SMS-capable phone, and send a text message to your active Twilio number. I sent something random such as “Webhook attached” and my Twilio Number responded with a confirmation message.

Example run of the SMS CSV file exporting app

Export message resource .csv files

Filter messages

After you send out messages to your audience using the Twilio Number, you can start filtering out the messages you want to view by date. There are plenty of ways to filter as you may notice here in the Twilio Docs

For me, I wanted to check out 5 messages I sent on June 9, 2020.

Using Python’s datetime library, we can use the datetime object to specify the numbers for the date and time. In my example, I used datetime(year, month, day, hour=0, minute=0, second=0) to conduct my search. Be sure to modify the date to today’s date, or whenever you last sent text messages.

We can also use limit as a parameter to query the appropriate results. Here’s an example of what my filtered message history looks like:

python 
filtered_message_history = client.messages.list(
                               date_sent=datetime(2020, 6, 9, 0, 0, 0),      #or your chosen date
                               from_=TWILIO_NUMBER,
                               to=RECIPIENT_NUMBER,
                               limit=5
                           )

Let’s check and see if this is correct and you actually sent these text messages out from your TWILIO_NUMBER on the provided datetime.

We’ll write the following for loop to iterate through our filtered_message_history:

python
for msg in filtered_message_history:
    print(msg.sid + ', ' + msg.body)

Add these below the filtered_message_history. The print statement takes the msg object and extracts the sid with the body of the message.

Recognize the body part? If you do, then you’re on the right track to obtaining the filtered messages!

Write to the .csv file

Our filtered_message_history variable is currently storing the values of the messages you sent to the specified recipient. In order to save these to a .csv, we’ll use the csv library in Python.

The following lines of code will open (or create, if it doesn’t exist) a file sender_message_history.csv. The second parameter indicates the action that will happen on the file. The w means that we will write to the .csv file.  

python 
sender_history_csv = open('sender_message_history.csv','w')
for record in filtered_message_history:
    sender_history_csv.write(record.sid + ',' + record.body + '\n') 
    #prints the SID of the text message from TWILIO_NUMBER to RECIPIENT_NUMBER
sender_history_csv.close()

As you can see, we loop through each record from the filtered_message_history and call the built-in write function on the JSON keys that you are using in your code. I decided to save the sid of the record so I can distinguish between each unique message that was sent, as well as the body message that matched the SID.

Check out the other keys that you can call in the Twilio Docs.

After you are satisfied with the .csv file, you will call the built-in close function on the file so your program can stop writing.

Alter the the contents in the .csv file

To save the records from your audience, you would follow the same steps above to open or create a new .csv file. However, if you have multiple recipients that you interact with, you might want to change the code so that you can keep track of which recipient sent the message.

The following code writes the RECIPIENT_NUMBER to recipient_messages_csv first by calling a from_ key on the array of  recipient_messages. Afterwards, your for loop is called to proceed writing every body message sent from RECIPIENT_NUMBER.  

python 
recipient_messages_csv = open('recipient_messages_history.csv','w')
recipient_messages = client.messages.list(
    date_sent=datetime(2020, 6, 12, 0, 0, 0),   #or your chosen date
    from_=RECIPIENT_NUMBER,
    to=TWILIO_NUMBER,
)
recipient_messages_csv.write(recipient_messages[0].from_ + ',')
for msg in recipient_messages:
    recipient_messages_csv.write(msg.body + ',')
recipient_messages_csv.close() 

Here’s an example of what my recipient_messages_csv looks like. I texted a bunch of nonsense to my TWILIO_NUMBER to make sure every message was recorded properly.

Example text message run of the SMS CSV file exporting app

Notice that the words “Add”, “My”, and “Number” were added to recipient_messages_csv along with other messages that I have sent before and after those words shown above.

Example run of the CSV file of messages from the file exporting app

Fetch message resources and export content

Make sure that all of your code has been saved and that you have one tab running flask and one tab running ngrok. If you closed a tab for any reason, open the terminal again and start the corresponding process with the following commands in their respective tabs.

In the Flask tab:

(venv) $ flask run

And in the second, run the ngrok tab:

$ ngrok http 5000

Furthermore, make sure that your SMS endpoint is configured with the forwarding URL reported by ngrok. Each time you restart ngrok the URL changes, so you will have to replace the URL in your Twilio Active Phone Numbers console.

Remember to add the /webhook at the end of the ngrok forward URL.

If you are running flask and ngrok at this point, text yourself a few more times. Then, rerun the app.py file again and check your directory msg-resource to find two .csv files. You can see the text messages you just sent to yourself in the sender_history_csv file.

Example of directory of files for your SMS message exporting CSV app

Conclusion: Exporting CSV Files with Message Resources

Congratulations, now you can further analyze your interactions between you and your recipients through these newly created .csv files! This simple SMS tutorial showed you how to fetch your message history and filter it appropriately for your use cases. Feel free to view the completed code on GitHub.

You can perform further analysis or simply remember what type of messages you have been sending to your recipients... whether they were friends, subscribers, or contacts of any sort.

What’s next for fetching message resources?

I hope that this tutorial demonstrated your ability to write code to make your life easier – and that you’re using the results to create memorable connections with your audience.

Looking for more ways to expand? Try the following:

  • Alter the code so that you can fetch the message history from a list of 2+ recipients
  • Export the message resource history from WhatsApp

Let me know if this tutorial improves your daily workflow! You can also learn more about sentiment analysis and to build a stronger brand for yourself.

Diane Phan is a Developer Network Intern on the Developer Voices team. She loves to help beginner programmers with growing businesses write code to improve their audience engagement and discover tools to enhance their workflow. She can be reached at dphan [at] twilio.com.