dwyl/sendemail

View on GitHub
lib/index.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict';

var AWS = require('aws-sdk');
var ses = new AWS.SES();
var path = require('path'); // -> resolve template files
var fs = require('fs'); // -> open template files
var Handlebars = require('handlebars'); // -> compile templates
var COMPILED_TEMPLATES = {}; // -> cache compiled templates

AWS.config.region = process.env.AWS_REGION;

/**
 * set_template_directory does exactly what its name suggests
 * @param {String} dir - the template directory
 * @returns {undefined}
 */
function set_template_directory (dir) {
  if (!dir) {
    throw new Error('Please Set a Template Directory');
  }
  fs.readdirSync(dir); // this should be sync (on startup)

  process.env.TEMPLATE_DIRECTORY = dir; // set the env var
}
set_template_directory(process.env.TEMPLATE_DIRECTORY);

/**
 * open template file sync (ONCE) and compile it!
 * @param {String} template_name - filename of template
 * @param {String} type          - the file type
 * @returns {Object}             - compiled templates
 */
function compile_template (template_name, type) {
  var filename = template_name + '.' + type;
  var template_cached = COMPILED_TEMPLATES[template_name + '.' + type];
  var compiled, template, filepath;

  // check if the template has already been opened
  if (!template_cached) {
    filepath = path.resolve(process.env.TEMPLATE_DIRECTORY, filename);
    template = fs.readFileSync(filepath, 'utf8');
    compiled = Handlebars.compile(template);
    COMPILED_TEMPLATES[template_name + '.' + type] = compiled;
  }

  return COMPILED_TEMPLATES[template_name + '.' + type];
}

function isTruthy (x) {
  return Boolean(x);
}

function destinationParams (options) {
  // see: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SES.html
  var toAddresses = options.toAddresses || [];
  var ccAddresses = options.ccAddresses || [];
  var bccAddresses = options.bccAddresses || [];

  toAddresses = toAddresses.filter(isTruthy);
  ccAddresses = ccAddresses.filter(isTruthy);
  bccAddresses = bccAddresses.filter(isTruthy);

  return { /* required */
    BccAddresses: bccAddresses,
    CcAddresses: ccAddresses,
    ToAddresses: toAddresses
  };
}

function messageParams (options) {
  var defaultCharset = 'utf8';

  return {
    /* required */
    Body: {
      /* required */
      Html: {
        Data: compile_template(options.templateName, 'html')(options.context),
        /* required */
        Charset: options.htmlCharset || defaultCharset
      },
      Text: {
        Data: compile_template(options.templateName, 'txt')(options.context),
        /* required */
        Charset: options.textCharset || defaultCharset
      }
    },
    Subject: {
      /* required */
      Data: options.subject,
      /* required */
      Charset: options.subjectCharset || defaultCharset
    }
  };
}

/**
 * sendMany function is similar to sendemail but allows more control
 * of params including multiple recipients and CC and BCC recipients
 *
 * @param {Object} options
   * @param {String[]} options.toAddresses - recipient emails addresses
   * @param {String[]} [options.ccAddresses] - cc recipient email addresses
   * @param {String[]} [options.bccAddresses] - bcc recipient email addresses
   * @param {Object} options.context - The key value pairs
   * that will be interpolated in the template
   * @param {String} [options.senderEmailAddress] - Specifies the sender
   * email address,defaults to SENDER_EMAIL_ADDRESS environment variable
   * @param {String} [options.replyToAddress] - Specifies the reply to
   * email address, defaults to SENDER_EMAIL_ADDRESS environment variable
   * @param {String} [options.htmlCharset] - charset for html email body
   * @param {String} [options.textCharset] - charset for text email body
   * @param {String} [options.subjectCharset] - charset for email subject
 * @param {Function} callback - continuation function called after
 * the email has been sent. */

function sendMany (options, callback) {
  var params;

  params = {
    Destination: destinationParams(options),
    Message: messageParams(options),
    Source: options.senderEmailAddress || process.env.SENDER_EMAIL_ADDRESS, /* required */
    ReplyToAddresses: [
      options.replyToAddress || process.env.SENDER_EMAIL_ADDRESS
    ]
  };

  ses.sendEmail(params, callback);
}

/**
 * sendemail method takes a template name and person object and uses
 * AWS SES to send the desired email.
 * @param {String} template_name - the template to use for the email
 * @param {Object} person - the object containing the details of the
 * person to whom we want to send the email. Requires both name
 * and email. if you don't *know* the name of the person, leave it
 * an empty string.
 * @param {Function} callback - continuation function called after
 * the email has been sent.
 * @returns {undefined}
 */
function sendemail (template_name, person, callback) {
  var options = {
    templateName: template_name,
    context: person,
    subject: person.subject,
    toAddresses: Array.isArray(person.email) ? person.email : [person.email],
    senderEmailAddress: person.senderEmailAddress,
    replyToAddress: person.replyToAddress,
    ccAddresses: null,
    bccAddresses: null
  };

  sendMany(options, callback);
}


module.exports.email = sendemail;
module.exports.sendMany = sendMany;
module.exports.compile_template = compile_template;
module.exports.set_template_directory = set_template_directory;