How to build a SMS-to-Slack Bridge with Python and Twilio
Time to read: 8 minutes
In this tutorial, we’ll be looking at how to build a SMS-to-Slack bridge using Python and Twilio. The bridge will work in such a way that every time your Twilio phone number receives an SMS message, we’ll forward the content of the SMS message to a channel in Slack. Furthermore, any threaded replies in Slack to the message that was posted will automatically be sent as an SMS message to the originating number.
Technical requirements
To follow along, you’ll need the following:
- A free Twilio Account. If you use this link to register, you will receive $10 credit when you upgrade to a paid account.
- A free Slack account, and a Slack workspace you have administrator access to.
- Python 3
- Ngrok. This will make the development version of our application accessible over the Internet.
Creating a Python environment
Let’s create a directory where our project will reside. From the terminal, run the following command:
Next, cd
into the project directory and run the following command to create a virtual environment.
To activate the virtual environment, run the following command:
If you are using a Windows computer, then the activation command is different:
Next, we’ll need to install all the dependencies our project will need:
- Flask: a Python web framework.
- Twilio-Python: A helper library that makes it easy to interact with the Twilio API.
- Python Slack Client: A helper library for interacting with the Slack API.
- Python-dotenv: A library for importing environment variables from a
.env
file.
To install all the dependencies at once, run the following command:
Creating a Slack webhook endpoint
As part of creating the Slack bot, we need to define an endpoint where Slack can forward messages that are posted in a channel. Before we can successfully configure that endpoint, Slack needs to verify and ensure that the endpoint is valid, so we’ll begin by implementing the verification portion of our Slack endpoint.
To pass Slack’s verification, the endpoint needs to return a response with the value of a challenge
key contained in the payload Slack sends to it in the verification request. You can read more about this process here.
Create a main.py file at the root of the project’s directory and add the following code to the file:
Here, we’ve created an endpoint with the /incoming/slack
URL and specified the HTTP method to be POST
. The challenge
key is obtained from the request
object from the Flask framework and returned back as a response
in plaintext, according to the verification requirements from Slack.
Run the following command in your terminal to start the Flask application:
Setting up Ngrok
Since our application is currently local, there’s no way Slack will be able to make a POST request to the endpoint we just created. We can use Ngrok to set up a temporary public URL so that our app is accessible over the web.
Run the following command on a second terminal window to start ngrok:
In this command, 5000
refers to the port your Flask application is currently listening on.
You should now be presented with a screen similar to the one below:
Take note of the https:// “Forwarding” URL as we’ll be making use of it shortly.
Creating the Slack bot
To be able to post and receive messages on behalf of our application to a channel on Slack, we need to create a Slack bot. Head over to Slack apps and select “Create New App”. Next, you'll be prompted with a screen similar to the one below.
Assign the name “twilio-slack” to the bot, select the Slack workspace you’ll use the app on, and then click the “Create App” button.
Once the app has been created, we need to assign the right Scopes to it. Scopes define the API methods an app is allowed to call. Select “Add features and functionality” and then select the “Permissions” box:
Next, scroll down to the Scopes section and assign the following scopes to the app:
- “channels:history”
- “channels:join”
- “channels:read”
- “chat:write”
- “chat:write.customize”
- “chat:write.public”
Our Slack bot needs a way to be notified whenever a message is posted to the channel where we’ll be sending the SMS notification to. To do so, the bot needs to subscribe to an event Slack provides. Head back to the “Basic information” page, open the “Add features and functionality” dropdown and select “Event Subscriptions”. Next, toggle “Event Subscriptions” on.
For the “Request URL” field, add the forwarding URL from ngrok with the /incoming/slack
path for the endpoint we created above added at the end. Your Request URL should look like https://aa3be367.ngrok.io/incoming/slack, but note that the first part of the ngrok domain will be different in your case.
After you’ve entered the URL, Slack will send a POST request to the endpoint to verify it, so make sure both the Flask application and ngrok are running. Once the verification is achieved, scroll down to the “Subscribe to events on behalf of users” section and add the following event :
- “message.channels”
This allows our application to be notified whenever a message is posted to a channel in Slack. Next click “Save Changes”.
After you’ve saved these settings, we need to install the bot to a Slack workspace so that an API token can be generated for us. Head back to the “Basic information” page and open the “Install your app to your workspace” dropdown. Click the “Install App to Workspace” and grant the necessary permissions. Once this is done, select “OAuth & Permissions” under the “Features” tab and take note of the “Bot User OAuth Access Token” that was generated for the bot. We’ll be needing it shortly.
Setting up Twilio
After you sign up for an account on Twilio, head over to your Twilio Console and click on Phone Numbers. If you already have one or more phone numbers assigned to your account, select the number you would like to use for this project. If this is a brand new account, buy a new phone number to use on this project.
Note that if you are using a trial Twilio account you will need to verify the phone number you’ll be sending SMS messages to. You can do that here.
In the phone number configuration scroll down to the “Messaging” section and under the “A message comes in” field, use the forwarding URL from ngrok with /incoming/twilio
appended. At this point, it’s important to note this endpoint doesn’t yet exist in our application. We shall be creating it shortly.
Ensure the request method is set to HTTP POST
and then click the “Save” button at the bottom of the page to save the settings.
On your Twilio Console, take note of your Account SID and Auth Token. We are going to need these values to authenticate with the Twilio service.
Coding our bot
In the Python project, create a .env file at the root of the project’s directory and edit the file with all the credentials and settings we’ve noted thus far:
For the phone number use the canonical E.164 format. Next, in the main.py, add the following import statements at the top of the file:
Here, we’ve imported all the major dependencies our project will be needing. Next, add the following code just below the app
variable:
The slack_client
instance will be used to interact with the Slack API, while the twilio_client
will be used to interact with the Twilio API.
Forwarding SMS messages to Slack
Next, we’ll add the endpoint we configured in the Twilio SMS configuration. This function will send incoming SMS messages to Slack.
The first thing we did was to obtain the message and phone number that sent the SMS. They both come in the payload of the POST
request with a key of Body
and From
respectively.
A Slack message is then constructed and posted to the “#general” channel of our workspace using the slack_client
instance. You can change the Slack channel according to your needs.
Twilio expects the response from this endpoint should be in TWIML or Twilio Markup Language. But in this project we really have nothing to do on the Twilio side. Thankfully, the Twilio Python helper library comes bundled with some classes that make generating an empty response easy.
Sending Slack threaded replies via SMS
We’ve handled one side of our bot’s logic. The next thing to do is to handle sending out SMS messages whenever a threaded reply is written on a Slack message that was posted by the Twilio endpoint.
Edit the send_incoming_slack()
function we created earlier with the following code:
Next, add the following auxiliary functions also in the main.py
file:
Once Slack makes a POST
request to the /incoming/slack
endpoint and we determine it is not a verification message, the parse_message()
function checks to see if there’s a thread_ts
key contained in the payload. This is important, because the presence of that key indicates that the message is a threaded reply. If the key exists, the function returns the value of the thread_ts
key, the text of the threaded reply message and the id
of the channel where the message was posted. If the message was not a threaded reply, we return None
for the three values and with that the request does not have anything else to do and ends with an empty response.
When the message is a threaded reply, the get_to_number()
function is invoked. This function sends a request to the Slack API to retrieve the text of the parent message the threaded reply belongs to. A check is carried out to ensure that a subtype
key exists in the payload that was returned and has a value of bot_message
. This allows us to know that the parent message was a message from our bot.
Next, the content of the parent message is passed as an argument to the extract_phone_number()
function. Using Python’s regular expression module, this function takes the message, and extracts each word contained in the message to a list
while ignoring punctuation marks. Based on our bot’s messaging structure, the item at index 3 is returned which will be the phone number from where the original message came from. The get_to_number()
function returns this number back to the send_incoming_slack()
function.
To complete the action of the endpoint, an SMS message with the content of the threaded reply is sent to the phone number of the original message using the twilio_client
instance.
Testing
To test the application make sure that you are running the Flask application and ngrok. Keep in mind that ngrok creates a different URL every time it runs, so after a restart you will need to update the Twilio endpoint in the Twilio Console and the Slack endpoint in the Slack app configuration to match the new URL assigned by ngrok. This is obviously only a concern during development, as a production deployment will use a public URL without the need to use ngrok.
To test the service, send an SMS message to your Twilio phone number from your phone. Head over to the Slack workspace on which you configured the bot and you should see the message appear in the #general channel.
Next, add a threaded reply to the message in Slack, and the message should be forwarded back to your phone in an SMS!
Conclusion
In this tutorial we’ve seen how we can build a Slack bot that receives and sends SMS messages using Python and Twilio. The GitHub repository with the complete code for this project can be found here.
Dotun Jolaoso
Website: https://dotunj.dev/
Github: https://github.com/Dotunj
Twitter: https://twitter.com/Dotunj_
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.