Creating a serverless SMS-Twitter app with AWS Lambda & Twilio
I use WIFI for most of my internet needs. This means I sometimes am unable to connect to the internet and eventually find myself needing to share some quick thoughts or get updates (like a DM or a mention) when I’m outside a WIFI zone.
Because SMS messages are really cheap and don’t require a subscription fee, I decided on a small project that allows me to send out tweets and receive direct messages via SMS.
This can easily be expanded to include sending direct messages and receiving notifications for mentions, follows, retweets etc.
To complete, I needed:
A Twilio account
An AWS account
A Twitter developer account
Some Python knowledge
While I did a lot of shuffling (between AWS, my Twitter developer account and Twilio) to set this up, I am breaking it down into three sections. This way, it is hopefully easier to follow along for anyone trying to replicate or understand one specific part of what I did.
Setting up Twilio
We will need to create a Twilio account and buy a phone number (trial accounts come with free credits you can use for this). Then we’ll add a number as a verified number.
To be able to communicate with any phone number on a trial account, it needs to be on the list of verified numbers.
Next, we head over to the Twilio phone number management console and add a webhook for received SMS messages. Note that this webhook will point to an API endpoint configured to trigger an AWS Lambda function whenever it receives a POST request (we see how to do this in the AWS section).
What this webhook does is make a request to the given endpoint each time an SMS message comes in. The POST request body will carry all details of the incoming SMS which we can then process as necessary.
Twilio allows us to specify an SMS reply in the response. This is great for providing feedback to a user (we will see this in the Lambda code).
Setting up the Twitter Developer Account
To get access to Twitter API keys, we create a Twitter app and provide the necessary information. Ensure your app has read, write and direct messages permissions. Then, generate an Access Token and Access Token Secret.
You will need to create a development environment for the Accounts Activity API to pass information about twitter events to you.
This page gives an idea of what events twitter sends notifications for, and what data is available.
Our endpoint will also need to process CRC requests (this is a security measure) before it can be successfully registered. We handle this later in the AWS section.
Add your webhook to twitter
When the code above runs, Twitter will make a GET request for a crc_token. If successful, Twitter will begin sending POST requests containing event information to the URL provided in
webhook_endpoint = urllib.parse.quote_plus(‘https://yourdomain.com/yourendpoint')
See the Twitter API documentation for further reading.
Setting up the AWS Lambda function
To use Lambda, we need to create an account with Amazon web services (a valid payment method will be required)
After this, we can sign up for the AWS free tier to get access to basic features.
SMS to Tweets
Navigate to AWS Lambda and create a new function.
We wouldn’t be needing any templates, so select the “Author from scratch” option. Name the function and choose a runtime (I used Python 3.7 for this).
Let's add environment variables to store some values we will need in our code. We’ll add our Twilio auth token, API endpoint and Twitter API keys.
Now we have a function, but we need to create a trigger. This lets us decide how to start the function. We can do this a number of ways, but for now, we will be using an API Gateway. This way Twilio can call the endpoint whenever an SMS comes in, our function will then take care of the rest.
Select API Gateway under the add triggers menu. And create a new API. By default, AWS sends the whole request body to the event and will throw an error for non-JSON responses. We will need to change that behaviour.
See this Twilio doc to understand how this can be done.
Now we can parse Twilio requests and respond in a format Twilio understands, let’s write the code to allow us to create tweets via SMS.
We start by clearing the Lambda sample code and importing all the libraries we will need (this will throw an error. I’ll explain why and how to fix it in a bit).
Then we will define a function which takes an event and a context (you can name this function whatever you want but ensure the name matches what is specified in the Handler).
AWS Lambda passes the request body in the event.
Next, we start an if statement to check for the twilioSignature header and Body in the event. If present, we go on to validate that this is not a malicious request (using the Twilio Request Validator) and update the Twitter status with Tweepy, else we handle appropriately.
Click save in the top right corner.
Great! We have a function set up to handle SMS triggered requests. But this function will fail because we have imported libraries that Lambda cannot access.
To provide Lambda with the required libraries, we need to build and upload a package with our code and the required libraries.
On your local machine, create a new folder and include a .py file containing your Lambda code inside.
Next, open up command prompt and cd to the folder you created, then use pip to install all required libraries with the following command
pip install [PACKAGENAME] — target .
We then need to put the files (.py files and library folders) into a .zip file.
In AWS, under the Function Code -> Code entry type, select upload a .zip file and upload your zip file.
Our code should be working well now. Sending an SMS to our Twilio number should create a new tweet and update us with SMS confirmation.
Tweet notifications with account activity API
We’ve managed to write some code to let us post tweets, but what if we want to be notified when events occur. For example, when we receive a DM or have a new mention or follower?
To do this, we need to create a second lambda function and register a webhook (registering the webhook has been covered in the Twitter section).
Our new function will need to be able to both handle CRC requests and events from Twitter.
We add some environment variables and create an API Gateway trigger (Twitter sends and expects JSON so we do not need to do any extra configuration on our endpoint)
Let’s now write the code to handle CRC requests.
Again we clear the sample code and check if this is a GET request. If it is then we know it is a CRC request and we generate and return the required response.
At this point, we can register the endpoint which triggers this function with Twitter and begin receiving event updates. But we also need to write the code to handle events.
To do this, we check if it is a POST request (Twitter will send event updates as POSTs) and load the request body as JSON. We then check if the SEND_NOTIFICATIONS environment variable is set to true, if this message is a direct message event, and if the direct message sender is not us (Twitter will send updates for messages we create as well, we do not want notifications for these).
If this is a direct message sent by someone else, we get the sender and the message and use Twilio to send an SMS update with the details to our phone number
Note that while Twilio has an awesome helper library for creating requests, we used Python Requests instead (smaller package file and easier since we don’t need some of the more advanced Twilio functions).
You may encounter some problems if importing Requests takes too long. If this happens, then you will need to increase the timeout under Basic Settings for your Lambda function.
See more about handling CRCs and managing Twitter webhooks here.