Amazon SES - Handling Bounces and Complaints.

Reading Time : ~ .

Why do we go for Bounce and Complaint Handling while sending mails?

In general while sending emails, we will prepare some recipient addresses as our mailing list, which are valid and our recipients want and expect our mail. But some times, some emails which are invalid will bounce, and if valid recipients do not want your mail, they may mark your email as spam in their email client. High bounce and complaint rates put your account at risk of being shut down. So in order to avoid such problem we'll handle the bounces and complaints and will remove those emails for not sending any mails further.

Flow of Bounce and Complaint handling in AWS using SNS:

In order to handle bounces and notifications AWS provides a service called SNS(Simple Notification Service). Using this feature we can handle bounces or complaints by configuring an webhook end point or email or using amazon's SQS service. As Django developers we'll try to know of  how to handle bouce or complaints using webhooks in the current blog post. For this we'll use amazon's boto package as development API.

1. First we need  to create an SNS Topic. An SNS Topic is a communication channel to send messages and subscribe to notifications. It provides an access point for publishers and subscribers to communicate with each other. The following code snippet will create an SNS Topic called 'bounce-complaint-topic'. 

import boto
sns_conn = boto.sns.connect_to_region(region_name, aws_access_key_id="*********", aws_secret_access_key="*********")
topic_obj = sns_conn.create_topic('bounce-complaint-topic')

The success response of creating  the topic will be as following.

       {u'ResponseMetadata':{u'RequestId': u'42b46710-degf-52e6-7d86-2ahc8e1c738c'}, 
        u'CreateTopicResult':{u'TopicArn': u'arn:aws:sns:eu-west-1:467741034465:bounce-complaint-topic'}

Here in the above result the topic-arn is some what different to what we had created, it is formed with the combination of region-name, customer account number and topic-name.

2. After creating  the topic we'll now create a subscription request. To receive messages published to a topic, we have to subscribe an endpoint to that topic. An endpoint can be a mobile app, web server, email address, or an Amazon SQS queue that can receive notification messages from Amazon SNS. Once you subscribe an endpoint to a topic and the subscription is confirmed, the endpoint will receive all messages published to that topic. As web developers we will use web server webhook or URL as an endpoint. With the following code snippet we'll create a subscription.

bounce_sub = sns_conn.subscribe(topic_arn_name, 'webserver protocol', 'endpoint')
Ex: bounce_sub = sns_conn.subscribe('arn:aws:sns:eu-west-1:467741034465:bounce-complaint-topic', 'http', '')

After successful creation of the  subscription request we'll receive some json data in the post request to the url that we configured for our notifications to confirm the subscription. We'll confirm the subscription by just calling the url in the json response with built-in python libraries. 

The sample JSON response will be as following.

  "Type" : "SubscriptionConfirmation",
  "MessageId" : "***********************",
  "Token" :"*******************************",
  "TopicArn" : "arn:aws:sns:eu-west-1:467741034465:bounce-complaint-topic",
  "Message" : "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:467741034465:bounce-complaint-topic.\nTo confirm the subscription, visit the SubscribeURL included in this message.",
  "SubscribeURL" : "*******",
  "Timestamp" : "2015-08-12T07:05:43.614Z",
  "SignatureVersion" : "1",
  "Signature" : "**********************",
  "SigningCertURL" : "************.pem"

We'll just open the  "SubscribeURL" to confirm the subscritpion.

js = json.loads(json_body.replace('\n', ''))
if js["Type"] == "SubscriptionConfirmation":
     subscribe_url = js["SubscribeURL"]

3. After confirming the subscription we'll now set the notifications types that will be published to the specified Amazon SNS topic, which was set to the webserver url.

conn = ses.connect_to_region(region_name, aws_access_key_id="******", aws_secret_access_key="******")
bounce_notif = conn.set_identity_notification_topic("email", "Bounce", "topic_arn")
complaint_notif = conn.set_identity_notification_topic("email", "Complaint", "topic_arn")

On setting the notifications, we'll receive a success JSON response to the webserver URL.

Successful Bounce Notification Subscription JSON response:

  "Type" : "Notification",
  "MessageId" : "****************",
  "TopicArn" : "aws:sns:eu-west-1:467741034465:bounce-complaint-topic",
  "Message" : "{\"notificationType\":\"AmazonSnsSubscriptionSucceeded\",\"message\":\"You have successfully subscribed your Amazon SNS topic 'aws:sns:eu-west-1:467741034465:bounce-complaint-topic' to receive 'Bounce' notifications from Amazon SES for identity ''.\"}\n",
  "Timestamp" : "2015-08-12T07:05:45.919Z",
  "SignatureVersion" : "1",
  "Signature" : "***********************",
  "SigningCertURL" : "*****.pem",
  "UnsubscribeURL" : "*********"
Successful  Complaint Notification Subscription JSON response:
  "Type" : "Notification",
  "MessageId" : "**********",
  "TopicArn" : "aws:sns:eu-west-1:467741034465:bounce-complaint-topic",
  "Message" : "{\"notificationType\":\"AmazonSnsSubscriptionSucceeded\",\"message\":\"You have successfully subscribed your Amazon SNS topic 'aws:sns:eu-west-1:467741034465:bounce-complaint-topic' to receive 'Complaint' notifications from Amazon SES for identity ''.\"}\n",
  "Timestamp" : "2015-08-12T07:05:46.338Z",
  "SignatureVersion" : "1",
  "Signature" : "***********",
  "SigningCertURL" : "",
  "UnsubscribeURL" : "******"

To unsubscribe to the notifications we can just open the "UnsubscribeURL" that is coming in the response. By this the process of setting our webserver url to the amazon SNS is completed. 

From now we'll receive bounce or complaint notifications to the webserver url that we configured.

"Bounce" Notification:

  "Type" : "Notification",
  "MessageId" : "***********",
  "TopicArn" : "arn:aws:sns:eu-west-1:********:bounce-complaint-topic",
  "Message" : "{\"notificationType\":\"Bounce\",\"bounce\":{\"bounceSubType\":\"General\",\"bounceType\":\"Permanent\",\"reportingMTA\":\"dsn;\",\"bouncedRecipients\":[{\"action\":\"failed\",\"emailAddress\":\"\",\"status\":\"5.1.1\",\"diagnosticCode\":\"smtp; 550 5.1.1 user unknown\"}],\"timestamp\":\"2015-08-12T07:58:38.130Z\",\"feedbackId\":\"0000014f20eb07dc-58484953-f5d7-4809-800f-ccdfd7041fe4-000000\"},\"mail\":{\"timestamp\":\"2015-08-12T07:58:37.000Z\",\"sourceArn\":\"arn:aws:ses:eu-west-1:********:identity/\",\"source\":\"\",\"messageId\":\"0000014f20eb0414-99d976eb-f1c6-47af-94b2-b68be09b931e-000000\",\"destination\":[\"\"],\"sendingAccountId\":\"********\"}}",
  "Timestamp" : "2015-08-12T07:58:38.175Z",
  "SignatureVersion" : "1",
  "Signature" : "*****************",
  "SigningCertURL" : "",
  "UnsubscribeURL" : "********:bounce-complaint-topic:*****"

"Complaint" Notification:
  "Type" : "Notification",
  "MessageId" : "***********",
  "TopicArn" : "arn:aws:sns:eu-west-1:********:bounce-complaint-topic",
  "Message" : "{\"notificationType\":\"Complaint\",\"complaint\":{\"complainedRecipients\":[{\"emailAddress\":\"\"}],\"complaintFeedbackType\":\"abuse\",\"userAgent\":\"Amazon SES Mailbox Simulator\",\"timestamp\":\"2015-08-12T07:58:39.000Z\",\"feedbackId\":\"**************\"},\"mail\":{\"timestamp\":\"2015-08-12T07:58:37.000Z\",\"sendingAccountId\":\"***********\",\"source\":\"\",\"messageId\":\"************\",\"destination\":[\"\"],\"sourceArn\":\"arn:aws:ses:eu-west-1:********:identity/\"}}",
  "Timestamp" : "2015-08-12T07:58:40.545Z",
  "SignatureVersion" : "1",
  "Signature" : "****************",
  "SigningCertURL" : "*******.pem",
  "UnsubscribeURL" : "********:bounce-complaint-topic:****"

We can get the corresponding bounce/ complaint emails from above JSON responses and stop them to not to send emails from next time.

    By Posted On

Need any Help in your Project?Let's Talk

Latest Comments
Related Articles
how to setup custom domain for amazon cloudfront Ashwin Kumar

We all want our own domain name to be setup for cloud front instead of amazon default cloud front domain name. We need two things ...

Continue Reading...
Using AWS Lambda with S3 and DynamoDB Dinesh Deshmukh

AWS lambda is handy tool for event driven computation, here we will learn how to configure and setup lambda function so to run our function ...

Continue Reading...
Configuring and Testing Load Balancer in AWS EC2 Jagadeesh V

When You have an application that is serving Huge Customer Base, so will be your Traffic. Sometimes The Application simply stops responding. We can use ...

Continue Reading...

Subscribe To our news letter

Subscribe to our news letter to receive latest blog posts into your inbox. Please fill your email address in the below form.
*We don't provide your email contact details to any third parties