DEV Community

Cover image for SES Email Tracking
🚀 Vu Dao 🚀
🚀 Vu Dao 🚀

Posted on

5 2

SES Email Tracking

SES Email Tracking

1. Email tracking gives us the power to build and maintain relationships in this exceedingly crowded, competitive inbox environment And tracking bounced emails, this will be useful for us to track our bounce rate, and monitor our future campaigns in order to get the lowest bounce rate possible and have your emails correctly delivered.

2. Definition and causes of bounces: A bounce (or bounced email) refers to the situation where your email is rejected by your subscriber's email server.

  • Soft bounce: This is a temporary issue. The reasons are the following:
    • Your recipients' mailbox and/or your own inbox are full
    • Your email message is too large and too heavy
    • Your recipients' email server is down or offline
    • A connection timeout occurred when Gmail tried to deliver your email
  • Hard bounce: This is a permanent issue. The reasons are the following:
    • Your recipients' email address does not exist (anymore)
    • The domains do not exist (anymore)
    • Your recipients' email server has completely blocked email deliveries

What’s In This Document


🚀 Setup Amazon SES to send detailed notifications about your bounces, complaints, and deliveries

Alt-Text

🚀 Create the SNS to send message to lambda function

Alt-Text

🚀 Create lambda function which store SES notification to Dynamodb

'use strict';
console.log('Loading function');

let doc = require('dynamodb-doc');
let dynamo = new doc.DynamoDB();
let tableName = 'ses-mailing';

exports.handler = (event, context, callback) => {
    //console.log('Received event:', JSON.stringify(event, null, 2));
    const message = JSON.parse(event.Records[0].Sns.Message);

    var eventType = message.eventType;
    if (eventType == undefined) {
        eventType = message.notificationType;
    }
    switch(eventType) {
        case "Bounce":
            handleBounce(message);
            break;
        case "Complaint":
            handleComplaint(message);
            break;
        case "Send":
            handleDelivery(message);
            break;
        case "Delivery":
            handleDelivery(message);
            break;

        case "Open":
            handleOpen(message);
            break;

        default:
            callback("Unknown notification type: " + message.notificationType);
    }
};

function handleBounce(message) {
    const messageId = message.mail.messageId;
    const addresses = message.bounce.bouncedRecipients.map(function(recipient){
        return recipient.emailAddress;
    });
    const bounceType = message.bounce.bounceType;

    console.log("Message " + messageId + " bounced when sending to " + addresses.join(", ") + ". Bounce type: " + bounceType);

    for (var i=0; i<addresses.length; i++){
        writeDDB(addresses[i], message, tableName, "disable");
    }
}

function handleComplaint(message) {
    const messageId = message.mail.messageId;
    const addresses = message.complaint.complainedRecipients.map(function(recipient){
        return recipient.emailAddress;
    });

    console.log("A complaint was reported by " + addresses.join(", ") + " for message " + messageId + ".");

    for (var i=0; i<addresses.length; i++){
        writeDDB(addresses[i], message, tableName, "disable");
    }
}

function handleDelivery(message) {
    const messageId = message.mail.messageId;
    const deliveryTimestamp = message.mail.timestamp;
    const addresses = message.mail.destination;
    console.log("Message " + messageId + " was delivered successfully at " + deliveryTimestamp + ".");

    for (var i=0; i<addresses.length; i++){
        writeDDB(addresses[i], message, tableName, "enable");
    }
}
function handleOpen(message) {
    const messageId = message.mail.messageId;
    const deliveryTimestamp = message.open.timestamp;
    const addresses = message.mail.destination;
    console.log("Message " + messageId + " was opened at " + deliveryTimestamp + ".");

    for (var i=0; i<addresses.length; i++){
        writeDDB(addresses[i], message, tableName, "enable");
    }
}

function writeDDB(id, payload, tableName, status) {
    const tags = payload.mail.tags;
    var configuration_set = null;
    var source_ip = null;
    var from_domain = null;
    var tenant = null;

    if (tags != undefined ) {
        console.log('Received tags:', JSON.stringify(tags, null, 2));
        if ('ses:configuration-set' in tags) {
            configuration_set = tags['ses:configuration-set'].join(',');
        }
        if ('ses:source-ip' in tags) {
            source_ip = tags['ses:source-ip'].join(',');
        }
        if ('ses:from-domain' in tags) {
            from_domain = tags['ses:from-domain'].join(',');
        }
        if ('tenant' in tags) {
            tenant = tags['tenant'].join(',');
        }

    }

    var eventType = payload.eventType;
    if (eventType == undefined) {
        eventType = payload.notificationType;
    }

    const item = {
            UserId: id,
            eventType: eventType,
            from: payload.mail.source,
            messageId: payload.mail.messageId,
            timestamp: payload.mail.timestamp,
            state: status,
            configuration_set: configuration_set,
            source_ip: source_ip,
            from_domain: from_domain,
            tenant: tenant
        };
    const params = {
            TableName:tableName,
            Item: item
        };
    dynamo.putItem(params,function(err,data){
            if (err) console.log(err);
            else console.log(data);
    });
}
Enter fullscreen mode Exit fullscreen mode

DDB Result - Partition key| Sort key | Global secondary indexes
Alt-text
Alt-text

Query Bounce Email By Using AWS CLI

1. Use dynamodb query

aws --region=us-east-1 dynamodb query --select ALL_ATTRIBUTES --table-name ses-mailing --index-name eventType-timestamp-index --key-condition-expression "eventType = :e and #timestamp >= :t" --expression-attribute-names '{ "#timestamp": "timestamp"}' --expression-attribute-values  '{":e":{"S":"Bounce"}, ":t": {"S": "2021-04-04"}}' > mail-bounce.json
cat mail-bounce.json | jq  -r '.Items[] | [.from.S, .UserId.S, .timestamp.S] | @csv ' > mail-bounce.csv
Enter fullscreen mode Exit fullscreen mode

2. Use dynamodb execute-statement

aws dynamodb execute-statement --statement "SELECT * FROM \"ses-mailing\".\"eventType-timestamp-index\" WHERE \"eventType\" = 'Bounce' AND \"timestamp\" >= '2021-04-05'" --region us-east-1 > ses.json
cat ses.json | jq -r '.Items[] | [([.UserId.S, .from.S, .timestamp.S] | join(","))] | @csv' | sort -r > bounce.list
Enter fullscreen mode Exit fullscreen mode

Refs


🌠 Blog · Github · Web · Linkedin · Group · Page · Twitter 🌠

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs