Using Test Credentials and Magic Phone Numbers to Test Twilio Applications

June 15, 2020
Written by
Reviewed by
Diane Phan
Twilion

Using Test Credentials and Magic Phone Numbers to Test Twilio Applications

A common problem when developing an application that uses Twilio services is how to effectively test it. Making real requests to Twilio for testing purposes is something that can be useful when done sparsely, but it is not ideal as a general approach to testing because it can end up being expensive. Also, when testing how your application responds to errors you are going to find that it is very hard to replicate all the possible error conditions that can occur in SMS or Voice communication.

In this article you are going to learn how to work with your Twilio Test Credentials to be able to send fake, yet realistic requests to Twilio that have a predictable result, and more importantly, are 100% free.

Tutorial requirements

To follow this tutorial you need the following components:

Running the example application

For this tutorial we are going to use a simple Flask application that sends SMS. This application is available on GitHub. If you have git installed, you can grab a copy as follows:

$ git clone https://github.com/miguelgrinberg/twilio-send-sms-demo

If you prefer to download the application from your web browser, click this download link.

Once you have the application installed, open a terminal and change to this directory:

$ cd twilio-send-sms-demo

Next we are going to create a virtual environment and install the dependencies for this application on it. If you use a Linux of Mac computer:

$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip install -r requirements.txt

If you are using a Windows computer, use the following commands:

$ python -m venv venv
$ venv\Scripts\activate
(venv) $ pip install -r requirements.txt

This application uses a .env (dot-env) file for configuration. Create a .env file in this directory and define four variables in it:

TWILIO_ACCOUNT_SID="ACxxxxxxxxxxx"
TWILIO_AUTH_TOKEN="xxxxxxxxxxxxx"
FROM_NUMBERS="+1xxxxxxxxxx"
TO_NUMBERS="+1xxxxxxxxxx"

You can find out the values of the first two variables that are correct for your account by logging in to your Twilio Console and then clicking “Settings” on the left sidebar. Scroll down until you see the “API Credentials” section.

twilio account sid and auth token

Copy the “Account SID” and “Auth Token” from the “LIVE Credentials” box into your .env file.

For the FROM_NUMBERS variable, enter the Twilio phone number associated with your account. If you don’t have a phone number on your account, you can buy one just for this tutorial (if you are using a trial account you’ll be spending your trial credit for this, not real money). Enter the number in full E.164 format. For example, if your Twilio number is +12345678900, you would enter:

FROM_NUMBERS="+12345678900"

If you have more than one number in your Twilio account, you can enter all of them separated by commas:

FROM_NUMBERS="+12345678900,+19876543200"

For the TO_NUMBERS variable, enter your mobile phone number. Here you can also enter a list of numbers you would like to send SMS to. Keep in mind that if you are using a trial account, Twilio requires that all numbers that will receive SMS be verified.

Once you have the four variables set in your .env file, save the file.

Now we are ready to start the application, with the flask run command:

(venv) $ flask run

You should see the Flask server running as follows:

flask run command

With the application still running, open your web browser and enter http://localhost:5000 in the address bar, and you should see the Send SMS Demo application in its full glory:

send sms demo screenshot

The Sender and Recipient dropdowns show the numbers that you configured in the .env file. If you select the sender and recipient numbers you would like to use, type a message and hit the “Submit” button, an SMS will be sent.

Make sure you can send yourself a message before continuing on to the next section.

Using Test Credentials

The main function in the example application is the send_sms() function. You can see the implementation of this function in file app.py below:

def send_sms(from_phone, to_phone, message):
    twilio.messages.create(from_=from_phone, to=to_phone, body=message)

The twilio.messages.create() function comes from the Twilio Helper Library for Python, and is where the request to the Twilio service is made.

How robust do you think this function is? You can probably guess that having a single line code isn’t as robust as it can be. We would like this function to be able to withstand all possible error conditions, but to achieve that we need a way to generate all these possible failures in a controlled testing environment, and ideally without having to spend money on Twilio services.

We are going to address this need using our Test Credentials. Stop the example application by pressing Ctrl-C on the terminal window where it was running. Then open the .env file again, and change the Account SID and Auth Token variables to the settings that appear on the ‘TEST Credentials” box in your Settings page.

twilio test credentials

When you use your test credentials, Twilio will accept your requests and process them normally, but it won’t actually do anything. That means that no SMS or phone calls will be made, and your account will not generate any charges.

Your test credentials function in a completely different environment than your live ones, with no connection between the two. In particular, any phone numbers that are associated with your live account are not going to be recognized under your test credentials. This gives us an opportunity to try our first error condition, using an invalid sender phone number.

Start the application again by running flask run, and try to send yourself another SMS. Your web browser should now show a bad looking error message.

internal server error

To find what was the error we have to look in the terminal window where the Flask application is running. The error should look like this:

2020-06-12 14:52:07

This is a long and obscure error message, but you can ignore most of it and concentrate on the exception raised, which is shown near the bottom. In this case it was a TwilioRestException, and the error message is actually self-explanatory:

Unable to create record: The From phone number +12345678900 is not a valid, SMS-capable inbound phone number or short code for your account.

So now we know that when there is an error, this application just crashes by raising a TwilioRestException with a useful error message.

If we look in the place where the send_sms() function is invoked in app.py, we can see that this code is already prepared to handle exceptions of type RuntimeError and show them as errors to the user via Flask’s message flashing mechanism:

        try:
            send_sms(form.from_phone.data, form.to_phone.data,
                     form.message.data)
        except RuntimeError as ex:
            flash(str(ex))
        else:
            flash('SMS sent!')

One improvement we can make to this application is to catch the TwilioRestException and raise a RuntimeError exception in its place. Let’s make this change in the send_sms() function, and also add the import for the TwilioRestException at the top of the file:

from twilio.base.exceptions import TwilioRestException

# …

def send_sms(from_phone, to_phone, message):
    try:
        twilio.messages.create(from_=from_phone, to=to_phone, body=message)
    except TwilioRestException as exc:
        raise RuntimeError(f'{exc.msg} (code: {exc.code})')

The msg and code attributes of the Twilio exception include the message and the numeric code for the error, which we format nicely into the RuntimeError using an f-string.

Stop and restart the Flask application and try to send yourself an SMS one more time. Now the output is much nicer:

send sms example with error

Magic numbers

The application is now able to handle unexpected errors in a more dignified way, but so far the only error we can replicate is the one that comes up when we use an invalid phone number as a sender. The test credentials do not give us a way to generate other error conditions, and more importantly, we have lost the ability to send a successful SMS, since now all messages fail.

To handle all these different scenarios, Twilio provides magic numbers, special phone numbers that have predefined behaviors.

For SMS, Twilio supports the following magic numbers as senders:

Number

Behavior

+15005550001

Invalid phone number.

+15005550006

Valid number.

+15005550007

The number is not owned by your account or not SMS capable.

+15005550008

The number has a full SMS queue.

Any other number

The number is not owned by your account or not SMS capable.

As receivers, the following SMS magic numbers are available:

Number

Behavior

+15005550001

Invalid phone number.

+15005550002

Cannot route to this number.

+15005550003

Your account does not have international permissions.

+15005550004

The number is in the blocked list.

+15005550009

The number is not SMS capable.

Any other number

Valid number.

Let’s add all of these magic numbers to our .env configuration. Replace the values for the FROM_NUMBERS and TO_NUMBERS with the following values:

FROM_NUMBERS="+15005550006,+15005550001,+15005550007,+15005550008,+15005550009,+12345678900"
TO_NUMBERS="+15005550001,+15005550002,+15005550003,+15005550004,+15005550009,+19876543200"

After making these changes to your .env file, remember to stop the Flask server and restart it.

Now by selecting combinations of sender and receiver magic numbers we can generate all possible outcomes, valid or invalid, and all without incurring any charges with Twilio.

successful send sms example with test credentials

failed send sms example with test credentials

Conclusion

In this article, you have learned how to use Twilio test credentials and magic numbers to test sending of SMS. Twilio also provides magic numbers for making phone calls, and for buying phone numbers.

I hope you find the use of test credentials and magic numbers a useful technique to add to your bag of tricks when working with Twilio!

Miguel Grinberg is a Python Developer for Technical Content at Twilio. Reach out to him at mgrinberg [at] twilio [dot] com if you have a cool Python project you’d like to share on this blog!