MMS Tutorial Using Python SDK
Articles - 6 min read

MMS Tutorial Using Python SDK

Learn how to send an MMS using Telnyx messaging and Python SDK

How to get someone to read your message? Ditch the words, send a picture.

The good thing is, you can learn how to send MMS on the Telnyx platform in just 30 minutes using our Python SDK. There’s no time like the present -- so let’s get started!
A quick intro to kick things off: The Telnyx messaging API supports both multimedia messages (MMS) and SMS. Inbound MMS include an attachment link in the webhook, which should be saved to a media storage of your own (like AWS S3).
At the end of this tutorial, you’ll have an application that:
  • Receives an inbound MMS / SMS
  • Iterates over any media attachments and downloads the remote - attachment locally
  • Uploads the attachment to your media storage
  • Sends the attachments back to the same phone number that originally sent the message
Let's dive in!

1. Prerequisites

You should have:
  • Completed or familiar with the Receiving SMS & MMS Quickstart
  • A working Messaging profile with a SMS/MMS enabled phone number, which you can configure in the Mission Control Portal
  • Be able to receive webhooks with something like ngrok
  • A familiarity with Flask
  • Python & PIP installed
  • An AWS account set up with proper profiles and groups with IAM for S3 (More information in Quickstart)
  • Previously created S3 bucket with public permissions available.

2. Setup

Telnyx Portal Configuration
Be sure to have a Messaging Profile for you SMS / MMS enabled phone number, and webhook URL pointing to ngrok or similar tool.
Install Packages via PIP
This step will create Pipfile file with the packages needed to run the application
1
2
3
4
5
pip install telnyx
pip install boto3
pip install flask
pip install dotenv
pip install requests
Set environment variables
Next, you’ll set the following environmental variables:
VariableDescription
TELNY_API_KEYYour Telnyx API Key
TELNYX_PUBLIC_KEYYour Telnyx Public Key
TELNYX_APP_PORTDefaults to 8000 The port the app will be served
AWS_PROFILEYour AWS profile as set in ~/.aws
AWS_REGIONThe region of your S3 bucket
TELNYX_MMS_S3_BUCKETThe name of the bucket to upload the media attachments
.env file
This app uses the python-dotenv package to manage environment variables. Make a copy of the file below, add your credentials, and save as .env in the root directory.
1
2
3
4
5
6
TELNYX_API_KEY=
TELNYX_PUBLIC_KEY=
TENYX_APP_PORT=8000
AWS_PROFILE=
AWS_REGION=
TELNYX_MMS_S3_BUCKET=
Code-along
We’ll use a single app.py to build the MMS application.
1
touch app.py
Setup Flask Server
Next, we’ll set up our Flask Server like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import telnyx
import os
from urllib.parse import urlunsplit, urlparse
import json
import requests
import boto3
from botocore.exceptions import ClientError
from flask import Flask, request, Response
from dotenv import load_dotenv

app = Flask(__name__)

## Will add more flask code
## ..
## ..

## Load env vars and start flask server
if __name__ == "__main__":
    load_dotenv()
    TELNYX_MMS_S3_BUCKET = os.getenv("TELNYX_MMS_S3_BUCKET")
    telnyx.api_key = os.getenv("TELNYX_API_KEY")
    TELNYX_APP_PORT = os.getenv("TELNYX_APP_PORT")
    app.run(port=TELNYX_APP_PORT)

3. Receiving Webhooks

Now that you have set up your auth token, phone number and connection, you can begin to use the API Library to send and receive SMS and MMS messages. The first step is to set up an endpoint to receive webhooks for inbound messages and outbound message Delivery Receipts (DLRs).
Basic Routing and Functions
Here’s a basic overview of the application:
  • Verify Webhook and create Telnyx Event
  • Extract information from the webhook
  • Iterate over any media and download/re-upload to S3 for each attachment
  • Send the message back to the phone number which it came from
  • Acknowledge the status update (DLR) of the outbound message
Media Download & Upload Functions
Before diving into the inbound message handler, we’ll first create a few functions to manage our attachments. To do this:
  • Download_file saves the content from a URL to disk
  • Upload_file uploads the file passed to AWS S3 and makes object public
  • Media_downloader_uploader calls the download function and passes result to upload function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def download_file(url):
    r = requests.get(url, allow_redirects=True)
    file_name = os.path.basename(urlparse(url).path)
    open(file_name, "wb").write(r.content)
    return file_name

def upload_file(file_path):
    global TELNYX_MMS_S3_BUCKET
    s3_client = boto3.client("s3")
    file_name = os.path.basename(file_path)
    try:
        extra_args = {
            "ContentType": "application/octet-stream",
            "ACL": "public-read"
        }
        s3_client.upload_file(
            file_path,
            TELNYX_MMS_S3_BUCKET,
            file_name,
            ExtraArgs=extra_args)
    except ClientError as e:
        print("Error uploading file to S3")
        print(e)
        quit()
    return f"https://{TELNYX_MMS_S3_BUCKET}.s3.amazonaws.com/{file_name}"

def media_downloader_uploader(url):
    file_location = download_file(url)
    file_url = upload_file(file_location)
    return file_url

4. Inbound Message Handling

Alright, now we’re ready to start receiving inbound MMS!
At a high level, we’ll be:
  1. Extracting relevant information from the webhook
  2. Building the webhook_url to direct the DLR to a new endpoint
  3. Iterate over any attachments and call our media_downloader_uploader function
  4. Send the outbound message back to the original sender with the media attachments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@app.route("/messaging/inbound", methods=["POST"])
def inbound_message():
    body = json.loads(request.data)
    message_id = body["data"]["payload"]["id"]
    print(f"Received inbound message with ID: {message_id}")
    dlr_url = urlunsplit((
        request.scheme,
        request.host,
        "/messaging/outbound",
        "", ""))
    to_number = body["data"]["payload"]["to"][0]["phone_number"]
    from_number = body["data"]["payload"]["from"]["phone_number"]
    medias = body["data"]["payload"]["media"]
    media_urls = list(map(lambda media: media_downloader_uploader(media["url"]), medias))
    try:
        telnyx_response = telnyx.Message.create(
            from_=to_number,
            to=from_number,
            text="👋 Hello World",
            media_urls=media_urls,
            webhook_url=dlr_url,
            use_profile_webhooks=False
        )
        print(f"Sent message with id: {telnyx_response.id}")
    except Exception as e:
        print("Error sending message")
        print(e)
    return Response(status=200)

5. Outbound Message Handling

As we defined our webhook_url path to be /messaging/outbound we’ll need to create a function that accepts a POST request to that path within messaging.js.
1
2
3
4
5
6
@app.route("/messaging/outbound", methods=["POST"])
def outbound_message():
    body = json.loads(request.data)
    message_id = body["data"]["payload"]["id"]
    print(f"Received message DLR with ID: {message_id}")
    return Response(status=200)

6. Final app.py

The final product should look something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import telnyx
import os
from urllib.parse import urlunsplit, urlparse
import json
import requests
import boto3
from botocore.exceptions import ClientError
from flask import Flask, request, Response
from dotenv import load_dotenv

app = Flask(__name__)

def download_file(url):
    r = requests.get(url, allow_redirects=True)
    file_name = os.path.basename(urlparse(url).path)
    open(file_name, "wb").write(r.content)
    return file_name

def upload_file(file_path):
    global TELNYX_MMS_S3_BUCKET
    s3_client = boto3.client("s3")
    file_name = os.path.basename(file_path)
    try:
        extra_args = {
            "ContentType": "application/octet-stream",
            "ACL": "public-read"
        }
        s3_client.upload_file(
            file_path,
            TELNYX_MMS_S3_BUCKET,
            file_name,
            ExtraArgs=extra_args)
    except ClientError as e:
        print("Error uploading file to S3")
        print(e)
        quit()
    return f"https://{TELNYX_MMS_S3_BUCKET}.s3.amazonaws.com/{file_name}"

def media_downloader_uploader(url):
    file_location = download_file(url)
    file_url = upload_file(file_location)
    return file_url

@app.route("/messaging/inbound", methods=["POST"])
def inbound_message():
    body = json.loads(request.data)
    message_id = body["data"]["payload"]["id"]
    print(f"Received inbound message with ID: {message_id}")
    dlr_url = urlunsplit((
        request.scheme,
        request.host,
        "/messaging/outbound",
        "", ""))
    to_number = body["data"]["payload"]["to"][0]["phone_number"]
    from_number = body["data"]["payload"]["from"]["phone_number"]
    medias = body["data"]["payload"]["media"]
    media_urls = list(map(lambda media: media_downloader_uploader(media["url"]), medias))
    try:
        telnyx_response = telnyx.Message.create(
            from_=to_number,
            to=from_number,
            text="👋 Hello World",
            media_urls=media_urls,
            webhook_url=dlr_url,
            use_profile_webhooks=False
        )
        print(f"Sent message with id: {telnyx_response.id}")
    except Exception as e:
        print("Error sending message")
        print(e)
    return Response(status=200)

@app.route("/messaging/outbound", methods=["POST"])
def outbound_message():
    body = json.loads(request.data)
    message_id = body["data"]["payload"]["id"]
    print(f"Received message DLR with ID: {message_id}")
    return Response(status=200)

if __name__ == "__main__":
    load_dotenv()
    TELNYX_MMS_S3_BUCKET = os.getenv("TELNYX_MMS_S3_BUCKET")
    telnyx.api_key = os.getenv("TELNYX_API_KEY")
    TELNYX_APP_PORT = os.getenv("TELNYX_APP_PORT")
    app.run(port=TELNYX_APP_PORT)

Using your Application

Here’s the fun part! Start the server python app.py.
So far, we’ve set up a local web server, but this is typically not accessible from the public internet.
To make your application accessible from the public internet, the best solution is a tunneling service which comes with client software that runs on your computer and opens an outgoing permanent connection to a public server. Then, a public URL is assigned on that server to your account. The specific tunneling tool that we’ll use is ngrok; after setting up ngrok setup on your computer, you can add the public URL to your Inbound Setting in the Mission Control Portal. To do this, click the edit symbol ✎ and paste the forwarding address from ngrok into the 'Send a Webhook to this URL' field, and add messaging/inbound to the end of the URL. You can also add an alternate address in the “Failover URL” section, or leave it blank for now.
Congratulations! Your application is ready to use -- you should be able to text a MMS to your phone number and get that same picture back! Make sure to check out our MMS product page to learn more about MMS use cases, and some frequently asked questions.
Share on Social

Worth checking out

By using the site, you agree to our use of cookies. Accept and close Find out more here.