Confirming SMS Message Delivery with RxJS Observables, Node.js, and Twilio Programmable SMS
Time to read: 11 minutes
SMS messages can reach over 4.5 billion text-enabled devices to notify people about upcoming appointments, emergencies, traffic disruptions, or commercial promotions. Sending SMS messages programmatically enables you to reach many people almost simultaneously. With Twilio Programmable SMS you can create a Node.js application that sends many messages and reports when each of them has been delivered—or not.
Twilio Programmable SMS includes a helper library for Node.js that makes it easy to interact with the SMS API without having to create and manipulate connections to the API endpoints. Once an SMS message request is created with the helper library its status is emitted as a JavaScript Promise. While that is great for creating a request asynchronously, Promises only resolve once, and the message request will pass through more than one state as it makes its way—or not—to the recipient.
You can create a mechanism for monitoring and reporting the status of a message request using ReactiveX for JavaScript (RxJS) Observables, which can emit new results asynchronously as the data from an underlying source changes. By creating an Observable wrapper around each message request and calling the helper library’s status method periodically, you can get message delivery information for each number and asynchronously report the status for each number as it changes.
Important compliance note: There are rules for using SMS messaging and they vary between countries. Familiarize yourself with the rules of the countries in which you’ll be sending messages with the Twilio Regulatory Guidelines for SMS.
Understanding the tutorial project
This tutorial will show you how to create a Node.js application that sends an SMS message to a list of phone numbers and reports the status of each message. You’ll use Twilio Programmable SMS to send the messages by using the Twilio Helper Library for Node.js in your program. You’ll create a RxJS wrapper, a mechanism that enhances existing code with new functionality, around the SMS functionality in the helper library.
You’ll learn how to create an Observable from scratch and how to emit the status of an SMS request with an Observable. You’ll find out how to use the RxJS operators map, distinct, merge, tap, and catchError. You’ll also create a timeout mechanism using the RxJS timer function to abandon status polling when a timeout interval elapses.
Prerequisites
To accomplish the task in this post you will need the following:
- Node.js and npm (The Node.js installation will also install npm.)
- Twilio account (Sign up for free using this link and receive a $10 account credit.)
- Twilio CLI
- Git
You should also have a working knowledge of the core elements of JavaScript, asynchronous JavaScript mechanics, and ReactiveX programming.
There is a companion repository for this post available on GitHub.
Getting your Twilio account credentials
To use the Twilio CLI and interact with the Twilio APIs you’ll need two essential pieces of information from your Twilio Console Dashboard: Account SID and Auth Token. You can find them on the top right hand-side of the dashboard.
These are user secrets, so be sure to store them in a safe place.
To use your credentials in development, you’ll want to store them as environment variables or in a .env file. If you choose to store them in a file, be sure that the filename is included in your .gitignore file so you don’t inadvertently check them into a public repository. For the purposes of this tutorial, you’ll store your secrets as environment variables.
If you are using a Unix-based operating system, such as Linux or macOS, you can set environment variables using the following commands:
If you are a Windows user, use the following commands:
Getting a Twilio Phone Number
Twilio Programmable SMS messages are sent using Twilio phone numbers, which provide instant access to local, national, mobile, and toll-free phone numbers in more than 100 countries with a developer-friendly API. You can get a Twilio phone number for free as part of your trial account.
Once you’ve created a Twilio account you can get a Twilio phone number using the Twilio CLI.
Note: The Twilio CLI is in beta status as of the date of this post. If you’ve previously installed it, be sure you have the latest version by executing the following command:
If you’ve stored your Twilio credentials as environment variables, the Twilio CLI will use them automatically. If you’ve stored them in some other way, you’ll have to login first using the following command:
To list the phone numbers available for registration, use the following command, substituting the appropriate ISO 3166 alpha-2 country code for “US”, if necessary:
You should see a list similar to the following output:
Copy one of the numbers from the list and register it to your Twilio account using the following command:
If your registration attempt is successful, you should see the following:
Once registered, the phone number is available for your use (until you release it using the CLI or Twilio Console). Note that the SID associated with the phone number is a user secret and should be handled securely. Store registered phone number under the TWILIO_PHONE_NUMBER
environment variable in E.164 format.
If you use Linux, Unix, or macOS:
If you’re Windows user:
You can verify the number has been successfully added to your account by sending a test SMS to an SMS-enabled phone number:
Note that with a trial account you can only send messages to phone numbers you’ve previously registered to your account. The SMS-enabled phone number you used to sign up for your Twilio account is the first number you’ve registered.
The API will return a response similar to the below output to indicate that SMS message has been successfully received and is queued to be sent:
Within a short time you should receive an SMS message on your phone:
You can check status of message creation request using the following CLI command:
As a result, you will see:
Initializing the Node.js project
Once you’ve registered and tested the phone number, you can initialize the project and its Git repository with a series of command-line instructions.
Open a console window and execute the following instructions in the directory where you want to create the project directory:
You can learn more about initializing Node.js projects in this post by Twilio's Phil Nash.
Install the dependencies you are going to use:
Sending your first message with Twilio SMS and Node.js
Create a sms-basics.js file in the project’s root directory and place the following JavaScript code inside:
The program flow for the code above is depicted in the following diagram:
The program starts with the initialization of the Twilio client using your Twilio Account SID and Auth Token loaded from the environment variables. Once the client
is initialized you can send a message with Twilio Programmable SMS API. To do that you’ve called a client.messages.create
method and passed to it an object containing the message body body
, recipient to
and sender from
.
The client.messages.create
method of the Twilio helper library returns a Promise object which resolves with the results of the SMS creation request sent to the Twilio Programmable SMS API, shown in green on the diagram. You’ve sent it to the console with the first console.log
statement:
From the above data, you’ve picked up a sid
value, which is a unique identifier of your request, and passed it to the next link in the promise chain. In the chained function you’ve invoked the client.messages.fetch
method, which returns another Promise. That Promise resolves with the current status of the SMS creation request, shown in blue on the diagram. In the last then
you’ve printed that result to the console.
Ensure you’ve set up the environment variables TWILIO_ACCOUNT_SID
, TWILIO_AUTH_TOKEN
, and TWILIO_PHONE_NUMBER
and run the program:
Your console output should be similar to:
If you haven’t been following along with the coding and want to catch up to this step using the code from the GitHub repository, execute the following commands in the directory where you’d like to create the project directory:
Sending SMS messages to multiple phone numbers and monitoring message status with an RxJS Observables wrapper
Now that you’ve got Twilio SMS basics under your belt you can create an RxJS wrapper for the Twilio SMS API which is a part of the twilio
library.
Create a new file called rxjs-twilio.js in the project root directory. Start coding from introducing import statements and initializing the Twilio client by inserting the following code:
Define the sendSMS
function, which is an entry point of the rxjs-twilio
file. Insert the following JavaScript code at the bottom of the rxjs-twilio.js file:
The sendSMS
function accepts two parameters: the recipient’s phone number and the message body. A constant subject
represents the Observable that is returned by the function. Subject
is one of the implementations of the Observable
interface.
The client.messages.create
function creates an SMS message creation request through the Twilio API. When the Promise returned by the client.messages.create
function resolves, the status of the creation request is emitted through the subject
Observable.
The pollStatus
method, which you’ll implement next, monitors the state of the Observable returned by the Twilio helper library. If the message creation request sent to the Twilio SMS API fails, the error is emitted through the subject
Observable inside the catch
block.
The sendSMS
function uses the distinct
operator to avoid emitting a duplicate status value. If the message status has not changed from one invocation of pollStatus
to the next.
Insert the following code at the bottom of the rxjs-twilio.js file:
The constant messageDeliveryStatuses
is an array of strings representing the Finalized Message Delivery Status values for a message.
The stopPolling
array will contain a dictionary of flags indicating if the polling timeout has elapsed for each pending SMS message request. This is necessary because the “sent” status can indicate either that the message is in the process of being delivered or it was delivered and Twilio did not receive a delivery confirmation, or other status, from the carrier.
The pollStatus
function accepts up to four parameters, the last two are optional:
sid
– the ID of the message creation request to pollsubject
– the status of the message creation requesttimeout
– the time, in seconds, after which polling should stopwatchdog
– the subscription of an Observable created with thetimer
method, which determine when to flip the flag in thestopPolling
array to true for the associated message ID
If the status of your message creation request changes to one of the messageDeliveryStatuses
values or the stopPolling[sid]
flag is set to true, the unsubscribe
method abandons the watchdog and cleans up the callback queue and the splice
method removes the entry from the stopPolling
dictionary to avoid creating a memory leak.
If the request status is not one of the finalized delivery status values the pollStatus
function is called recursively. To avoid setting up a new watchdog for each recursive execution of the function in the inner pollStatus
invocations, the existing watchdog
is passed as an argument in the else
clause.
The client.messages(sid).fetch()
method returns a Promise that resolves with an object representing the state of each SMS request. When the Promise resolves, the result is emitted through the subject
Observable, which was passed as a parameter from the sendSMS
function.
The wrapper flow is depicted in the diagram below:
Testing the RxJS Observables wrapper
To put the Observables wrapper to use and see how it handles an unpredictable sequence of responses from the SMS API, you’ll need a program to iterate through a series of phone numbers and gather the Observables from each number into a collection. Then you can report on the status of each SMS message each time an Observable in the collection emits new information indicating a change in the status of the associated message request.
Create a file called sms.js in the project root and insert the following JavaScript code:
The code creates an array of phone numbers to send an SMS message. It iterates through each element of the array, invoking the sendSMS
function and passing a “Hello World!” message to it along with the phone number.
For testing purposes, use phone numbers that can accept SMS messages, like your registered number. Also include numbers, like landlines, that are valid numbers but can’t accept SMS messages. Include values that aren’t valid phone numbers to test how the program and the API handle invalid data.
The Observable returned by the sendSMS
is piped to the following operators:
map
removes some information from the Twilio API response, leaving only the phone number and current statuscatchError
catches errors that eventually occur and returns an Observable emitting the identity of the request that failed and the failure reasonmap
adds a timestamp to the response.
Each Observable returned by sendSMS
is pushed to the requests
array, which is then passed as a parameter to the merge
method to consolidate the array into one Observable.
The consolidated Observable is piped through the tap function, which performs a side action every time a new result is emitted by the Observable, creating a line in the output between each set of results as one of the SMS message requests is updated.
The action performed by the subscribe
operator sends the results emitted by the Observable to the console.
Run the program:
The output should be similar to:
The output shows the status of three message creation requests to the Twilio Programmable SMS API through the helper library for Node.js. Whenever the status of any of the requests changes, new output is produced.
Two of the phone numbers used in the sample code are not able to receive SMS, so the API will return error messages. Those types of errors will usually be returned right away.
For phone numbers capable of receiving SMS, the Observable will usually emit data three times because the message request will have three states: queued, sent, and delivered. The exception to this will be when the message can’t be delivered, such as when the phone is turned off, or the carrier doesn’t return a response to Twilio. In those cases the final state will be “sent”.
If you haven’t been following along with the coding and want to catch up to this step using the code from the GitHub repository, execute the following commands in the directory where you’d like to create the project directory:
Summary
This post introduced you to using Twilio Programmable SMS with RxJS Observables in a Node.js application. You’ve learned how to perform repetitive API calls and emit responses with Observables. You saw how to combine three Observables to create a new one that emits data whenever one of the inner Observable emits data. Using these techniques you can get updates on the delivery status of SMS messages sent with Twilio Programmable SMS.
Additional Resources
Twilio Programmable SMS – Send and receive text messages globally with the API that over a million developers depend on.
ReactiveX introductions and tutorials – The ReactiveX website has an extensive list of resources for learning more about Reactive Programming and the various language implementations. They’re 3rd-party productions, so watch and read at your own discretion.
RxJS – The RxJS website is the place for canonical information about the ReactiveX library for JavaScript.
Which Operator do I use? – A helpful tool for choosing the best Observables operator for a desired action.
If you want to learn more about JavaScript Promises, which are a better asynchronous tool for some programming situations, check out the following posts:
- Asynchronous JavaScript: Introduction to JavaScript Promises
- Asynchronous JavaScript: Advanced Promises with Node.js
If you’d like to learn more about RxJS Observables, check out this post:
Ready for more messaging excitement? Try some Programmable SMS missions in TwilioQuest!
Maciej Treder is a Senior Software Development Engineer at Akamai Technologies. He is also an international conference speaker and the author of @ng-toolkit, an open source toolkit for building Angular progressive web apps (PWAs), serverless apps, and Angular Universal apps. Check out the repo to learn more about the toolkit, contribute, and support the project. You can learn more about the author at https://www.maciejtreder.com. You can also contact him at: contact@maciejtreder.com or @maciejtreder on GitHub, Twitter, StackOverflow, and LinkedIn.
Gabriela Rogowska contributed to this post.
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.