Sending email messages through AWS SNS with Node SDK

Amazon SNS is often used to send messages on various protocols, and it's easy to test how the service works using the AWS SDK and CLI. We can create topics and subscribers with the CLI, and can easily send messages with a bit of NodeJS code.

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.