Amazon Announces Simple Notification Service (SNS)

Introducing SNS

Today Amazon announced a new service offering, Simple Notification Service, or SNS. This service allows users to send out Notifications to subscribers in one of three ways:
  • Email
  • SQS
  • HTTP

First of all, this already is quite appealing to most users since it replaces the need to have an external mail relay for sending any sort of emails out of the cloud. As we all know most amazon servers are already blacklisted from spam filters so you previously had to use an external service such as Gmail or AuthSMTP to send out any sort of emails from within the cloud.

Secondly, this system actually uses a subscription based service, instead of simply blasting out notifications to whoever you tell it to. Yes, it requires you to use your AWS access keys to sign someone up, but they have to approve it (if it's email) before you can send them something. This means that not only does it detract spam, but it also allows your users to decide if they want to receive your messages or not.

Additionally the system offers an easy way to allow users to unsubscribe. It adds a simple unsubscribe link to the bottom of every email, following the CAN-SPAM act's Unsubscribe Policy.

Using the new SNS module in boto

Just like with any other boto module, you'll start by connecting to SNS:

>>> import boto
>>> sns = boto.connect_sns()

Creating a topic

Next, we'll create a new Topic.

>>> t = sns.create_topic("Test")
>>> t
{u'CreateTopicResponse': {u'ResponseMetadata': {u'RequestId': u''}, u'CreateTopicResult': {u'TopicArn': u'arn:aws:sns:us-east-1:your-account-id:Test'}}}

Note the "TopicArn" here because you'll need to use that later to subscribe to this topic. If you forget it or lose it you can always use the get_all_topics function to find it.

>>> sns.get_all_topics()
{u'ListTopicsResponse': {u'ResponseMetadata': {u'RequestId': u''}, u'ListTopicsResult': {u'Topics': [{u'TopicArn': u'arn:aws:sns:us-east-1:your-account-id:Test'}], u'NextToken': None}}}

Subscribing to the Topic

Now a topic isn't very good without anyone subscribing to it, so lets subscribe ourselves to this topic via email.

>>> sns.subscribe("arn:aws:sns:us-east-1:your-account-id:Test", "email", "your-email")
{u'SubscribeResponse': {u'SubscribeResult': {u'SubscriptionArn': u'pending confirmation'}, u'ResponseMetadata': {u'RequestId': u'your-request-id'}}}

Notice here that your subscription is in a state "pending confirmation." This is because SNS follows the subscription rules for the CAN-SPAM act, so you'll need to check your email for something from the service and click the link there. Once you click this link you'll be presented with a page that gives you a link to unsubscribe if you wish, and verifies the topic that you just subscribed to. Now lets go back to our code and make sure that we did indeed subscribe properly.

>>> sns.get_all_subscriptions_by_topic("arn:aws:sns:us-east-1:your-account-id:Test")
{u'ListSubscriptionsResponse': {u'ListSubscriptionsResult': {u'NextToken': None, u'Subscriptions': [{u'Owner': u'your-account-id', u'Endpoint': u'your-email', u'Protocol': u'email', u'TopicArn': u'arn:aws:sns:us-east-1:your-account-id:Test', u'SubscriptionArn': u'arn:aws:sns:us-east-1:your-account-id1:Test:subscription-id'}]}, u'ResponseMetadata': {u'RequestId': u'request-id'}}}

Pushing a message

Now, lets publish a message to this topic.

>>> sns.publish("arn:aws:sns:us-east-1:your-account-id:Test", "Test Message body", "Test Message subject")
{u'PublishResponse': {u'PublishResult': {u'MessageId': u'message-id'}, u'ResponseMetadata': {u'RequestId': u'request-id'}}}

Note that this simple case doesn't really make much sense to us since it's only to one subscriber, but immagine a system where you had to have thousands of subscribers. This type of system would allow you to "Fire and Forget" that the notification was going out at all. I'll be working on adding support for a simple command line interface that lets you send notifications automatically from a pyami instance.

Cleaning up

Lastly, lets remove our testing topic and subscriptions. Unsubscribing can happen in one of two ways:
  1. User clicks the unsubscribe link in any email they received
  2. You manually remove them

Since the first option is relatively easy, lets take a look at how to remove a user manually. This is done using the unsubscribe function, which takes the subscription ID. In case you forgot this ID, you can use the get_all_subscriptions_by_topic function to get them all again.

>>> sns.get_all_subscriptions_by_topic("arn:aws:sns:us-east-1::Test"){u'ListSubscriptionsResponse': {u'ListSubscriptionsResult': {u'NextToken': None, u'Subscriptions': [{u'Owner': u'your-account-id', u'Endpoint': u'your-email', u'Protocol': u'email', u'TopicArn': u'arn:aws:sns:us-east-1:your-account-id:Test', u'SubscriptionArn': u'subscription-arn'}]}, u'ResponseMetadata': {u'RequestId': u'request-id'}}}
>>> sns.unsubscribe("subscription-arn")

Make sure you copy in your full subscription arn, not just the subscription ID.
Lastly, we'll remove the topic from our SNS

>>> sns.delete_topic("topic-arn")

That's it! Happy Notifying!


Ovais Reza said…
Where to get SNS module, its not there and svn. repository seems to be empty, where to get the code?

Unknown said…
SNS is available in the boto repository in SVN trunk only, it should be available in the next release but for now you can check it out and install it via the instructions here:
Unknown said…
boto-2.0a2 does not have "boto.sns" in its packages list and so that does not get included in the egg upon install.
GJB said…
Thanks Chris. I am struggling to set up SNS in a different region than the default. I think it should be something like sns = boto.sns.SNSConnection(region="X") -- but I can't find an X that works for US west (or I am on the wrong track altogether). Appreciate any advice you can offer.