From b636670aa56d235ac36683df78d73bc09c3fc1a8 Mon Sep 17 00:00:00 2001 From: Ross Biro Date: Tue, 9 Oct 2018 11:25:18 -0400 Subject: [PATCH 1/2] Added code to use an smtp server instead of SES. --------- BEGIN META VARIABLES -------- Project : Task : Done : --------- END META VARIABLES -------- --- index.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 9afefca..2205267 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,12 @@ console.log("AWS Lambda SES Forwarder // @arithmetric // Version 3.1.0"); // name part of an email address before the "at" symbol (i.e. `@example.com`). // The key must be lowercase. var defaultConfig = { + // Uncomment this if you want to use smtp instead of SES + //smtp_info: { + // region: "aws-region", + // // The aws secret contains the + // secretName: "name of aws secret", + //}, fromEmail: "noreply@example.com", subjectPrefix: "", emailBucket: "s3-bucket-name", @@ -226,6 +232,78 @@ exports.processMessage = function(data, next) { next(null, data); }; +/** + * Send email using an SMTP Server drop in replacement for ses.sendRawMessage + * more or less. + * + * @param {object} config - The config object to get the smtp info out of. + * @param {object} params - params includes destination, source, and raw message + * @param {function} callback - Callback function invoked as (error, data). + */ +exports.sendSMTPEmail = function (config, params, callback) { + var secretsmanager = new AWS.SecretsManager({region: config.smtp_info.region }); + secretsmanager.getSecretValue({SecretId: config.smtp_info.secretName}, + function(err, data) { + if (err) { + callback(err, null); + } else if (! ('SecretString' in data )) { + console.log({ level: 'debug', message: 'no secret string.'}); + callback(new Error('No Secret String'), null); + } else { + var smtp_info = JSON.parse(data.SecretString); + + console.log({level: 'debug', message:'host=' + smtp_info.server + + ' port=' + smtp_info.port + + ' username=' + smtp_info.username}); + + var smtp_client = require('smtp-client'); + var mail_client = new smtp_client.SMTPClient({ + host: smtp_info.server, + port: parseInt(smtp_info.port, 10), + secure: true, + timeout: 60000 + }); + + var done = false; + var sendit = async function(smtp_info, params) { + await mail_client.connect(); + //await mail_client.secure({timeout: 30000}); + // runs EHLO command or HELO as a fallback + await mail_client.greet({hostname: smtp_info.server}); + // authenticates a user + await mail_client.authPlain({username: smtp_info.username, + password: smtp_info.password}); + // runs MAIL FROM command + await mail_client.mail({from: params.Source}); + // runs RCPT TO command (run this multiple times to add more recii) + console.log({level: 'debug', message: 'Destinations = ' + params.Destinations}); + if (! params.Destinations instanceof Array) { + params.Destinations = [ params.Destinations]; + } + for (var i = 0; i < params.Destinations.length; i++) { + var email = params.Destinations[i]; + console.log({level: 'debug', message:'did to: ' + email}); + await mail_client.rcpt({to: email}); + } + + // runs DATA command and streams email source + await mail_client.data(params.RawMessage.Data); + // runs QUIT command + await mail_client.quit(); + }; + sendit(smtp_info, params).catch(function(err) { + done = true; + console.log({level: 'error', message: 'send smtp ' + err + " " + err.stack}); + callback(err, null); + }).then(function(response) { + if (!done) { + callback(null, response); + } + }); + } + }); +}; + /** * Send email using the SES sendRawEmail command. * @@ -243,7 +321,7 @@ exports.sendMessage = function(data, next) { data.log({level: "info", message: "sendMessage: Sending email via SES. " + "Original recipients: " + data.originalRecipients.join(", ") + ". Transformed recipients: " + data.recipients.join(", ") + "."}); - data.ses.sendRawEmail(params, function(err, result) { + data.ses.sendRawEmail(data.config, params, function(err, result) { if (err) { data.log({level: "error", message: "sendRawEmail() returned error.", error: err, stack: err.stack}); @@ -291,9 +369,18 @@ exports.handler = function(event, context, overrides) { context: context, config: overrides && overrides.config ? overrides.config : defaultConfig, log: overrides && overrides.log ? overrides.log : console.log, - ses: overrides && overrides.ses ? overrides.ses : new AWS.SES(), s3: overrides && overrides.s3 ? overrides.s3 : new AWS.S3() }; + data['ses'] = overrides && overrides.ses ? overrides.ses : ( + 'smtp_info' in data ['config'] ? { + sendRawEmail: function(config, params, callback) { + exports.sendSMTPEmail(config, params, callback); + } + } : { + sendRawEmail: function(config, params, callback) { + new AWS.SES().sendRawEmail(params, callback); + }}); + var nextStep = function(err, data) { if (err) { data.log({level: "error", message: "Step (index " + (currentStep - 1) + From 5a471ce66ba4b8449b7499846ee4ac21134e027d Mon Sep 17 00:00:00 2001 From: Ross Biro Date: Tue, 9 Oct 2018 11:29:23 -0400 Subject: [PATCH 2/2] Added comments to explain what the AWS secret should look like. --------- BEGIN META VARIABLES -------- Project : Task : Done : --------- END META VARIABLES -------- --- index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 2205267..125b029 100644 --- a/index.js +++ b/index.js @@ -22,8 +22,16 @@ var defaultConfig = { // Uncomment this if you want to use smtp instead of SES //smtp_info: { // region: "aws-region", - // // The aws secret contains the + // // The aws secret contains the + // // smtp server info. // secretName: "name of aws secret", + // // The AWS Secret should look like. + // // { + // // "server": "smtp.server", + // // "username": "username", + // // "password": "secret password", + // // "port": "port-number" + // // } //}, fromEmail: "noreply@example.com", subjectPrefix: "",