AWS Messaging & Targeting Blog
Handling Bounces and Complaints
As you may have seen in Jeff Barr’s blog post or in an announcement, HAQM Simple Email Service (HAQM SES) now provides bounce and complaint notifications via HAQM Simple Notification Service (HAQM SNS). You can refer to the HAQM SES Developer Guide or Jeff’s post to learn how to set up this feature. In this post, we will show you how you might manage your email list using the information you get in the HAQM SNS notifications.
Background
HAQM SES assigns a unique message ID to each email that you successfully submit to send. When HAQM SES receives a bounce or complaint message from an ISP, we forward the feedback message to you. The format of bounce and complaint messages varies between ISPs, but HAQM SES interprets these messages and, if you choose to set up HAQM SNS topics for them, categorizes them into JSON objects.
Scenario
Let’s assume you use HAQM SES to send monthly product announcements to a list of email addresses. You store the list in a database and send one email per recipient through HAQM SES. You review bounces and complaints once each day, manually interpret the bounce messages in the incoming email, and update the list. You would like to automate this process using HAQM SNS notifications with a scheduled task.
Solution
To implement this solution, we will use separate HAQM SNS topics for bounces and complaints to isolate the notification channels from each other and manage them separately. Also, since the bounce and complaint handler will not run 24/7, we need these notifications to persist until the application processes them. HAQM SNS integrates with HAQM Simple Queue Service (HAQM SQS), which is a durable messaging technology that allows us to persist these notifications. We will configure each HAQM SNS topic to publish to separate SQS queues. When our application runs, it will process queued notifications and update the email list. We have provided sample C# code below.
Configuration
Set up the following AWS components to handle bounce notifications:
- Create an HAQM SQS queue named ses-bounces-queue.
- Create an HAQM SNS topic named ses-bounces-topic.
- Configure the HAQM SNS topic to publish to the SQS queue.
- Configure HAQM SES to publish bounce notifications using ses-bounces-topic to ses-bounces-queue.
Set up the following AWS components to handle complaint notifications:
- Create an HAQM SQS queue named ses-complaints-queue.
- Create an HAQM SNS topic named ses-complaints-topic.
- Configure the HAQM SNS topic to publish to the SQS queue.
- Configure HAQM SES to publish complaint notifications using ses-complaints-topic to ses-complaints-queue.
Ensure that IAM policies are in place so that HAQM SNS has access to publish to the appropriate SQS queues.
Bounce Processing
HAQM SES will categorize your hard bounces into two types: permanent and transient. A permanent bounce indicates that you should never send to that recipient again. A transient bounce indicates that the recipient’s ISP is not accepting messages for that particular recipient at that time and you can retry delivery in the future. The amount of time you should wait before resending to the address that generated the transient bounce depends on the transient bounce type. Certain transient bounces require manual intervention before the message can be delivered (e.g., message too large or content error). If the bounce type is undetermined, you should manually review the bounce and act accordingly.
You will need to define some classes to simplify bounce notification parsing from JSON into .NET objects. We will use the open-source JSON.NET library.
/// <summary>Represents the bounce or complaint notification stored in HAQM SQS.</summary> class HAQMSqsNotification { public string Type { get; set; } public string Message { get; set; } } /// <summary>Represents an HAQM SES bounce notification.</summary> class HAQMSesBounceNotification { public string NotificationType { get; set; } public HAQMSesBounce Bounce { get; set; } } /// <summary>Represents meta data for the bounce notification from HAQM SES.</summary> class HAQMSesBounce { public string BounceType { get; set; } public string BounceSubType { get; set; } public DateTime Timestamp { get; set; } public List<HAQMSesBouncedRecipient> BouncedRecipients { get; set; } } /// <summary>Represents the email address of recipients that bounced /// when sending from HAQM SES.</summary> class HAQMSesBouncedRecipient { public string EmailAddress { get; set; } }
Sample code to handle bounces:
/// <summary>Process bounces received from HAQM SES via HAQM SQS.</summary> /// <param name="response">The response from the HAQM SQS bounces queue /// to a ReceiveMessage request. This object contains the HAQM SES /// bounce notification.</param> private static void ProcessQueuedBounce(ReceiveMessageResponse response) { int messages = response.ReceiveMessageResult.Message.Count; if (messages > 0) { foreach (var m in response.ReceiveMessageResult.Message) { // First, convert the HAQM SNS message into a JSON object. var notification = Newtonsoft.Json.JsonConvert.DeserializeObject<HAQMSqsNotification>(m.Body); // Now access the HAQM SES bounce notification. var bounce = Newtonsoft.Json.JsonConvert.DeserializeObject<HAQMSesBounceNotification>(notification.Message); switch (bounce.Bounce.BounceType) { case "Transient": // Per our sample organizational policy, we will remove all recipients // that generate an AttachmentRejected bounce from our mailing list. // Other bounces will be reviewed manually. switch (bounce.Bounce.BounceSubType) { case "AttachmentRejected": foreach (var recipient in bounce.Bounce.BouncedRecipients) { RemoveFromMailingList(recipient.EmailAddress); } break; default: ManuallyReviewBounce(bounce); break; } break; default: // Remove all recipients that generated a permanent bounce // or an unknown bounce. foreach (var recipient in bounce.Bounce.BouncedRecipients) { RemoveFromMailingList(recipient.EmailAddress); } break; } } } }
Complaint Processing
A complaint indicates the recipient does not want the email that you sent them. When we receive a complaint, we want to remove the recipient addresses from our list. Again, define some objects to simplify parsing complaint notifications from JSON to .NET objects.
/// <summary>Represents an HAQM SES complaint notification.</summary> class HAQMSesComplaintNotification { public string NotificationType { get; set; } public HAQMSesComplaint Complaint { get; set; } } /// <summary>Represents the email address of individual recipients that complained /// to HAQM SES.</summary> class HAQMSesComplainedRecipient { public string EmailAddress { get; set; } } /// <summary>Represents meta data for the complaint notification from HAQM SES.</summary> class HAQMSesComplaint { public List<HAQMSesComplainedRecipient> ComplainedRecipients { get; set; } public DateTime Timestamp { get; set; } public string MessageId { get; set; } }
Sample code to handle complaints is:
/// <summary>Process complaints received from HAQM SES via HAQM SQS.</summary> /// <param name="response">The response from the HAQM SQS complaint queue /// to a ReceiveMessage request. This object contains the HAQM SES /// complaint notification.</param> private static void ProcessQueuedComplaint(ReceiveMessageResponse response) { int messages = response.ReceiveMessageResult.Message.Count; if (messages > 0) { foreach (var message in response.ReceiveMessageResult.Message) { // First, convert the HAQM SNS message into a JSON object. var notification = Newtonsoft.Json.JsonConvert.DeserializeObject<HAQMSqsNotification>(message.Body); // Now access the HAQM SES complaint notification. var complaint = Newtonsoft.Json.JsonConvert.DeserializeObject<HAQMSesComplaintNotification>(notification.Message); foreach (var recipient in complaint.Complaint.ComplainedRecipients) { // Remove the email address that complained from our mailing list. RemoveFromMailingList(recipient.EmailAddress); } } } }
Final Thoughts
We hope that you now have the basic information on how to use bounce and complaint notifications. For more information, please review our API reference and Developer Guide; it describes all actions, error codes and restrictions that apply to HAQM SES.
If you have comments or feedback about this feature, please post them on the HAQM SES forums. We actively monitor the forum and frequently engage with customers. Happy sending with HAQM SES!