Setting SMS marketing subscriptions with MessageBird

⏱ 30 min build time || Download the Code

Why build SMS marketing subscriptions?

In this MessageBird Developer Tutorial, you’ll learn how to implement an SMS marketing campaign subscription application powered by the MessageBird SMS API, which enables your subscribers to seamlessly opt-in and out.

SMS makes it incredibly easy for businesses to reach consumers everywhere at any time, directly on their mobile devices. For many people, these messages are a great way to discover things like discounts and special offers from a company, while others might find them annoying. For this reason, it’s important and also required by law in many countries to provide clear opt-in and opt-out mechanisms for SMS broadcast lists. To make it work independently of a website it's useful to assign a programmable virtual mobile number to your SMS campaign and handle incoming messages programmatically so users can control their subscription with basic command keywords.

We'll walk you through the following steps:

  • A person can send the keyword SUBSCRIBE to a specific VMN that the company includes in their advertising material; the opt-in is immediately confirmed.
  • If the person no longer wants to receive messages, they can send the keyword STOP to the same number; the opt-out is also confirmed.
  • An administrator can enter a message in a form on a website. Then they can immediately send this message to all confirmed subscribers.

Getting started

First things first, our sample application is built in Node.js, so you’ll need Node and npm, you can easily install them for free.

You can download or clone the complete source code from the MessageBird Developer Tutorials GitHub repository to run the application on your computer and follow along with the tutorial.

To install the MessageBird SDK for Node.js and other dependencies, open a console pointed at the directory into which you've placed the sample application and run the following command:

npm install

The sample application uses mongo-mock to provide an in-memory database for testing, so you don't need to configure an external database.

Prerequisites for receiving messages

Overview

This tutorial describes receiving messages using MessageBird. From a high-level viewpoint, receiving is relatively simple: your application defines a webhook URL, which you assign to a number purchased on the MessageBird Dashboard using Flow Builder. A webhook is a URL on your site that doesn't render a page to users but is like an API endpoint that can be triggered by other servers. Whenever someone sends a message to that number, MessageBird collects it and forwards it to the webhook URL, where you can process it.

Exposing your development server with localtunnel

When working with webhooks, an external service like MessageBird needs to access your application, so the webhook URL must be public; however, during development you're typically working in a local development environment that is not publicly available. Thankfully this is not a big deal since various tools and services allow you to quickly expose your development environment to the Internet by providing a tunnel from a public URL to your local machine. One of these tools is localtunnel.me, which you can install using npm:

npm install -g localtunnel

You can start a tunnel by providing a local port number on which your application runs. Our sample is configured to run on port 8080, so you can launch your tunnel with this command:

lt --port 8080

After you've launched the tunnel, localtunnel displays your temporary public URL. We'll need that in a minute.

Another common tool for tunneling your local machine is ngrok, which works virtually in the same way; you can have a look at it if you're facing problems with localtunnel.me.

Get an inbound number

A requirement for receiving messages is a dedicated inbound number. Virtual mobile numbers look and work similar to regular mobile numbers; however, instead of being attached to a mobile device via a SIM card, they live in the cloud and can process inbound SMS and voice calls. MessageBird offers numbers from different countries for a low monthly fee; feel free to explore our low-cost programmable and configurable numbers.

Purchasing a number is quite easy:

  1. Go to the ‘Numbers’ section in the left-hand side of your Dashboard and click the blue button ‘Buy a number’ in the top-right side of your screen.

  2. Pick the country in which you and your customers are located, and make sure the SMS capability is selected.

  3. Choose one number from the selection and the duration for which you want to pay now.

  4. Confirm by clicking ‘Buy Number’ in the bottom-right of your screen.

VMN

Awesome, you’ve set up your first virtual mobile number! 🎉

Pro-tip: Check out our Help Center for more information about virtual mobile numbers and country restrictions.

Connect your number to the webhook

So you have a number now, but MessageBird has no idea what to do with it. That's why now you need to define a Flow that links your number to your webhook. This is how you do it:

STEP ONE

On the Numbers section of the MessageBird Dashboard, click the "Add new flow" icon next to the number you purchased.

VMN

STEP TWO

Hit ‘Create Custom Flow’ and give your flow a name, choose ‘SMS’ as the trigger and hit ‘Next’.

VMN

STEP THREE

The number is already attached to the first step ‘SMS’. Add a new step by pressing the small ‘+’, choose ‘Fetch to URL’ and select ‘POST’ as the method; copy the output from the lt command in the URL and add /webhook to it—this is the name of the route we use to handle incoming messages in our sample application. Click on ‘Save’ when ready.

VMN

STEP FOUR

Ready! Hit ‘Publish’ on the right top of the screen to activate your flow. Well done, another step closer to testing incoming messages! Your flow should look something like this:

VMN

Pro-tip: It might be useful to rename it this flow, because Untitled flow won't be helpful in the long run. You can do this by clicking on the icon next to button ‘Back to Overview’ and pressing ‘Rename flow’.

VMN

A number must be added to your MessageBird contact list before you can send SMS messages to it. To make sure that any phone number that sends a message to your VMN can receive messages from you, you can add an Add Contact step just before the ‘Forward to URL’ step. Be sure to configure the `Add Contact’ step to add the "sender" to your contact list.

Configuring the MessageBird SDK

While the MessageBird SDK and an API key are not required to receive messages, it is necessary for sending confirmations and marketing messages. The SDK is defined in package.json and loaded with a statement in index.js:

// Load and initialize MessageBird SDK
var messagebird = require('messagebird')(process.env.MESSAGEBIRD_API_KEY);

You need to provide a MessageBird API key, as well as the phone number you registered so that you can use it as the originator via environment variables. Thanks to dotenv you can also supply these through an .env file stored next to index.js:

MESSAGEBIRD_API_KEY=YOUR-API-KEY
MESSAGEBIRD_ORIGINATOR=+31970XXXXXXX

Let's create your live API access key. First, go to the MessageBird Dashboard; if you have already created an API key it will be shown right there. If you don’t see any key on the Dashboard or if you're unsure whether this key is in live mode, go to the Developers section in the MessageBird Dashboard and open the API access (REST) tab. There you can create new API keys and manage your existing ones.

Receiving messages

Now we're fully prepared for receiving inbound messages; let's have a look at the actual implementation of our /webhook route:

// Handle incoming webhooks
app.post('/webhook', function(req, res) {
// Read input sent from MessageBird
var number = req.body.originator;
var text = req.body.payload.trim().toLowerCase();

The webhook receives some request parameters from MessageBird; however, we're only interested in two of them: the originator (the number of the user who sent the message) and the payload (the text of the message). The content is trimmed and converted into lower case so we can easily do case-insensitive command detection.

MongoClient.connect(dbUrl, {}, function(err, db) {
// Find subscriber in our database
var subscribers = db.collection('subscribers');
subscribers.findOne({ number : number }, function(err, doc) {

Using our MongoDB client, we'll look up the number in a collection aptly named subscribers.

We're looking at three potential cases:

  • The user has sent SUBSCRIBE and the number doesn’t exist. In that case, the subscriber should be added and opted in.
  • The user has submitted SUBSCRIBE and the number exists but has opted out. In that case, it should be opted in (again).
  • The user has sent STOP and the number exists and has opted in. In that case, it should be opted out.

For each of those cases, a differently worded confirmation message should be sent. For the sake of keeping the tutorial simple, all incoming messages that don't fit any of these cases are ignored and don't get a reply; however, for production-ready applications, you can optimize this behavior by sending a help message with all supported commands.

The implementation of each case is similar, so let's only look at one of them here:

if (doc == null && text == 'subscribe') {
// The user has sent the "subscribe" keyword
// and is not stored in the database yet, so
// we add them to the database.
subscribers.insertOne(
{
number: number,
subscribed: true,
},
function(err, result) {
console.log('subscribed number', err, result);
},
);
// Notify the user
messagebird.messages.create(
{
originator: process.env.MESSAGEBIRD_ORIGINATOR,
recipients: [number],
body: 'Thanks for subscribing to our list! Send STOP anytime if you no longer want to receive messages from us.',
},
function(err, response) {
console.log(err, response);
},
);
}

If no doc (database entry) exists and the text matches “SUBSCRIBE”, the script executes an insert query that stores a document with the number and the boolean variable subscribed set to true. The user is notified by calling the messagebird.messages.create() SDK method and, as parameters, passing the originator from our configuration, a recipient list with the number from the incoming message and a hardcoded text body.

Sending messages

Showing form

We've defined a simple form with a single text area and a submit button, and stored it as a Handlebars template in views/home.handlebars. It’s rendered for a GET request on the root of the application. As a small hint for the admin, we're also showing the number of subscribers in the database.

Processing input

The form submits its content as a POST request to the /send route. The implementation of this route fetches all subscribers that have opted in from the database and then uses the MessageBird SDK to send a message to them. It’s possible to send a message to up to 50 receivers in a single API call, so the script splits a list of subscribers that is longer than 50 numbers (highly unlikely during testing, unless you have amassed an impressive collection of phones) into blocks of 50 numbers each. Sending uses the messagebird.messages.create() SDK method which you've already seen in the previous section.

Here's the full code block:

app.post('/send', function(req, res) {
// Read input from user
var message = req.body.message;
MongoClient.connect(dbUrl, {}, function(err, db) {
// Get number of subscribers to show on the form
var subscribers = db.collection('subscribers');
subscribers.find({ subscribed: true }, {}).toArray(function(err, docs) {
// Collect all numbers
var recipients = [];
var count = 0;
for (var d in docs) {
recipients.push(docs[d].number);
count = parseInt(d) + 1;
if (count == docs.length || count % 50 == 0) {
// We have reached either the end of our list or 50 numbers,
// which is the maximum that MessageBird accepts in a single
// API call, so we send the message and then, if any numbers
// are remaining, start a new list
messagebird.messages.create(
{
originator: process.env.MESSAGEBIRD_ORIGINATOR,
recipients: recipients,
body: message,
},
function(err, response) {
console.log(err, response);
},
);
recipients = [];
}
}
res.render('sent', { count: count });
});
});
});

Testing

You’re done! It’s time to test your application.

Double-check that you’ve set up your number correctly with a flow that forwards incoming messages to a localtunnel URL and that the tunnel is still running. Keep in mind that whenever you start a fresh tunnel, you'll get a new URL, so you have to update it in the flows accordingly. You can also configure a more permanent URL using the -s attribute with the lt command.

To start the sample application you have to enter another command, but your existing console window is now busy running your tunnel, so you need to open another one. With Mac you can press Command + Tab to open a second tab that's already pointed to the correct directory. With other operating systems you may have to open another console window manually. Either way, once you've got a command prompt, type the following to start the application:

node index.js

While keeping the console open, take out your phone, launch the SMS app, and send a message to your virtual mobile number with the keyword "SUBSCRIBE". You should receive a confirmation message stating that you've been subscribed to the broadcast list. Open http://localhost:4567/ in your browser (or your tunnel URL) and you should also see that there's one subscriber. Try sending yourself a message now. And voilá, your marketing system is ready!

You can adapt the sample application for production by replying mongo-mock with a real MongoDB client, deploying the application to a server and providing that server's URL to your flow. Of course, you should add some authorization to the web form; otherwise, anybody could send messages to your subscribers. Don't forget to download the code from the MessageBird Developer Tutorials GitHub repository.

Nice work! 🎉

You've just built your own marketing system with MessageBird with Node.js!

Start building!

Want to build something similar but not quite sure how to get started? Feel free to let us know at support@messagebird.com; we'd love to help!

Questions?

We’re always happy to help with code or other doubts you might have! Check out our Quickstarts, API Reference, Tutorials, SDKs, or contact our Support team.

Cookie Settings