Receive and Reply to SMS and MMS Messages in Python

In this guide, we'll show you how to use Programmable SMS to respond to incoming SMS messages in your Python web application. When someone sends a text message to your Twilio number, Twillio can call a webhook you create in Python from which you can send a reply back using TwiML.

All this talk of webhooks and TwiML got you feeling anxious? Fear not. This guide will help you master the basics in no time.

The code snippets in this guide are written using the Flask web framework and the Twilio Python SDK. Let's get started!

Incoming SMS Diagram

What is a Webhook?

Webhooks are user-defined HTTP callbacks. They are usually triggered by some event, such as receiving an SMS message or an incoming phone call. When that event occurs, Twilio makes an HTTP request (usually a POST or a GET) to the URL configured for the webhook.

To handle a webhook, you only need to build a small web application that can accept the HTTP requests. Almost all server-side programming languages offer some framework for you to do this. Examples across languages include ASP.NET MVC for C#, Servlets and Spark for Java, Express for Node.js, Django and Flask for Python, and Rails and Sinatra for Ruby. PHP has its own web app framework built in, although frameworks like Laravel, Symfony and Yii are also popular.

Whichever framework and language you choose, webhooks function the same for every Twilio application. They will make an HTTP request to a URI that you provide to Twilio. Your application performs whatever logic you feel necessary - read/write from a database, integrate with another API or perform some computation - then replies to Twilio with a TwiML response with the instructions you want Twilio to perform.

What is TwiML?

TwiML is the Twilio Markup Language, which is just to say that it's an XML document with special tags defined by Twilio to help you build your SMS and voice applications. TwiML is easier shown than explained:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say>Thanks for calling!</Say>
</Response>

Every TwiML document will have the root <Response> element and within that can contain one or more verbs. Verbs are actions you'd like Twilio to take, such as <Say> a greeting to a caller, or send an SMS <Message> in reply to an incoming message. For a full reference on everything you can do with TwiML, refer to our TwiML API Reference.

Generating TwiML in your Web Application

When someone sends a text message to your Twilio number, you can send a reply back using TwiML using your configured webhook. Here's how to generate TwiML using the helper library.

Loading Code Samples...
Language
SDK Version:
  • 5.x
  • 6.x
Format:
  • XML
from flask import Flask, request, redirect
from twilio import twiml

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a simple text message."""
    # Start our TwiML response
    resp = twiml.Response()

    # Add a message
    resp.message("The Robots are coming! Head for the hills!")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a simple text message."""
    # Start our TwiML response
    resp = MessagingResponse()

    # Add a message
    resp.message("The Robots are coming! Head for the hills!")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>The Robots are coming! Head for the hills!</Message>
</Response>
When your phone number receives an incoming message, Twilio will send an HTTP request to your server. This code shows how your server should respond to reply with a text message (using TwiML).
Respond to an incoming text message

When your phone number receives an incoming message, Twilio will send an HTTP request to your server. This code shows how your server should respond to reply with a text message (using TwiML).

When you use the helper library, you don't have to worry about generating the raw XML yourself. Of course, if you prefer to do that, then we won't stop you.

You have the code, now you need a URL you can give to Twilio. Twilio can only access public servers on the Internet. That means you need to take your web application and publish it to a web or cloud hosting provider (of which there are many), you can host it on your own server, or you can use a service such as ngrok to expose your local development machine to the internet. We generally only recommend the latter for development and testing purposes and not for production deployments.

Configure Your Webhook URL

Now that you have a URL for your web application's TwiML reply generating routine, you can configure your Twilio phone number to call your webhook URL whenever a new SMS (or MMS) message comes in for you.

  1. Log into Twilio.com and go to the Console's Numbers page
  2. Click on the phone number you'd like to modify
  3. Find the Messaging section and the "A MESSAGE COMES IN" option
  4. Select "Webhook" and paste in the URL you want to use:

SMS Webhook

Make sure you choose HTTP POST or HTTP GET to correspond to what your web application is expecting. Usually the default of POST will be fine.

Backup Webhook URL

You'll notice in the console that there is also a spot to provide a Webhook URL for when the "PRIMARY HANDLER FAILS." Twilio will call this URL in the event that your primary handler returns an error or does not return a response within 15 seconds. Refer to our Availability and Reliability guide for more details on the fallback URL.

Respond with Media (MMS Message)

To send an MMS simply add an image URL. If necessary, restart your server, then text your Twilio number again. You should receive a text message that includes an image. You can even send multiple images by adding more Media elements to your response. Check out the API Reference for more details.

MMS messages can only be sent and received by numbers having MMS capability. You can check the capabilities of numbers in the account portal or query the Available Phone Numbers resource to search for Twilio numbers that are MMS enabled.

Loading Code Samples...
Language
SDK Version:
  • 5.x
  • 6.x
Format:
  • XML
from flask import Flask, request, redirect
from twilio import twiml

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a MMS message."""
    # Start our TwiML response
    resp = twiml.Response()

    # Add a text message
    msg = resp.message("The Robots are coming! Head for the hills!")

    # Add a picture message
    msg.media("https://farm8.staticflickr.com/7090/6941316406_80b4d6d50e_z_d.jpg")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)


@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a MMS message."""
    # Start our TwiML response
    resp = MessagingResponse()

    # Add a text message
    msg = resp.message("The Robots are coming! Head for the hills!")

    # Add a picture message
    msg.media("https://farm8.staticflickr.com/7090/6941316406_80b4d6d50e_z_d.jpg")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
<?xml version="1.0" encoding="utf-8"?>
<Response>
    <Message>
        <Body>The Robots are coming! Head for the hills!</Body>
        <Media>https://farm8.staticflickr.com/7090/6941316406_80b4d6d50e_z_d.jpg</Media>
    </Message>
</Response>
Generate a TwiML Message with Image

Custom Responses to Incoming SMS Messages

Let's take a look at how we might respond to an incoming SMS with a different message depending on the incoming Body parameter from the incoming Twilio Request.

Loading Code Samples...
Language
SDK Version:
  • 5.x
  • 6.x
Format:
  • XML
from flask import Flask, request, redirect
from twilio import twiml

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def incoming_sms():
    """Send a dynamic reply to an incoming text message"""
    # Get the message the user sent our Twilio number
    body = request.values.get('Body', None)

    # Start our TwiML response
    resp = twiml.Response()

    # Determine the right reply for this message
    if body == 'hello':
        resp.message("Hi!")
    elif body == 'bye':
        resp.message("Goodbye")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def incoming_sms():
    """Send a dynamic reply to an incoming text message"""
    # Get the message the user sent our Twilio number
    body = request.values.get('Body', None)

    # Start our TwiML response
    resp = MessagingResponse()

    # Determine the right reply for this message
    if body == 'hello':
        resp.message("Hi!")
    elif body == 'bye':
        resp.message("Goodbye")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>Goodbye!</Message>
</Response>
Generate a dynamic TwiML Message

Now, try sending your Twilio number a text that says "hi" or "bye", and you should get the corresponding response.

Enhance Messages with Add-ons

Need more information about the phone number that sent the message? Need to analyze the message itself for sentiment or other data? Add-ons are available in the Add-ons Marketplace to accomplish these tasks and more.

To learn how to enable Add-ons for your incoming SMS messages, refer to our Add-ons quickstart.

Add-ons Diagram

Where to next?

When you're ready to dig deeper into handling incoming messages, check out our guide on how to Create an SMS Conversation and our Automated Survey tutorial.

Andrew Baker
Jarod Reyes
David Prothero
Paul Kamp
Agustin Camino

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
SDK Version:
  • 5.x
  • 6.x
Format:
  • XML
from flask import Flask, request, redirect
from twilio import twiml

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a simple text message."""
    # Start our TwiML response
    resp = twiml.Response()

    # Add a message
    resp.message("The Robots are coming! Head for the hills!")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a simple text message."""
    # Start our TwiML response
    resp = MessagingResponse()

    # Add a message
    resp.message("The Robots are coming! Head for the hills!")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>The Robots are coming! Head for the hills!</Message>
</Response>
SDK Version:
  • 5.x
  • 6.x
Format:
  • XML
from flask import Flask, request, redirect
from twilio import twiml

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a MMS message."""
    # Start our TwiML response
    resp = twiml.Response()

    # Add a text message
    msg = resp.message("The Robots are coming! Head for the hills!")

    # Add a picture message
    msg.media("https://farm8.staticflickr.com/7090/6941316406_80b4d6d50e_z_d.jpg")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)


@app.route("/sms", methods=['GET', 'POST'])
def sms_reply():
    """Respond to incoming calls with a MMS message."""
    # Start our TwiML response
    resp = MessagingResponse()

    # Add a text message
    msg = resp.message("The Robots are coming! Head for the hills!")

    # Add a picture message
    msg.media("https://farm8.staticflickr.com/7090/6941316406_80b4d6d50e_z_d.jpg")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
<?xml version="1.0" encoding="utf-8"?>
<Response>
    <Message>
        <Body>The Robots are coming! Head for the hills!</Body>
        <Media>https://farm8.staticflickr.com/7090/6941316406_80b4d6d50e_z_d.jpg</Media>
    </Message>
</Response>
SDK Version:
  • 5.x
  • 6.x
Format:
  • XML
from flask import Flask, request, redirect
from twilio import twiml

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def incoming_sms():
    """Send a dynamic reply to an incoming text message"""
    # Get the message the user sent our Twilio number
    body = request.values.get('Body', None)

    # Start our TwiML response
    resp = twiml.Response()

    # Determine the right reply for this message
    if body == 'hello':
        resp.message("Hi!")
    elif body == 'bye':
        resp.message("Goodbye")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)

@app.route("/sms", methods=['GET', 'POST'])
def incoming_sms():
    """Send a dynamic reply to an incoming text message"""
    # Get the message the user sent our Twilio number
    body = request.values.get('Body', None)

    # Start our TwiML response
    resp = MessagingResponse()

    # Determine the right reply for this message
    if body == 'hello':
        resp.message("Hi!")
    elif body == 'bye':
        resp.message("Goodbye")

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>Goodbye!</Message>
</Response>