Email

The following links were used as reference for setting everything up:

The configuration for the lambda function used is as follows:

var AWS = require('aws-sdk');

var forwardFrom = '<[email protected]>';
var forwardTo = [
    {
        source: '[email protected]',
        destinations: ['[email protected]']
    },
    {
        source: '[email protected]',
        destinations: ['[email protected]']
    },
    {
        source: '[email protected]',
        destinations: ['[email protected]', '[email protected]']
    }
];

var defaultTo = '[email protected]';

exports.handler = function(event, context) {
    function fetchMessage(data) {
        return new Promise(function(resolve, reject) {
            const s3 = new AWS.S3({ signatureVersion: 'v4' });

            s3.copyObject(
                {
                    Bucket: 'emails-example.com',
                    CopySource: 'emails-example.com/' + data.mail.messageId,
                    Key: data.mail.messageId,
                    ACL: 'private',
                    ContentType: 'text/plain',
                    StorageClass: 'STANDARD'
                },
                function(err) {
                    if (err) {
                        console.error(err);

                        return reject(
                            new Error('Error: Could not make readable copy of email.')
                        );
                    }

                    // Load the raw email from S3
                    s3.getObject(
                        {
                            Bucket: 'emails-example.com',
                            Key: data.mail.messageId
                        },
                        function(err, result) {
                            if (err) {
                                console.error(err);

                                return reject(
                                    new Error('Error: Failed to load message body from S3.')
                                );
                            }

                            return resolve(result.Body.toString());
                        }
                    );
                }
            );
        });
    }

    function escapeHTML(s) {
        return s
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
    }

    async function main() {
        console.log('JSON.stringify(event)');
        console.log(JSON.stringify(event));

        var msgInfo = event.Records[0].ses;

        console.log('msgInfo', JSON.stringify(msgInfo));

        // construct "to" list
        const toList = [];

        for (const dest of msgInfo.mail.destination) {
            console.log('dest', dest);

            const filteredForwardAddresses = forwardTo.filter(
                mapping => mapping.source === dest
            );

            console.log('filteredForwardAddresses', filteredForwardAddresses);

            for (const mapping of filteredForwardAddresses) {
                console.log('mapping', mapping);

                for (const destination of mapping.destinations) {
                    console.log('destination', destination);

                    toList.push(destination);
                }
            }
        }

        console.log('toList', toList);

        if (toList.length === 0) {
            console.log('No matching forward addresses found.');
            toList.push(defaultTo);
        }

        // don't process spam messages
        if (
            msgInfo.receipt.spamVerdict.status === 'FAIL' ||
            msgInfo.receipt.virusVerdict.status === 'FAIL'
        ) {
            console.log('Message is spam or contains virus, ignoring.');
            context.succeed();
        }

        console.log('here');

        var email = await fetchMessage(msgInfo);

        console.log('Source email');
        console.log(email);

        var headers =
            'From: ' +
            msgInfo.mail.commonHeaders.returnPath +
            ' ' +
            forwardFrom +
            '\r\n';

        headers += 'Reply-To: ' + msgInfo.mail.commonHeaders.from[0] + '\r\n';

        headers += 'X-Original-To: ' + msgInfo.mail.commonHeaders.to[0] + '\r\n';

        headers += 'To: ' + toList.join(', ') + '\r\n';

        headers +=
            'Subject: ' +
            msgInfo.mail.commonHeaders.subject +
            ' -- From: ' +
            msgInfo.mail.commonHeaders.from[0] +
            '\r\n';

        if (email) {
            var res;

            res = email.match(/Content-Type:.+\s*boundary.*/);

            if (res) {
                headers += res[0] + '\r\n';
                davidwhynot;
            } else {
                res = email.match(/^Content-Type:(.*)/m);

                if (res) {
                    headers += res[0] + '\r\n';
                }
            }

            res = email.match(/^Content-Transfer-Encoding:(.*)/m);

            if (res) {
                headers += res[0] + '\r\n';
            }

            res = email.match(/^MIME-Version:(.*)/m);

            if (res) {
                headers += res[0] + '\r\n';
            }

            var splitEmail = email.split('\r\n\r\n');

            splitEmail.shift();

            console.log('JSON.stringify(splitEmail)');
            console.log(JSON.stringify(splitEmail));

            var additionalInfoText =
                'To: ' +
                msgInfo.mail.commonHeaders.to[0] +
                ' From: ' +
                msgInfo.mail.commonHeaders.from[0] +
                '\r\n';

            var additionalInfoHTML =
                '<div>To: ' +
                escapeHTML(msgInfo.mail.commonHeaders.to[0]) +
                ' From: ' +
                escapeHTML(msgInfo.mail.commonHeaders.from[0]) +
                '</div><div><br></div>\r\n';

            var matchingLinesPlain = splitEmail.filter(line =>
                line.match(/Content-Type: text\/plain/)
            );

            for (const line of matchingLinesPlain) {
                splitEmail.splice(splitEmail.indexOf(line) + 1, 0, additionalInfoText);
            }

            console.log('matchingLinesPlain', matchingLinesPlain);

            var matchingLinesHTML = splitEmail.filter(line =>
                line.match(/Content-Type: text\/html/)
            );

            console.log('matchingLinesHTML', matchingLinesPlain);

            for (const line of matchingLinesHTML) {
                splitEmail.splice(splitEmail.indexOf(line) + 1, 0, additionalInfoHTML);
            }

            console.log('JSON.stringify(splitEmail) (after join)');
            console.log(JSON.stringify(splitEmail));

            email = headers + '\r\n' + splitEmail.join('\r\n\r\n');
        } else {
            email = headers + '\r\n' + 'Empty email';
        }

        console.log('email');
        console.log(email);

        new AWS.SES().sendRawEmail(
            {
                RawMessage: { Data: email }
            },
            function(err, data) {
                if (err) context.fail(err);
                else {
                    console.log('Sent with MessageId: ' + data.MessageId);

                    context.succeed();
                }
            }
        );
    }

    main();
};