AWS Compute Blog
Outbound Voice Calling with Amazon Pinpoint
This post is courtesy of Tom Moore, Solutions Architect – AWS
With the recent extension of Amazon Pinpoint to allow an outgoing voice channel, customers can now build applications that include voice messaging to their users. Potential use cases include two-factor authentication via voice for your website and automated reminders of upcoming appointments. This blog post guides you through the process of setting up this functionality.
The Amazon Pinpoint voice channel allows for outbound calls only. If your use case requires additional capabilities such as an interactive voice response (IVR) system, you need to use Amazon Connect instead for your messaging.
Prerequisites
- You have an AWS account
- You have installed the AWS Command Line (AWS CLI) tools
- You have installed the AWS Serverless Application Model (AWS SAM) CLI
As part of this configuration, you set a default AWS Region. You should set the default Region to the Region where Amazon Pinpoint is available. Valid Regions are currently US East (N. Virginia), US West (Oregon), EU (Ireland), and EU (Frankfurt). If you have already installed and configured the AWS CLI tools and your default Region doesn’t support Amazon Pinpoint, do one of the following:
- Run the
aws configure
command and change the default Region - Specify the
--region
switch on any commands that you issue
The Region that you select for the AWS CLI must be the same region you select in the AWS Management Console. To change the Region on the console, choose the down arrow next to the displayed Region (N. Virginia in the following image) and select the new Region.
Services
This blog post touches on the following AWS services:
- AWS Lambda
- Amazon Pinpoint
- Amazon Polly
- Amazon CloudWatch Logs
- AWS Identity and Access Management (IAM)
Because the code for this blog post is in NodeJS, basic familiarity with JavaScript is helpful for understanding the code and making changes to it.
Pricing
This blog post uses two features that aren’t covered under the AWS Free Tier: Amazon Pinpoint long codes (virtual phone numbers) for messaging and Amazon Pinpoint voice messaging. For pricing information for these features, see Amazon Pinpoint long code pricing and Amazon Pinpoint voice message pricing.
For example, suppose that you set up the Amazon Pinpoint application in a US Region with a single phone number and make 10 minutes of outbound calls to US phone numbers. You incur the following charges.
Item | Quantity | Unit Cost | Total |
Long codes | 1 | $1.00 | $1.00 |
Call charges | 10 | $0.013 | $0.13 |
Total | $1.13 |
Creating an Amazon S3 bucket
To deploy your AWS SAM application, you need an Amazon S3 bucket to store the deployment files. When you create a bucket in your account, note the bucket name for later use, where YOUR_BUCKET
appears in our code. This bucket is used for temporary storage of your AWS SAM deployments. It shouldn’t be publicly accessible.
On the Amazon S3 console, choose Create Bucket.
Enter a name for the bucket. The name must conform to the Amazon S3 bucket naming requirements. Choose the Region where you will be deploying your Lambda function and using Amazon Pinpoint. Keep the rest of the defaults and choose Create.
If you prefer, you can use the following command with the AWS CLI to create the S3 bucket in your account.
aws s3 mb s3://{Bucket Name}
Setting up Amazon Pinpoint
The first step in enabling outbound calling is to set up Amazon Pinpoint.
On the AWS Management Console, under Customer Engagement, choose Amazon Pinpoint. Enter a project name and choose Create a project.
If you have already created Amazon Pinpoint projects in this Region, you get a project-list page instead of a getting-started page, as shown in the following image. On this page, choose Create a project and enter a project name.
Now you can select the project features that you want to enable. On the Configure features page, for SMS and voice, choose Configure.
On the Set up SMS page, expand the Advanced configurations section and choose Request long codes.
On the Long code specifications page, select the country that you want to request the long code (10-digit phone number) for. Keep the rest of the defaults and choose Request long codes.
You’re assigned a phone number and returned to the Amazon Pinpoint configuration page. The phone number assigned to your application appears under Number settings, as shown in the following image. You can send voice messages only from a long code that your account owns.
This completes the Amazon Pinpoint setup.
Creating the application
AWS SAM provides a more streamlined process for creating serverless applications. The AWS SAM CLI also provides a convenient mechanism for packaging and deploying your serverless applications. For the code in this blog post, see Amazon Pinpoint Call Generator on GitHub. You can also deploy this application through the AWS Serverless Application Repository. For more information, see Amazon Pinpoint Call Generator.
Once you have a copy of the code, you need to make a few changes using your favorite text editor or IDE.
Modifying the template file
The template file, template.yaml
, defines your AWS SAM application. Specifically, the template defines two resources: an IAM role for your serverless function and the serverless function itself.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Serverless application to trigger outbound calls from Pinpoint.
Globals:
Function:
Timeout: 30
Resources:
CallGeneratorFunctionIamRole:
Type: AWS::IAM::Role
Properties:
RoleName: PinpointCallGenerator-Role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: '/'
Policies:
- PolicyName: logs
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
- PolicyName: Pinpoint
PolicyDocument:
Statement:
- Effect: Allow
Action:
- sms-voice:*
Resource: '*'
CallGeneratorFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: app.lambda_handler
Runtime: nodejs8.10
FunctionName: PinpointCallGenerator
Role: !GetAtt CallGeneratorFunctionIamRole.Arn
Environment:
Variables:
LongCode: '[YOUR_LONG_CODE_HERE]'
Language: 'en-US' #Update this for different language
Voice: 'Joanna' #Update this for different voices
#Outputs:
CallGeneratorLambdaFunction:
Description: "Lambda function to trigger calls"
Value: !GetAtt CallGeneratorFunction.Arn
CallGeneratorFunctionIamRole:
Description: "IAM Role created for this function"
Value: !GetAtt CallGeneratorFunctionIamRole.Arn
The CallGeneratorFunctionIamRole
IAM role allows the Lambda function to create CloudWatch Logs entries for monitoring the execution of your Lambda function and to call the Amazon Pinpoint voice service.
The Environment
section of the CallGeneratorFunction
definition sets the environment parameters that are provided to your Lambda function. By using environment variables, you can easily change the configuration for how your application makes calls without having to update your code.
Update the LongCode
parameter to the number that you reserved through Amazon Pinpoint. In Amazon Pinpoint, the number appears as +1 123-456-7890, but in the template, you can’t use spaces or punctuation in the number: +11234567890.
Optionally, you can update the Language
and Voice
parameters to reflect different cultures. For valid options for these parameters, see Voices in Amazon Polly.
Understanding the source file
The main source file is app.js
. It contains the NodeJS code for the application.
The exports
line defines a standard Lambda handler that is called from the Lambda runtime. The triggerCall
function handle the calling of Amazon Pinpoint asynchronously.
const AWS = require('aws-sdk');
var pinpointsmsvoice = new AWS.PinpointSMSVoice({apiVersion: '2018-09-05'});
function triggerCall (eventData) {
return new Promise (resolve => {
var parms = {
Content: {
SSMLMessage: {
LanguageCode : process.env.Language,
Text : eventData.Message,
VoiceId: process.env.Voice
}
},
OriginationPhoneNumber: process.env.LongCode,
DestinationPhoneNumber: eventData.PhoneNumber
};
console.log ("Call Parameters: ", JSON.stringify(parms));
pinpointsmsvoice.sendVoiceMessage (parms, function (err, data) {
if (err) {
console.log ("Error : "+ err.message);
resolve(eventData.PhoneNumber + " " + err.message);
}
else {
console.log (data);
resolve(eventData.PhoneNumber + " OK");
}
});
});
}
exports.lambda_handler = async (event, context, callback) => {
console.log ("In Function - lambda_handler")
try {
var result = await triggerCall (event);
}
catch (err) {
console.log(err);
callback(err, null);
}
};
The parms
structure defines the standard payload that is passed to Amazon Pinpoint to trigger a voice phone call. In this case, the parameters are all extracted from either the message payload or the environment variables defined in our AWS SAM template. We’re expecting the message to be passed in as a Synthesized Speech Markup Language (SSML) payload.
var parms = {
Content: {
SSMLMessage: {
LanguageCode : process.env.Language,
Text : eventData.Message,
VoiceId: process.env.Voice
}
},
OriginationPhoneNumber: process.env.LongCode,
DestinationPhoneNumber: eventData.PhoneNumber
};
The following code sends the parameters off to Amazon Pinpoint to trigger the voice call and then resolves the asynchronous call.
pinpointsmsvoice.sendVoiceMessage (parms, function (err, data) {
if (err) {
console.log ("Error : "+ err.message);
resolve(eventData.PhoneNumber + " " + err.message);
}
else {
console.log (data);
resolve(eventData.PhoneNumber + " OK");
}
});
Packaging and deploying the application
Deploying an AWS SAM application requires the following commands.
sam validate
This command verifies that your template is valid, free from errors.
sam package --template-file template.yaml --output-template-file packaged.yaml --s3-bucket [YOUR_BUCKET]
This command packages up your resources into a zip file and uploads the resulting files to your S3 bucket in preparation for deployment. The command also creates the packaged.yaml template file, which contains the details necessary to deploy your application via AWS CloudFormation.
sam deploy --template-file packaged.yaml --stack-name pinpoint-call-generator --capabilities CAPABILITY_NAMED_IAM
This command deploys your packaged files using AWS CloudFormation.
After all commands have completed, your function is ready to test.
Testing the application
After you have deployed your application, you can test it on the Lambda console. Sign in to the AWS Management Console and then choose or search for Lambda.
On the Lambda console, choose the function’s name to open it.
On the function’s page, choose Test.
When you first choose Test, an editor opens. Here you can configure the payload that Lambda passes your function as part of the test call.
Replace the default text with the following.
{
"Message" : "<speak>This is a text from <emphasis>Pinpoint</emphasis> using SSML. <break time='1s' /> I repeat. This is a text from <emphasis>Pinpoint</emphasis> using SSML.</speak>",
"PhoneNumber" : "+11234567890"
}
The Message portion of the payload is defined in SSML. For more information about SSML, see Speech Synthesis Markup Language (SSML) Reference.
Update the PhoneNumber
value with the phone number that you want to call and enter a name for your test payload. To save the configured payload to use in your tests, choose Save.
After the configuration panel closes, choose Test. Amazon Pinpoint calls your phone number and read the message out.
Conclusion
The blog post walked you through the basis of setting up outbound calling using Amazon Pinpoint. You can now trigger the Lambda function with any of the standard Lambda event triggers or with the AWS SDK in mobile or web applications. For example, you could provide a one-time password to users, trigger reminders for appointments, or notify someone when a file arrives in an S3 bucket.
The provided function code is intended to respond to single message-triggering events. These include application logic, files arriving in S3, or scheduled reminders. You need to make additional changes to support bulk event sources such as Amazon SQS or streaming sources such as Amazon DynamoDB streams and Amazon Kinesis. For more information about Lambda event sources, see Supported Event Sources.
If your use case requires additional resiliency, you might want to use Amazon SNS or Amazon SQS to deliver messages to Lambda. If your customers are from an international audience, you might consider passing the language and the voice through the event and updating the code to retrieve those values.