Sending email messages through AWS SNS with Node SDK
Amazon Simple Notification Service is a fully managed messaging service based on the pubsub (publish-subscribe) paradigm.
1. About SNS
To start with SNS, one first needs to create a topic, which is a channel for the messages on a specific area. For example, a topic can be the deletion of objects from a specified S3 bucket, and that event can trigger a message published to the topic.
The topic owner (the account who created the topic) can decide who can publish (send) messages to the topic, and who can subscribe to it.
The message can get to the subscribers through various protocols: email, SMS, Lambda or HTTP, just to mention a few. When a new message arrives, the subscribers will automatically receive them, and there’s no need for requesting the message or polling for it.
A good analogy is to subscribe to a newsletter. We don’t need to ask for the latest edition of the newsletter, because we’ll receive it automatically.
2. Use cases
SNS is a powerful service, and it has many use cases in the AWS ecosystem. Some examples are:
- An object is deleted from an S3 bucket, and a notification is sent about it to the bucket owner.
- Archive download from Glacier has finished.
- Publish message to SQS.
- Broadcast time-critical messages to mobile applications.
- Send a message when an ElastiCache node fails.
These are just a few of the many use cases.
3. Create messages with Node SDK
The awesome news is that we can also publish messages and see SNS work with the help of the NodeJS SDK and the AWS CLI.
3.1. Pre-requisites
You’ll need an AWS account and credentials for programmatic access. The CLI also needs to be installed on your computer. If it’s still not there (shame), here’s a good guide on how to do it properly.
3.2. Cost
This post covers how to send messages via email and SMS. If you are eligible for the free tier, running the commands and the code below won’t cost you anything. AWS provides the first 100 SMSs and 1 000 emails for free. However, sending SMSs worldwide cost 3-4 cents, so if you have a non-US phone number, expect a minimal charge for sending phone messages.
3.3. Create a topic
The first step is to create a topic. An account can have up to 100 000 topics, but this threshold won’t be challenged in this post.
We can create a new topic using the create-topic
command of the CLI:
aws sns create-topic --region us-west-2 --name TestTopic
The response should be similar to this:
{
"TopicArn": "arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic"
}
The TopicArn
is the ID of the SNS topic, and it contains the account ID of the creator and the name of the topic.
If the account has already created a topic of the same name, the response will return the ARN of the existing topic, so no new topic will be created.
The TopicArn
will be needed for the subscription, and it’s a good idea to copy it.
3.4. Add email subscription
Email is one of the protocols SNS supports to send messages to. The email address to which the messages will be sent is called an endpoint. Similarly, for the SMS protocol, the endpoint will be the phone number where the SMS is sent to.
We can use the subscribe
command in the CLI to add our (or someone else’s) email address to the so far empty list of subscribers.
We’ll need to specify three things: the topic which we subscribe to (TestTopic
), the protocol (email) and the endpoint (the email address):
aws sns subscribe --topic-arn arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic --protocol email --notification-endpoint <YOUR EMAIL ADDRESS>
The response will be this:
{
"SubscriptionArn": "pending confirmation"
}
We got the state of the subscription back, which is pending confirmation
. It means that this email address hasn’t subscribed yet, and it needs to be confirmed. AWS sends an email to this address starting with You have chosen to subscribe to the topic: arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic
, and a link to click on to confirm the subscription. The link is valid for three days.
So go ahead, and confirm it. The link will redirect to the confirmation page, where the ARN and the ID (a UUID) of the subscription can be seen.
We can also confirm the subscription from the CLI:
aws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic
We’ll get a Subscriptions
array back, where each element is a Subscription
object with the above mentioned ID (SubscriptionArn
) and other important pieces of data:
{
"Subscriptions": [
{
"SubscriptionArn": "arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic:87a65128-a0d7-4e2d-a2c5-1720e688587b",
"Owner": "<ACCOUNT ID>",
"Protocol": "email",
"Endpoint": "<YOUR EMAIL>",
"TopicArn": "arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic"
}
]
}
Because the subscription has now an ID, we can start sending messages to our email address.
3.5. Publish messages
We can simulate how other services send messages by creating some code using the SDK. We can also write applications that use SNS to send emails or SMSs with this code.
In the project folder, type npm init -y
, then npm install aws-sdk
. In a file called publish-sns-message.js
(the name can be anything else, of course), we can write the following code:
const AWS = require('aws-sdk')
const sns = new AWS.SNS({
region: 'us-west-2'
})
const params = {
Subject: 'My first test message',
Message: 'This is my first test message from SNS. \n If you receive this message, then you have done a good job!',
TopicArn: 'arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic'
}
const publishToSNS = async () => {
try {
const { MessageId } = await sns.publish(params).promise()
console.log(`Your message with id ${ MessageId } has been delivered.`)
} catch (e) {
console.log(e)
}
}
publishToSNS()
The structure of the code follows the usual AWS SDK pattern. First, we have to require
the SDK, then initiate the SNS class with the new
keyword. We define the region at the service (i.e. SNS) level, in this case, it’s us-west-2
.
SDK services accept an argument called params
. Let’s have a look at the most basic properties of params
for SNS.
Subject
will be the subject of the message SNS sends to the email address (endpoint). This seems to be quite straightforward.
Message
is also not very hard to reason about, this will be the text we (and other subscribers) will receive in the body of the email.
It’s important to define the TopicArn
property, otherwise SNS won’t know which channel to send the message to. Paste here the ARN of the topic copied above when it was created using the CLI.
The publishToArn
is an async
wrapper function around the publish
method of sns
. As with most methods, publish
can be changed to return a Promise by chaining the promise
built-in method. We can use try/catch to await
the value of what the promise has been resolved with.
The response will contain the MessageId
, which we can log to the console for now, but it can also be saved to the database in the real application, so that we can track which message was sent where.
And finally, the moment of truth! In the terminal, type node publish-sns-message.js
, and if everything goes well (and why not), a message like this
Your message with id 12474982-f3af-5d77-92a6-1c0b10c004a2 has been delivered.
should appear in the console.
What’s even more cool, check your mailbox, and be amazed, because you should have received an email from AWS Notifications with the content described in the Message
property.
3.6. Send SMS
But that’s not all. As it was mentioned above, SNS supports multiple protocols for subscribers. Let’s quickly add a phone number endpoint to the (so far very short) list of subscribers:
aws sns subscribe --topic-arn arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic --protocol sms --notification-endpoint <YOUR PHONE NUMBER>
The protocol
here is sms
because we want to send an SMS to our phone number. The notification-endpoint
will be your (or someone else’s) phone number in +61123456789
format. Phone numbers don’t need to be confirmed.
We need to make a small change in the code. In this case, params
will handle multiple messages to different endpoints, so the string value doesn’t work here. It needs to be a stringified JSON object.
Let’s create a messages
object with JSON-compatible keys and values:
const messages = {
"default": "This is the default message",
"email": "This is my first test message from SNS. \n If you receive this message, then you have done a good job!",
"sms": "SMS from SNS"
}
We added the sms
key, and the value (the message sent to the phone) is different from the email, because SNS supports this feature. When a stringified object is added to params
, we’ll need to define a default
message in case something goes wrong.
The params
object will be changed like this:
const params = {
Subject: 'My first test message',
MessageStructure: 'json',
Message: JSON.stringify(messages),
TopicArn: 'arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic'
}
Message
will be the stringified object (messages
), and we’ll also need to define the MessageStructure
property, which is in this case json
.
Let’s run the code again, and you should receive another email from AWS as well as an SMS from NOTICE. Magic!
4. Clean-up
After we sent a few email messages and SMSs, it’s a good idea to clean up i.e. delete the subscriptions and the topic.
It’s important to note that subscriptions in Confirmed
state can be deleted.
When we delete the topic, all of its subscriptions will also be deleted.
The following CLI command will delete the topic:
aws sns delete-topic --topic-arn arn:aws:sns:us-west-2:<ACCOUNT ID>:TestTopic
The command doesn’t return anything. If we try to delete a topic that doesn’t exist, we won’t receive anything back either, so the we can use the list-topics
CLI command to check if we still have the TestTopic
:
{
"Topics": []
}
We don’t.
Subscription to the topic won’t be deleted immediately, but they become orphans, and AWS deletes them periodically.
5. Summary
AWS SNS is a messaging service based on the pubsub principle. Entities using different protocols (email, HTTP(S), phone, lambda, SQS) can subscribe to topics, and when a new message is published to the topic, the subscribers will automatically receive the message.
With the help of the SDK, message sending applications can be created using the traditional AWS SDK method schema of params
and promise
.
Thanks for reading, and see you next time.