Schedule a Message in Twilio Studio

March 10, 2023
Written by
Reviewed by

How to Schedule a Message in Twilio Stuido

Back in August 2022, we released Twilio Message Scheduling for general availability! This feature enables you to schedule an SMS, MMS, or WhatsApp message for a fixed time in the future.

Scheduling a message is free of charge and can be done by including the following additional parameters in your API request:

  • ScheduleType: indicates your intent to schedule a message
  • SendAt: indicates when Twilio will send a message

At the time of publishing this blog post, Twilio Studio, our low-code/no-code application builder, does not have a built-in feature to schedule messages. In this blog post, you’ll learn a workaround that uses Studio and a bit of Python code.

The app in action, schedule a message in Studio then receive it later on.

Please note that code snippets will be shown in Python (in this GitHub repo), however the same principle applies to scheduling a message in other languages.

This blog post will be structured as followed (feel free to jump ahead):

- Prerequisites: Things you need before continuing

- Step 1: Create a free Twilio account

- Step 2: Buy a Twilio phone number

- Step 3: Create a Messaging Service

- Step 4: Setup local environment

- Step 5: Configure environment variables

- Step 6: Schedule a text message with Twilio

- Step 7: Create an endpoint to connect with Studio

- Step 8: Use Twilio Studio to schedule a message

- Next Steps: & Related Resources 

##Prerequisites {#prerequisites}
##Step 1: Create a free Twilio account {#create-free-Twilio-account}

If you want to give Twilio a spin, and haven’t yet, sign up for a free Twilio account. Sign up is quick and no credit card is required!

The signup process includes verifying your personal phone number, as a security measure.

##Step 2: Buy a Twilio phone number {#buy-Twilio-number}

If you haven’t done so already, buy a Twilio phone number – a phone number purchased through Twilio – to send messages using Twilio.

After signing up for an account, log in to the Twilio Console. Then, navigate to the Phone Numbers page. Click Buy a Number to purchase a Twilio number.

Buy a Number in Twilio Console

When you sign up for a free Twilio account, you’re given a free trial balance ($15 in the United States) for you to experiment with.

Twilio pricing uses a pay-as-you-go usage-based model for SMS so you aren’t locked into any contracts.

##Step 3: Create a Messaging Service {#create-messaging-service}

To take advantage of Message Scheduling, you will need to configure your Twilio number with a Messaging Service.

In the Twilio Console, visit the Messaging Services page and click the Create Messaging Service button, then follow the prompts.

Create a Messaging Service

On the next screen, enter a Messaging Service friendly name, such as “schedule-a-message”. Then click the Create Messaging Service button.

Enter a Friendly Name for the Messaging Service

Click the Add Senders button to add your Twilio phone number to this Messaging Service.


Add a Sender to the Service

In the Sender Type dropdown, select Phone Number, then click Continue.

Add a Sender

Select your Twilio phone number, by clicking the checkbox next to the number you want to use as a sender. Then click the Add Phone Numbers button.

Select your Twilio number

You should see a confirmation notification at the top right corner of the screen that says “Numbers {YOUR-NUMBER} were successfully assigned to the service”

Confirm Notification

Click the Step 3: Set up integration button to continue.

In this step, you can use the default settings, so click the Step 4: Add compliance info button.

Leave Default settings

Next, click the Complete Messaging Service Setup button to finalize creating a Messaging Service.

Click Continue

To test out your Messaging Service, click the Try sending a message button.

Test the Messaging Service

Continuing on this screen, enter the following details:

  • To phone number, or the phone number that would receive the message
  • In the From dropdown, select Messaging Service
  • Select the Messaging Service which you created earlier
  • Input text for the Body and click the Send test SMS button

Enter the details to test the service

If successful, you should receive an SMS at your test number and see a similar response to the following in the Console:


201 - CREATED - The request was successful. We created a new resource and the response body contains the representation.
{
  "body": "Let's test out our Messaging Service!",
  "num_segments": "0",
  "direction": "outbound-api",
  "from": null,
  "date_updated": "Wed, 01 Mar 2023 05:22:27 +0000",
  "price": null,
  "error_message": null,
  "uri": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXX/Messages/SMXXXXXXXXXX.json",
  "account_sid": "ACXXXXXXXXXXXXXXXXX",
  "num_media": "0",
  "to": "+1469XXXXXXX",
  "date_created": "Wed, 01 Mar 2023 05:22:27 +0000",
  "status": "accepted",
  "sid": "SMXXXXXXXXXX",
  "date_sent": null,
  "messaging_service_sid": "MGXXXXXXXXXXXXXXXXX",
  "error_code": null,
  "price_unit": null,
  "api_version": "2010-04-01",
  "subresource_uris": {
    "media": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXX/Messages/SMXXXXXXXXXX/Media.json"
  }
}

Once you have created a Messaging Service, you should note down your Messaging Service SID from the list of Messaging Services. It should look similar to this: MGXXXXXXXXXXX

##Step 4: Setup local environment {#setup-local-environment}

Having successfully created a Messaging Service, this step will set up a project that will accommodate your code.

Open a Terminal window and create an empty project directory called twilio-schedule-message:

mkdir twilio-schedule-message

Then change into that directory, as that’s where your code will be.

cd twilio-schedule-message

Since the code for this tutorial will be in Python, create a virtual environment:

python3 -m venv .venv

 

Activate your virtual environment:

source .venv/bin/activate

Then, using the pip package manager, install the required dependencies in your virtual environment:

pip install python-dotenv twilio>=7.16.5 Flask
##Step 5: Configure environment variables {#configure-env-variables}

With your local environment set up, it’s time to configure environment variables so your credentials are hidden. As a best practice when working with sensitive information like API keys and passwords, it’s important to ensure they are secure and not exposed to the public.

Create a file called .env in the project’s root directory (twilio-schedule-message/) to store your API keys.

Within the .env file, create the following environment variables:

TWILIO_ACCOUNT_SID=PASTE_YOUR_ACCOUNT_SID_HERE
TWILIO_AUTH_TOKEN=PASTE_YOUR_AUTH_TOKEN_HERE
TWILIO_MSG_SRVC_SID=PASTE_YOUR_MESSAGE_SERVICE_SID_HERE

Make sure to replace PASTE_YOUR_ACCOUNT_SID_HERE and PASTE_YOUR_AUTH_TOKEN_HERE with the Account SID and Auth Token associated with your Twilio Account. These can be found on the Homepage of your Twilio Console under Account Info.

Also, replace PASTE_YOUR_MESSAGE_SERVICE_SID_HERE with the Message Service SID from the Message Service you created earlier. This can be found from the list of Messaging Services.

Your .env file should now look similar to this:

TWILIO_ACCOUNT_SID=ACXXXXXXXXXXX
TWILIO_AUTH_TOKEN=12345678901234567
TWILIO_MSG_SRVC_SID=MGXXXXXXXXXXX

If you’re pushing this code to a Git repository, please make sure to add the .env file to your .gitignore so that these credentials are secured. i.e. echo ".env" >> .gitignore

##Step 6: Schedule a text message with Twilio {#schedule-message-with-Twilio}

In this next step, you will interact with the Twilio SMS API to create a scheduled message.

If you’d like to see the following code associated with this blog post, it’s available in this GitHub repository.

Within your project directory, create a file called scheduler.py and paste the following code into it:

import os
from datetime import datetime


from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException
from dotenv import load_dotenv


load_dotenv()


account_sid = os.getenv('TWILIO_ACCOUNT_SID')
auth_token = os.getenv('TWILIO_AUTH_TOKEN')

client = Client(account_sid, auth_token)

print(repr(datetime.utcnow()))


def schedule_message():
    try:
        message = client.messages \
            .create(
                messaging_service_sid = os.getenv('TWILIO_MSG_SRVC_SID'),
                to = 'ENTER_THE_NUMBER_YOURE_TEXTING_TO',
                body = 'Ahoy, world! This is a scheduled message in Python.',
                schedule_type = 'fixed',
                send_at = datetime(2023, 3, 3, 5, 55, 10)
            )
        print(message.sid)
    except TwilioRestException as e:
        print(e)
        raise


schedule_message()

Here’s a breakdown of the code in scheduler.py:

  • Lines 1-7, are module imports to make use of their functionality.
    • Lines 1-2, provide access to operating system and date functionality.
    • Lines 5-6, provide access to functionality within the Twilio API.
    • Line 7, provides access to environment variables from the .env file.
  • Line 10, reads environment variables from the .env file.
  • Lines 13-14, assigns variables from the values of your Twilio credentials.
  • Line 15, creates a client object using your Twilio credentials.
  • Lines 21-34, define a function that sends a scheduled message using the Twilio API.
    • Line 25, messaging_service_sid parameter is set to the environment variable of your Messaging Service SID, which identifies the Messaging Service used to send the message.
    • Line 26, to parameter is used as the recipient of the message. Make sure to replace ENTER_THE_NUMBER_YOURE_TEXTING_TO with the recipient’s number.
    • Line 27, body parameter sets the text of your message. In this case, the recipient will receive a text message reading, “Ahoy, world! This is a scheduled message in Python.”
    • Line 28, schedule_type parameter indicates your intent to schedule a message. fixed means the message is scheduled at a fixed time.
    • Line 29, send_at parameter indicates the time that Twilio will send the message. It must be in ISO 8601 format. In this example, the message is scheduled to be sent on March 3, 2023 at 5:55.
  • Line 37, invokes the schedule_message() function and sends out a text message.

To test out the message, run the scheduler.py file with this command in your terminal:

python3 scheduler.py

Message Scheduling supports messages that need to be scheduled more than 15 minutes but fewer than 7 days in advance. Therefore, when modifying the value of the send_at parameter, make sure it falls within that range (>15 minutes and <7 days).

Your application is now capable of sending a scheduled message at a fixed time in the future. But by modifying the scheduler.py file, you can adjust the schedule_message() function to accept dynamic parameters. This way, instead of hardcoding values into the function, they can be provided at execution time for greater flexibility. Check out changes made to the scheduler.py file:


import os
from datetime import datetime
from datetime import timedelta


from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException
from dotenv import load_dotenv


load_dotenv()


account_sid = os.getenv('TWILIO_ACCOUNT_SID')
auth_token = os.getenv('TWILIO_AUTH_TOKEN')

client = Client(account_sid, auth_token)


def schedule_message(minutes, body):
    try:
        message = client.messages \
            .create(
                messaging_service_sid = os.getenv('TWILIO_MSG_SRVC_SID'),
                to = 'ENTER_THE_NUMBER_YOURE_TEXTING_TO',
                body = body,
                schedule_type = 'fixed',
                send_at = minutes_from_now(minutes)
            )
        print(message.sid)
    except TwilioRestException as e:
        print(e)
        raise


def minutes_from_now(minutes):
    if (minutes > 15 and minutes < 10080):
        return datetime.utcnow() + timedelta(minutes=minutes)
    else:
        print('Message must be scheduled more than 15 minutes and fewer than 7 days in advance.')


schedule_message(16, 'Ahoy, world! This is another scheduled message in Python.')

Here’s a breakdown of the revisions made to scheduler.py:

  • Line 3, provides access to manipulate date and times.
  • Line 20, the schedule_message() function now accepts two parameters: minutes and body. Using the minutes parameter, you can specify how many minutes in advance you want to schedule a message. Using the body parameter, you can pass in the body of the text message.
  • Line 26, the body parameter will take in a parameterized message.
  • Line 28, the send_at parameter will invoke a new function called minutes_from_now() which returns a datetime object.
  • Lines 36-40, define a function that returns a datetime object based on the input parameter.
    • Lines 37-38, if the input parameter is within 15 minutes to 7 days in advance, a datetime object will be returned.
  • Line 43, invokes the schedule_message() function and sends out a text message 16 minutes in advance.

Test out the scheduler by re-running the scheduler.py file with this command in your terminal:

python3 scheduler.py

Before continuing to the next step, let’s make one more change to our function. Instead of hardcoding a “to” phone number, you can parameterize it. Make note of the following changes to schedule_message():


def schedule_message(to_number, minutes, body):
    try:
        message = client.messages \
            .create(
                messaging_service_sid = os.getenv('TWILIO_MSG_SRVC_SID'),
                to = to_number,
                body = body,
                schedule_type = 'fixed',
                send_at = minutes_from_now(minutes)
            )
        print(message.sid)
    except TwilioRestException as e:
        print(e)
        raise
  • Line 1, adds a new parameter, to_number, to the function.
  • Line 6, passes the value of to_number to the to parameter.
  • Delete the call to schedule_message() at the bottom of the file

 

##Step 7: Create an endpoint to connect with Studio {#create-endpoint-for-studio}

In the previous step, you created a function called schedule_message() that will schedule a message using the Twilio SMS API. In this step, you will create an endpoint using Flask, a web framework for Python. This endpoint will be used later in Studio and interact with the Make HTTP Request Widget.

Within your project directory, create a file called app.py and paste the following code into it:

from flask import Flask
from flask import Response
from flask import request

from scheduler import schedule_message


app = Flask(__name__)


@app.route("/v1/message/schedule", methods=["POST"])
def send_scheduled_texts():
    try:
        data = request.get_json()
        to_number = data.get("number")
        minutes_ahead = data.get("minutes")
        message = data.get("message")

        schedule_message(to_number, minutes_ahead, message)
        return Response('{"status": "Message sent successfully"}', status=201, mimetype='application/json')
    except Exception as e:
        print(e)
        return Response('{"status": "Message was not sent"}', status=500, mimetype='application/json')


app.run(host='localhost', port=8080)

Here’s a breakdown of the code in app.py:

  • Lines 1-3, are module imports to make use of Flask functionality.
  • Line 5, is a function import from the previously created scheduler.py file.
  • Line 8, creates an instance of Flask.
  • Lines 11-23, define a function that sets a route for the Flask app to respond to HTTP POST requests via the /v1/message/schedule endpoint.
    • Lines 13-17, extracts JSON data from the request body and assigns them to variables.
    • Lines 19-20, calls the schedule_message() function, passing in the data from the JSON request. If the function call succeeds, it returns a Response object with a successful response and a 201 status code.
    • Lines 21-23, if the function call fails, it returns a Response object with a failure response and a 500 status code.
  • Lines 26, starts the Flask app listening on port 8080 of localhost.

In a new terminal window, run app.py with the following command:

python3 app.py

If you receive an error message, you may need to comment out the schedule_message() invocation in scheduler.py on line 43.

At this point, your server should be running on http://localhost:8080. As of now, your application is only running on a server within your computer. But you need a public-facing URL (not http://localhost). You could deploy your application to a remote host, but a quick way to temporarily make your web application available on the Internet is by using a tool called ngrok.

In another terminal window run the following command:

ngrok http 8080

This will create a “tunnel” from the public Internet to port 8080 on your local machine, where the Flask app is listening for requests. You should see output similar to this:

Running ngrok in the terminal

Take note of the line that says “Forwarding”. In the image above, it reads: https://5bad813c2718.ngrok.io -> http://localhost:8080.

This means that your local application is accessible, publicly, on https://5bad813c2718.ngrok.io and your endpoint is accessible on https://5bad813c2718.ngrok.io/v1/message/schedule.

Each time you run the command ngrok http 8080, a new Forwarding URL will be randomly generated.

##Step 8: Use Twilio Studio to schedule a message {#schedule-message-in-studio}

Now that you have created the backend for scheduling a message, it’s time to leverage Twilio Studio to schedule a message using your backend application.

You can use an existing Studio Flow or create a new Flow.

To create a new Flow:

  1. Navigate to the Studio Flows section in the Console.
  2. Click the Create new Flow button to create a new Flow.
  3. Name your Flow. For this project, let’s name it “Schedule SMS in Studio”. Then click Next.
  4. Select the Start from scratch option. Then click Next.

From the Widget Library, drag and drop the Make HTTP Request widget onto the Canvas. Then, from the Trigger widget, draw the Transition from Incoming Message to the Make HTTP Request widget. Your Flow should look similar to this:

Creating a Flow in Studio

Select the Make HTTP Request widget to configure the following properties:

  • For the Widget Name, call it something like “schedule_message”
  • Select “POST” as the Request Method in the dropdown
  • Set the Request URL to “{YOUR-NGROK-URL}/v1/message/schedule”
  • Change the Content Type to “Application/JSON” in the dropdown
  • Add the following to the Request Body:
{
    "number": "{{contact.channel.address}}",
    "minutes": 16,
    "message": "Ahoy, world!"
}

The Request URL should point to a publicly available URL. If you used ngrok, paste the Forwarding URL from the output of running ngrok http 8080.

When modifying minutes, make sure it falls within the range (>15 and <10080 minutes), since Message Scheduling supports messages that need to be scheduled more than 15 minutes and fewer than 7 days in advance.

Configuring the Request Body of the widget

Save those changes by clicking the Save button. Finally, publish your Flow by clicking the Publish button.

Publishing the Flow

Although the Flow is published, you still need to configure your Twilio number to test it out.

Select the Trigger Widget by clicking on it. In Flow Configuration, under Active configurations for this Flow, click the Manage Phone Numbers link.

Managing a phone number to associate with this Flow

Select your Twilio phone number and scroll down to the Messaging section. Under A Message Comes In, select Studio Flow. Then select the name of the Studio Flow you created earlier. If you used the example name, it should be “Schedule SMS in Studio”. Then click Save.

Selecting a Studio Flow to associate with this number

With your Flow published, your web server and ngrok running, you can try it out.

Make sure that your web server and ngrok are running before the message is meant to be scheduled (in this case, 16 minutes).

Since the Flow is triggered by an Incoming Message, send a text message to your Twilio number to trigger the scheduled message.

As a recap, when your Flow is triggered, it makes an HTTP Request to your endpoint /v1/message/schedule. From there, the schedule_message() function is called which will send a scheduled message based on the input from Studio.

##Next steps & related resources {#next-steps}

Nice job following along, but the fun doesn’t stop here. There are many other features and use cases you can incorporate into your own workflows. For instance, you can see a list of scheduled messages and also cancel a scheduled message before it’s sent.

For more information about scheduling a message and answering common questions, see the Message Scheduling FAQs.

If you’d like to see the code associated with this blog post, it’s available in this GitHub repository.

Thanks so much for reading! If you found this tutorial helpful, have any questions, or want to show me what you’ve built, let me know online. And if you want to learn more about me, check out my intro blog post.

Anthony Dellavecchia image and job title

Anthony Dellavecchia is a Developer Evangelist at Twilio who writes code on stage in front of a crowd. He is an experienced software developer who teaches thousands of people how to change the world with code. His goal is to help you build deep experiences and connections with technology so that they stick with you forever.

Check him out online @anthonyjdella