aboutsummaryrefslogtreecommitdiffstats
path: root/tools/node_modules/nodemailer/lib/engines/ses.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/nodemailer/lib/engines/ses.js')
-rw-r--r--tools/node_modules/nodemailer/lib/engines/ses.js217
1 files changed, 217 insertions, 0 deletions
diff --git a/tools/node_modules/nodemailer/lib/engines/ses.js b/tools/node_modules/nodemailer/lib/engines/ses.js
new file mode 100644
index 0000000..4766c4f
--- /dev/null
+++ b/tools/node_modules/nodemailer/lib/engines/ses.js
@@ -0,0 +1,217 @@
+/*
+ * This file is based on the original SES module for Nodemailer by dfellis
+ * https://github.com/andris9/Nodemailer/blob/11fb3ef560b87e1c25e8bc15c2179df5647ea6f5/lib/engines/SES.js
+ */
+
+// NB! Amazon SES does not allow unicode filenames on attachments!
+
+var http = require('http'),
+ https = require('https'),
+ crypto = require('crypto'),
+ urllib = require("url");
+
+// Expose to the world
+module.exports = SESTransport;
+
+/**
+ * <p>Generates a Transport object for Amazon SES</p>
+ *
+ * <p>Possible options can be the following:</p>
+ *
+ * <ul>
+ * <li><b>AWSAccessKeyID</b> - AWS access key (required)</li>
+ * <li><b>AWSSecretKey</b> - AWS secret (required)</li>
+ * <li><b>ServiceUrl</b> - optional API endpoint URL (defaults to <code>"https://email.us-east-1.amazonaws.com"</code>)
+ * </ul>
+ *
+ * @constructor
+ * @param {Object} options Options object for the SES transport
+ */
+function SESTransport(options){
+ this.options = options || {};
+
+ //Set defaults if necessary
+ this.options.ServiceUrl = this.options.ServiceUrl || "https://email.us-east-1.amazonaws.com";
+}
+
+/**
+ * <p>Compiles a mailcomposer message and forwards it to handler that sends it.</p>
+ *
+ * @param {Object} emailMessage MailComposer object
+ * @param {Function} callback Callback function to run when the sending is completed
+ */
+SESTransport.prototype.sendMail = function(emailMessage, callback) {
+
+ // SES strips this header line by itself
+ emailMessage.options.keepBcc = true;
+
+ //Check if required config settings set
+ if(!this.options.AWSAccessKeyID || !this.options.AWSSecretKey) {
+ return callback(new Error("Missing AWS Credentials"));
+ }
+
+ this.generateMessage(emailMessage, (function(err, email){
+ if(err){
+ return typeof callback == "function" && callback(err);
+ }
+ this.handleMessage(email, callback);
+ }).bind(this));
+};
+
+/**
+ * <p>Compiles and sends the request to SES with e-mail data</p>
+ *
+ * @param {String} email Compiled raw e-mail as a string
+ * @param {Function} callback Callback function to run once the message has been sent
+ */
+SESTransport.prototype.handleMessage = function(email, callback) {
+ var request,
+
+ date = new Date(),
+
+ urlparts = urllib.parse(this.options.ServiceUrl),
+
+ params = this.buildKeyValPairs({
+ 'Action': 'SendRawEmail',
+ 'RawMessage.Data': (new Buffer(email, "utf-8")).toString('base64'),
+ 'Version': '2010-12-01',
+ 'Timestamp': this.ISODateString(date)
+ }),
+
+ reqObj = {
+ host: urlparts.hostname,
+ path: urlparts.path || "/",
+ method: "POST",
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Content-Length': params.length,
+ 'Date': date.toUTCString(),
+ 'X-Amzn-Authorization':
+ ['AWS3-HTTPS AWSAccessKeyID='+this.options.AWSAccessKeyID,
+ "Signature="+this.buildSignature(date.toUTCString(), this.options.AWSSecretKey),
+ "Algorithm=HmacSHA256"].join(",")
+ }
+ };
+
+ //Execute the request on the correct protocol
+ if(urlparts.protocol.substr() == "https:") {
+ request = https.request(reqObj, this.responseHandler.bind(this, callback));
+ } else {
+ request = http.request(reqObj, this.responseHandler.bind(this, callback));
+ }
+ request.end(params);
+};
+
+/**
+ * <p>Handles the response for the HTTP request to SES</p>
+ *
+ * @param {Function} callback Callback function to run on end (binded)
+ * @param {Object} response HTTP Response object
+ */
+SESTransport.prototype.responseHandler = function(callback, response) {
+ var body = "";
+ response.setEncoding('utf8');
+
+ //Re-assembles response data
+ response.on('data', function(d) {
+ body += d.toString();
+ });
+
+ //Performs error handling and executes callback, if it exists
+ response.on('end', function(err) {
+ if(err instanceof Error) {
+ return typeof callback == "function" && callback(err, null);
+ }
+ if(response.statusCode != 200) {
+ return typeof callback == "function" &&
+ callback(new Error('Email failed: ' + response.statusCode + '\n' + body), null);
+ }
+ return typeof callback == "function" && callback(null, {
+ message: body
+ });
+ });
+};
+
+/**
+ * <p>Compiles the messagecomposer object to a string.</p>
+ *
+ * <p>It really sucks but I don't know a good way to stream a POST request with
+ * unknown legth, so the message needs to be fully composed as a string.</p>
+ *
+ * @param {Object} emailMessage MailComposer object
+ * @param {Function} callback Callback function to run once the message has been compiled
+ */
+
+SESTransport.prototype.generateMessage = function(emailMessage, callback) {
+ var email = "";
+
+ emailMessage.on("data", function(chunk){
+ email += (chunk || "").toString("utf-8");
+ });
+
+ emailMessage.on("end", function(chunk){
+ email += (chunk || "").toString("utf-8");
+ callback(null, email);
+ });
+
+ emailMessage.streamMessage();
+};
+
+/**
+ * <p>Converts an object into a Array with "key=value" values</p>
+ *
+ * @param {Object} config Object with keys and values
+ * @return {Array} Array of key-value pairs
+ */
+SESTransport.prototype.buildKeyValPairs = function(config){
+ var keys = Object.keys(config).sort(),
+ keyValPairs = [],
+ key, i, len;
+
+ for(i=0, len = keys.length; i < len; i++) {
+ key = keys[i];
+ if(key != "ServiceUrl") {
+ keyValPairs.push((encodeURIComponent(key) + "=" + encodeURIComponent(config[key])));
+ }
+ }
+
+ return keyValPairs.join("&");
+};
+
+/**
+ * <p>Uses SHA-256 HMAC with AWS key on date string to generate a signature</p>
+ *
+ * @param {String} date ISO UTC date string
+ * @param {String} AWSSecretKey ASW secret key
+ */
+SESTransport.prototype.buildSignature = function(date, AWSSecretKey) {
+ var sha256 = crypto.createHmac('sha256', AWSSecretKey);
+ sha256.update(date);
+ return sha256.digest('base64');
+};
+
+/**
+ * <p>Generates an UTC string in the format of YYY-MM-DDTHH:MM:SSZ</p>
+ *
+ * @param {Date} d Date object
+ * @return {String} Date string
+ */
+SESTransport.prototype.ISODateString = function(d){
+ return d.getUTCFullYear() + '-' +
+ this.strPad(d.getUTCMonth()+1) + '-' +
+ this.strPad(d.getUTCDate()) + 'T' +
+ this.strPad(d.getUTCHours()) + ':' +
+ this.strPad(d.getUTCMinutes()) + ':' +
+ this.strPad(d.getUTCSeconds()) + 'Z';
+};
+
+/**
+ * <p>Simple padding function. If the number is below 10, add a zero</p>
+ *
+ * @param {Number} n Number to pad with 0
+ * @return {String} 0 padded number
+ */
+SESTransport.prototype.strPad = function(n){
+ return n<10 ? '0'+n : n;
+};
+