Last active
November 14, 2020 15:24
-
-
Save OssiPesonen/d4a20114106fedca1a6171df5d5f75a3 to your computer and use it in GitHub Desktop.
Lambda SES bounce event handler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const AWS = require('aws-sdk'); | |
const _ = require('lodash'); | |
const successResponse = message => { | |
return { | |
statusCode: 200, | |
body: JSON.stringify({ | |
message: message | |
}) | |
} | |
}; | |
/** | |
* Deliver given message to DLQ | |
* | |
* @param sqs | |
* @param message | |
* @returns {Promise<void>} | |
*/ | |
async function sendMessageToDLQ (sqs, message) { | |
await sqs.sendMessage({ MessageBody: message, QueueUrl: process.env.DLQ_URL }).promise(); | |
} | |
/** | |
* Process bounced messages | |
* | |
* @param event SNS notification event | |
* @return {object} Success response object | |
*/ | |
exports.handler = async (event) => { | |
const sns = new AWS.SNS({ region: process.env.REGION }); | |
const sqs = new AWS.SQS({ region: process.env.REGION }); | |
if (_.get(event, 'Records', null)) { | |
for (const property in event.Records) { | |
const record = event.Records[ property ]; | |
const notification = JSON.parse(record.Sns.Message); | |
// Make sure notification type is Bounce | |
if (notification.notificationType === 'Bounce') { | |
const headers = _.get(notification, 'mail.headers', null); | |
if (!headers) { | |
// SES has a configuration error, handle failure | |
await sendMessageToDLQ(sqs, record.Sns.Message); | |
return successResponse('Original message headers missing'); | |
} | |
const snsTargetArn = notification.mail.headers.find((header) => header.name === 'X-BOUNCE-SNS-TARGET-ARN'); | |
if (!snsTargetArn) { | |
// Client did not provide the TargetArn, handle failure | |
await sendMessageToDLQ(sqs, record.Sns.Message); | |
return successResponse('Missing TargetArn header'); | |
} | |
let bouncedRecipients = []; | |
// Add all bounced recipients to message | |
if (_.get(notification, 'bounce.bouncedRecipients', false)) { | |
notification.bounce.bouncedRecipients.forEach(function (value) { | |
bouncedRecipients.push({ emailAddress: value.emailAddress }); | |
}); | |
} | |
// Build the message | |
const message = JSON.stringify({ | |
messageId: notification.mail.messageId, | |
bounceType: notification.bounce.bounceType, | |
bounceSubType: notification.bounce.bounceSubType, | |
timestamp: notification.bounce.timestamp, | |
bouncedRecipients: bouncedRecipients | |
}); | |
// Processed, publish | |
await sns.publish({ | |
MessageAttributes: { | |
'OriginalMessageId': { | |
DataType: 'String', | |
StringValue: bounce.messageId | |
} | |
}, | |
Subject: 'Here is a bounced email notification', | |
Message: message, | |
TargetArn: snsTargetArn.value | |
}).promise(); | |
} | |
else { | |
// Not a bounce message. Deliver to DLQ. | |
await sendMessageToDLQ(sqs, record.Sns.Message); | |
return successResponse('Not a bounce message'); | |
} | |
} | |
} | |
return successResponse('ok'); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment