Making a one-to-many mobile-only SMS broadcaster

Do you need business messaging that can be easily accessed without the use of internet? SMS is great for infield business communications because you can often get a message even when your internet is unreliable. So how about we make a two way, one-to-many SMS broadcaster.

Imagine you’re writing software for a school. The school organises an annual camp for students and needs to be able to contact parents with updates about various things. Unfortunately, this year the camp flooded and the group will arrive back in town, hours later than expected. Due to the remote location of the camp, the internet coverage is spotty at best and your school software needs a way to easily bulk send communications to the parents.

Let’s try using a MessageMedia dedicated number, webhooks, and a simple lambda function to create a special number to text, which then broadcasts that message to everyone on a list.

In this example, a list of parents and their phone numbers are stored in a DynamoDB database (Parents). Inbound orders are sent via MessageMedia webhooks to a POST route on an AWS API Gateway which calls a Lambda function (sendMessage) that scans all the phone numbers and sends the texts.

Prerequisites

  • You will need a MessageMedia API Key and Secret, which you can get here.
  • An AWS account.
  • A MessageMedia dedicated number – this is a paid feature, please
    speak to support
    to have it turned on for your account.

Database Setup

Create a DynamoDB table using the AWS console. Specify table name as ‘Parents’. Specify the name of the partition key as ‘phoneNumber’ with type String. Keep table settings at default and click ‘Create’.

In the table you just created go to the Indexes tab. Click ‘Create index’ and specify ‘parentName’ typed String as the partition key (a sort key is not required). You’ll need the ARN of the database you just created for the next step.

IAM Setup

You need to create a policy that allows access to your table. This policy will be used for direct access to the database from the client. In the AWS IAM console go to Policies, Create Policy and Create your own Policy. Name the policy ‘ParentDetailsAccess’ and copy the policy from below, replacing with the respective ARNs of your tables:

{
 "Version": "2012-10-17",
 "Statement": [
 {
 "Sid": "DBAccessStatement",
 "Effect": "Allow",
 "Action": [
 "dynamodb:*"
 ],
 "Resource": [
 "arn:aws:dynamodb:{region}:{id}:table/Parents"
 ]
 }
 ]
 }

Now, in the AWS IAM console, create a new user named ‘ParentListUser’ and allow programmatic access. In the next screen choose ‘Attach existing policies directly’, search for your ‘ParentDetailsAccess’ policy and assign it. At the end of the process copy and save the access key ID and secret access key in the designated places inside website/config.js.
Also, create a role. Choose AWS service and Lambda. In the next screen, attach the default ‘AWSLambdaInvocation-DynamoDB’ as well as your previously created policy ‘ParentDetailsAccess’ to this role. Name it ‘BroadcastRole’ and confirm.

Lambda Setup for handleMessage

In the AWS Lambda console create a new function, choose ‘Author from scratch’, enter name ‘handleMessage’ and choose the previously created ‘BroadcastRole’.
Copy the source code from the following files into the Lambda console and create two environment variables named USERNAME and PASSWORD with your MessageMedia credentials.
Save the function with a name like “broadcaster”.

Index.js

var AWS = require("aws-sdk");
var app = require ('./app');

var config = {
 tableName : "parents",
 counterTableName : "Counters",
 counterTableField : "orderId"
};

var docClient = new AWS.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
 console.log('Received event:', JSON.stringify(event, null, 2));
 
 // Verify request format
 var input = event;
console.log("sending message");

// create the broadcast
 app.sendMessage(
 input.content,
 () => { callback(null, app.successResponse()); });
 
};

app.js

var AWS = require("aws-sdk");
var https = require("https");

var config = {
 tableName : "parents",
 counterTableName : "Counters",
 counterTableField : "orderId"
};

var docClient = new AWS.DynamoDB.DocumentClient();

module.exports = {

 /**
 * Sends a message via MessageMedia API.
 */
 sendMessage : (message, callback) => {

console.log("Scanning parents table.");
 
 docClient.scan({
 TableName: "parents",
 ProjectionExpression: "phoneNumber"
 }, function(err, parents) {
 if (err) {
 console.log("Error: " + JSON.stringify(err));
 } else {
 
 var request = https.request({
 hostname : "api.messagemedia.com",
 path : "/v1/messages",
 auth : process.env.USERNAME + ":" + process.env.PASSWORD,
 method : "POST",
 headers: { "Content-Type" : "application/json" }
 });
 
 var messagesArray = [];
 
 parents.Items.forEach(function(parent) {
 console.log("creating a message");
 
 var message1 = {
 content : message,
 destination_number : parent.phoneNumber
 };
 
 messagesArray.push(message1);
 
 });
 
 request.write(JSON.stringify({
 messages : messagesArray
 } ));
 request.end();
 callback();
 }
 }
 );

},


 /**
 * Generate a success response for the Lambda callback.
 */
 successResponse : () => {
 return {
 statusCode: 200,
 body: JSON.stringify({ "ok" : true }),
 headers: { "Content-Type": "application/json" }
 };
 }

}

API Gateway Setup

The API gateway needs just one route to receive the webhook from incoming SMS messages from MessageMedia. Go to Amazon API Gateway in the AWS console and create a new API. Choose New API, provide a name (e.g. “Coffee Order System”) and click Create. Click Actions, Create Resource, enter resource name “Webhook” and path “/webhook” and Create Resource. Under the newly created path click Actions, Create Method and choose POST. Set up this method to invoke the previously created Lambda function broadcaster. Click Actions, Deploy API. Create a new stage named production and Deploy. Copy the Invoke URL, concatenate the string /webhook at the end and provide this URL to your MessageMedia account manager for setup.

The Webhook

You can set up webhooks either in the web portal, or via the MessageMedia Webhooks Management API. To use the API, we can download the PostMan collection. Follow the instructions on the repository to add your API Key and Secret, and copy the following in the body, in Postman:

{ “url”: “YOURURL/production/webhook, “method”: “POST”, “encoding”: “JSON”, “headers”: { }, “events”: [ “RECEIVED_SMS” ], “template”: “{\”content\”:\”$moContent\”,\”source_number\”:\”$sourceAddress\”}” }

When you click submit in postman, this will create a webhook that sends the content of “template” to the API gateway (make sure you put your API gateway URL in the right spot above).

Conclusion

Now you’ve got everything set up and ready to go. To finish off, import all of your parent name and phone number entries into the database you created earlier. When you send a message to your dedicated number, a webhook will be triggered to pull all of the numbers from your database and broadcast the exact same message to each. There are numerous applications for this sort of facility, such as weather warning alerts, in field communications between drivers, and more. This can be a cheap, effective way to broadcast communications without the need for a computer or a stable internet connection.