diff --git a/index.js b/index.js index 5f0f5fe..0a6814c 100644 --- a/index.js +++ b/index.js @@ -24,6 +24,8 @@ console.log("AWS Lambda SES Forwarder // @arithmetric // Version 5.0.0"); // `example+test@example.com` would be treated as if it was sent to // `example@example.com`. // +// - rejectSpam: Rejects any emails that fail the SES spam checks. +// // - forwardMapping: Object where the key is the lowercase email address from // which to forward and the value is an array of email addresses to which to // send the message. @@ -41,6 +43,7 @@ var defaultConfig = { emailBucket: "s3-bucket-name", emailKeyPrefix: "emailsPrefix/", allowPlusSign: true, + rejectSpam: false, forwardMapping: { "info@example.com": [ "example.john@example.com", @@ -85,6 +88,36 @@ exports.parseEvent = function(data) { return Promise.resolve(data); }; +/** + * Filters out SPAM emails + * + * @param {object} data - Data bundle with context, email, etc. + * + * @return {object} - Promise resolved with data. + */ +exports.filterSpam = function(data) { + const receipt = data.event.Records[0].ses.receipt; + if (data.config.rejectSpam && receipt) { + const verdicts = [ + 'spamVerdict', + 'virusVerdict', + 'spfVerdict', + 'dkimVerdict', + 'dmarcVerdict' + ]; + for (let key of verdicts) { + const verdict = receipt[key]; + if (verdict && verdict.status === 'FAIL') { + return Promise.reject( + new Error('Error: Email failed spam filter: ' + key) + ); + } + } + } + + return Promise.resolve(data); +}; + /** * Transforms the original recipients to the desired forwarded destinations. * @@ -340,6 +373,7 @@ exports.handler = function(event, context, callback, overrides) { var steps = overrides && overrides.steps ? overrides.steps : [ exports.parseEvent, + exports.filterSpam, exports.transformRecipients, exports.fetchMessage, exports.processMessage, diff --git a/test/filterSpam.js b/test/filterSpam.js new file mode 100644 index 0000000..b6ccb87 --- /dev/null +++ b/test/filterSpam.js @@ -0,0 +1,120 @@ + +/* global describe, it */ + +var assert = require("assert"); +var fs = require("fs"); + +var index = require("../index"); + +describe('index.js', function() { + describe('#filterSpam()', function() { + it('skip if not configured', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {} + }; + index.filterSpam(data) + .then(function() { + assert.ok(true, "filterSpam returned successfully"); + done(); + }); + }); + + it('skip if filtering disabled', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {rejectSpam: false} + }; + index.filterSpam(data) + .then(function() { + assert.ok(true, "filterSpam returned successfully"); + done(); + }); + }); + + it('allow good message through', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {rejectSpam: true} + }; + index.filterSpam(data) + .then(function() { + assert.ok(true, "filterSpam returned successfully"); + done(); + }); + }); + + it('should reject spam messages', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {rejectSpam: true} + }; + data.event.Records[0].ses.receipt.spamVerdict.status = "FAIL"; + index.filterSpam(data) + .catch(function(err) { + assert.ok(err, "Error: Email failed spam filter: spamVerdict"); + done(); + }); + }); + + it('should reject messages that might have a virus', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {rejectSpam: true} + }; + data.event.Records[0].ses.receipt.virusVerdict.status = "FAIL"; + index.filterSpam(data) + .catch(function(err) { + assert.ok(err, "Error: Email failed spam filter: virusVerdict"); + done(); + }); + }); + + it('should reject messages that fail a DKIM check', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {rejectSpam: true} + }; + data.event.Records[0].ses.receipt.dkimVerdict.status = "FAIL"; + index.filterSpam(data) + .catch(function(err) { + assert.ok(err, "Error: Email failed spam filter: dkimVerdict"); + done(); + }); + }); + + it('should reject messages that fail a SPF check', + function(done) { + var data = { + event: JSON.parse(fs.readFileSync("test/assets/event.json")), + log: console.log, + context: {}, + config: {rejectSpam: true} + }; + data.event.Records[0].ses.receipt.spfVerdict.status = "FAIL"; + index.filterSpam(data) + .catch(function(err) { + assert.ok(err, "Error: Email failed spam filter: spfVerdict"); + done(); + }); + }); + }); +});