SMS Fallback to Voice Notifications
Time to read: 9 minutes
Did you know that ~40% of the calls through Twilio are to a phone that can’t receive text messages? How many folks haven’t opted into your messaging campaigns that you have phone numbers for?
Voice notifications enable you to communicate with everyone that gives you a phone number, which helps drive up appointments, reservations, or action. Even if users don’t answer the phone, visual voicemail will transcribe your voice notification and provide a similar result as an SMS. This post will show you how to reach the folks you’re not reaching today with Programmable Voice.
Prerequisites
To follow this tutorial, you need the following items:
- A Twilio account
- A Twilio phone number
Please reference the companion repo on Github.
Use Twilio Functions to send voice notifications
Write a Function to send SMS
If you have already made calls to Twilio’s Programmable SMS API to send your customer notifications, you can go ahead and leverage that existing code to send an SMS. If not, you can follow along with our sample.
Navigate to Functions and Assets -> Services in the Twilio Console. Click “Create Service” button.
Enter “voice-notifications” in the Service Name input and click the “Next” button.
Click the “Add +” button and select “Add Function” from the drop-down. Replace “path_1” with “sendSMS”.
Click the down arrow to the right of the word “Protected” and select “Public” from the drop-down.
We’re going to write a simple Twilio Function to send an SMS based on 3 parameters: From
, To
, and Body
. These values are stored in the event object, which contains request parameters and headers, and we access them from the event
parameter. We will leverage Axios to make an HTTP request to our other functions, so let’s add that in addition to the Twilio client.
Next let’s use the Twilio client to send an SMS message by adding the following code directly after the const body
variable:
Set dependencies
Click on the “Dependencies” link under the Settings pane. Type “axios” into the MODULE box and “^0.27.2” in the VERSION text box. Then click the “Add” button.
Add another dependency by entering “twilio” into the MODULE box and “3.56” into the VERSION box. Then click the “Add” button.
Deploy Functions
Click the blue “Deploy All” button in the bottom left corner.
Copy the URL of the /sendSMS
function by clicking the three dots to the right of the function name and selecting “Copy URL”.
Example: https://voice-notifications-1234.twil.io/sendSMS
Test your function to make sure you're able to send an SMS replacing <copied_url>
with the link copied above.
Notice the link in the above command…
Write Function to send voice notifications
Now that we have sent an SMS, we will write another Twilio Function named /sendVoiceNotification
to send a voice notification.
Again we will need to change this function from Protected
to Public
. We will use the same 3 parameters, From
, To
, and Body
. Using the Body
parameter, we will create TwiML, which will speak the message provided to the function.
Then we will create a Programmable Voice call using the to
, from
, and twiml
variables. The call will use Answering Machine Detection to ensure if the customer doesn’t answer, Twilio will leave them a voicemail. Add this code below directly below the twilioClient variable.
Handle undeliverable SMS
Next we need to write the logic to handle a scenario where the text message was undeliverable. There are two primary ways to get notified when an SMS is undeliverable, Event Streams and Status Callbacks.
Leveraging Event Streams allows you to subscribe to a specified list of event types, so for this we can just subscribe to “Undeliverable SMS” events. The main advantage to using Event Streams is that you do not have to modify your existing code. Subscribing to Event Streams enables you to receive SMS undeliverable status events from your entire account. The drawback to this approach is that it may require additional logic if you want to take different actions for different messages. For example, you may want to send a simple voice notification to tell a customer that their table is ready, but you might want to leverage an IVR to notify them of a change to their reservation so they can reschedule.
Event Streams allows you to create Webhook, Amazon Kinesis, or Segment Sink types. In this example, we will use a simple Webhook sink to call another Twilio Function.
Click the “Add +” button on the Functions page and name the new function /eventStreamWebhook
. Again make this function Public
.
Paste the following code into the new function.
Click the ”Deploy All” button at the button of the page to build and deploy our latest changes to the Twilio Functions serverless environment.
Setting up Event Streams to a webhook destination
In this blog post, we are going to use a Webhook destination, but any of the destinations will work to collect SMS undelivered events. If you prefer to use Segment or Kinesis please refer to the Event Streams documentation.
Create a Sink Instance
Navigate to “Explore Products” in the Twilio Console and click on Event Streams under the Developer tools section. Then click Manage and click “Create new sink”.
Provide a description for the new Sink and select the Webhook sink type.
Click “Next step” and paste the /eventStreamWebhook
URL into the Destination field. Select “POST” and “False” for the next two options then click “Finish”.
In the resulting pop-up, click “Create Subscription” and then continue to the next section.
Subscribe to undelivered SMS events
An Event Stream sink needs to have one or more subscriptions to event types. This will let Twilio Event Streams know which event types your application is interested in receiving. In this case, we just want to know when an SMS message is undelivered.
Provide a description for this new subscription.
Scroll down to the “Product groups” section and click “Messaging” and then scroll to the bottom of the list and select the latest “Schema version” for the “Undelivered” event type. At the time of writing, the latest version was “3”.
Click “Create Subscription” at the bottom, and you are done building your automated system for sending Voice Notifications for failed SMS!
Test it out!
To mimic a cell phone subscriber who cannot receive SMS messages, we can purchase a Twilio Number and set the Incoming Message Webhook to a blank value. Any SMS messages to that number will result in a 30008 error code.
Purchase a Twilio Phone Number
Navigate in the console to Phone Numbers -> Buy a number and then click the “Buy” button next to a number of your choice. For detailed instructions, please see this article.
Write this number down, you will swap this number in the example below as the <twilio_number_to> variable.
Create a TwiML Bin
In the Twilio Console, navigate to TwiML Bins (either pinned to the menu or through clicking “Explore Products”) -> My TwiML Bins and then click the “+” button to add a new TwiML Bin. Provide the TwiML Bin with a name like “Forward Voice to my cell phone” and then paste the following code into the TWIML field, replacing the phone number with your own phone number.
Click “Create” at the bottom of the screen.
Configure the new Twilio Phone Number
Navigate in the console to Phone Numbers -> Active Numbers and click on the number you just purchased.
Scroll down to the Voice configuration and select the “TwiML Bin” option in the “A CALL COMES IN” drop down and then select the “Forward Voice to cell phone” TwiML bin we created earlier.
Scroll down to the Messaging configuration and select the “Webhook” option in the “A MESSAGE COMES IN” drop down and then leave the text input blank. This will signal to Twilio to reject any upcoming SMS and return a 30008 error code to the originating Twilio Programmable Messaging API status callback.
Click “Save” at the bottom of the page.
Use this number as the <twilio_number_to> field below.
Make a call to your /sendSMS function
Now we will use the functions you wrote earlier to send an SMS to your new Twilio number. Use the following curl command to invoke your new function. Insert the Twilio Number you just purchased as the <twilio_number_to> field. Insert the original Twilio Number provided with your account (or any other SMS enabled Twilio Number in your account) in the <original_twilio_number> field.
You should see a Success! Message SID:
in the terminal after running this curl command and then you should receive a voice call from your Twilio Number that will speak the original message to you. Try answering the call and then try again to see what happens when you don’t answer the incoming call.
Handle opt-outs
Some users may opt-out of SMS messages which might have unintended consequences for their experience with your brand. For example, if a user does not realize that SMS messages are used for notification that their to-go order is ready, missing that notification might cause them to have a poor customer experience. In cases such as this, you can fall back to a voice notification automatically.
We will add some logic to our /sendSMS
Function to detect when a 21610 error is thrown, indicating that a user has opted out of messages from that number. Ideally, this would never occur since we recommend developers listen to incoming message webhooks and update their backend database when a user replies with an opt-out keyword. In that case, you would add this logic inside your application to check if the user was unsubscribed before sending, and whether the voice notification should be sent instead.
Insert this code inside the catch block at the end of the /sendSMS
function to replace the return callback.
So you’re resulting code should look like:
To test this, use your personal cell phone and text “STOP” to your original Twilio Number (the one you have been using to send SMS messages from). Then call the /sendSMS function with that original Twilio Number as the From
and your personal cell phone number as the To
. You should not receive the SMS since you are opted-out but instead you should receive a voice notification with the same content.
Final considerations and resources
I’ll leave you with a few caveats to this solution you need to consider:
Enable your customers to press a digit or say something to be able to speak to a human, so you’re not sending the equivalent of a “no reply,” and your customers have to go elsewhere for service:
- Best practice would be to direct them to the relevant contact center queue, e.g. rescheduling, or human best placed to deal with that inquiry e.g. restaurant front desk.
- As you scale voice notifications, try and scale them alongside human capacity to answer the anticipated contact center volumes.
- Use a Conversational IVR to capture caller intent and include this in your inbound contact center call.
If your message is sending URLs you should consider replacing the URL with an alternative. Some examples are:
- Providing them a way to call in for more information
- Allowing them to press 1 to receive the link via a 1-time message via a separate Messaging Service from your normal notifications
- Allowing them to opt-in/resubscribe to SMS messages, and then sending the SMS with the URL.
Be aware of when you are sending messages with numbers. Here are a few scenarios where some massaging of the message is needed before sending the voice notification:
- Detect when currencies are used and replace with the amount and spoken currency ($5.02 -> 5 dollars and 2 cents).
- Insert spaces between digits for spoken numbers (order numbers etc.)
- Convert time of day (5:30 PM would be “five thirty PM”)
Always use a Neural voice for voice notifications so that visual voicemail transcription will be more accurate.
If you want to specify different content for each SMS message you can leverage status callbacks to initiate the Voice Notification which will allow you to specify an alternative message. The downside to this approach is that you must edit each SMS API call to provide a specific status callback endpoint.
Final thoughts...
Even with Twilio’s unmatched SMS deliverability, there will ultimately be some customers you cannot reach via SMS, such as landlines. Using automatic fallback to voice notifications allows you to easily reach those customers and still provide a great customer experience without rearchitecting your customer engagement model. It can also offer a way to reach customers who have opted out of SMS but still need communications from your business to have a great experience.
Additional resources
The following reference resources will provide you with in-depth information on some of the topics mentioned in this post:
- Getting started with Advanced Opt-out for handling SMS opt-outs before getting a 21610 error
- For sending calls to agents, consider Flex which allows for omnichannel routing and rich caller context
- More details on Twilio Programmable Voice
Mark is a Solutions Engineer working with Enterprise customers at Twilio. He has spent the last decade working with customers on everything from VoIP to enterprise integration patterns. In his spare time, he enjoys trying to keep his home automation running. He can be reached mvickstrom [at] twilio.com.
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.