SES Email Tracking

vumdao

馃殌 Vu Dao 馃殌

Posted on April 7, 2021

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鈥檚 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 馃尃

馃挅 馃挭 馃檯 馃毄
vumdao
馃殌 Vu Dao 馃殌

Posted on April 7, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

SES Email Tracking
aws SES Email Tracking

April 7, 2021