Skip to content
Browse files

Merge pull request #38 from AGROSICA/master

Amazon SES Engine support and example
  • Loading branch information...
2 parents 9c29ca9 + b536ada commit 36f68317f4ab89528953c448fe6808d8aa516d35 @andris9 andris9 committed Aug 12, 2011
Showing with 177 additions and 1 deletion.
  1. +70 −0 examples/example_ses.js
  2. +1 −1 examples/{example.js → example_smtp.js}
  3. +106 −0 lib/engines/SES.js
View
70 examples/example_ses.js
@@ -0,0 +1,70 @@
+var nodemailer = require('../lib/mail');
+
+// Set up SES settings
+nodemailer.SES = {
+ AWSAccessKeyID: "AKIAEXAMPLE",
+ AWSSecretKey: "ZEXAMPLE"
+};
+console.log('SES Configured');
+
+// unique cid value for the embedded image
+var cid = Date.now() + '.image.png';
+
+// Message object
+var message = {
+ sender: '"Sender Name" <test@example.com>',
+ to: '"Receiver Name" <test@example.com>',
+ subject: 'Nodemailer is unicode friendly ✔',
+
+ body: 'Hello to myself!',
+ html:'<p><b>Hello</b> to myself <img src="cid:' + cid + '"/></p>',
+ debug: true,
+ attachments:[
+ {
+ filename: 'notes.txt',
+ contents: 'Some notes about this e-mail'
+ },
+ {
+ filename: 'image.png',
+ contents: new Buffer('iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/' +
+ '//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U' +
+ 'g9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC', 'base64'),
+ cid: cid
+ }
+ ]
+}
+
+// Callback to be run after the sending is completed
+var callback = function(error, success){
+ if(error){
+ console.log('Error occured');
+ console.log(error.message);
+ return;
+ }
+ if(success){
+ console.log('Message sent successfully!');
+ }else{
+ console.log('Message failed, reschedule!');
+ }
+}
+
+console.log('Sending Mail')
+
+// Catch uncaught errors
+process.on('uncaughtException', function(e){
+ console.log('Uncaught Exception', e.stack);
+});
+
+// Send the e-mail
+var mail;
+try{
+ mail = nodemailer.send_mail(message, callback);
+}catch(e) {
+ console.log('Caught Exception',e);
+}
+
+var oldemit = mail.emit;
+mail.emit = function(){
+ console.log('Mail.emit', arguments);
+ oldemit.apply(mail, arguments);
+}
View
2 examples/example.js → examples/example_smtp.js
@@ -21,7 +21,7 @@ var message = {
subject: 'Nodemailer is unicode friendly ✔',
body: 'Hello to myself!',
- html:'<p><b>Hello</b> to myself <img src="cid:"' + cid + '"/></p>',
+ html:'<p><b>Hello</b> to myself <img src="cid:' + cid + '"/></p>',
debug: true,
attachments:[
{
View
106 lib/engines/SES.js
@@ -0,0 +1,106 @@
+var http = require('http');
+var https = require('https');
+var crypto = require('crypto');
+
+//Taken shamelessly from the [MDN](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date)
+function ISODateString(d){
+ function pad(n){return n<10 ? '0'+n : n}
+ return d.getUTCFullYear()+'-'
+ + pad(d.getUTCMonth()+1)+'-'
+ + pad(d.getUTCDate())+'T'
+ + pad(d.getUTCHours())+':'
+ + pad(d.getUTCMinutes())+':'
+ + pad(d.getUTCSeconds())+'Z'
+}
+
+//Extracts the hostname from a given URL
+function getHostname(url) {
+ return url.replace(/^https?:\/\/([^\/]*).*$/, "$1");
+}
+
+//Custom keyValPair construction that ignores "special" config keys
+function buildKeyValPairs(config) {
+ var keys = Object.keys(config).sort();
+ var keyValPairs = [];
+ for(var k in keys) {
+ if(keys[k] != "ServiceUrl") {
+ keyValPairs.push((encodeURIComponent(keys[k]) + "=" + encodeURIComponent(config[keys[k]])));
+ }
+ }
+ return keyValPairs.join("&");
+}
+
+//Following signature documentation from [here](http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/index.html?HMACShaSignatures.html)
+function buildSignature(date, AWSSecretKey) {
+ var sha256 = crypto.createHmac('sha256', AWSSecretKey);
+ sha256.update(date);
+ return sha256.digest('base64');
+}
+
+//Adds the callback to the response handler's scope
+function buildResponseHandler(callback) {
+ return function(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 callback && callback(err, null);
+ }
+ if(response.statusCode != 200) {
+ return callback &&
+ callback(new Error('Email failed: ' + response.statusCode + '\n' + body), null);
+ }
+ return callback && callback(null, body);
+ });
+ };
+}
+
+//Constructs the email to be send and sends it to Amazon SES
+exports.send = function(emailMessage, config, callback) {
+ var email = "";
+ var params = "";
+ var request;
+ var date = new Date();
+ //Check if required config settings set
+ if(!config.AWSAccessKeyID || !config.AWSSecretKey) {
+ return callback(new Error("Missing AWS Credentials"));
+ }
+ //Set defaults if necessary
+ config.ServiceUrl = config.ServiceUrl || "https://email.us-east-1.amazonaws.com";
+ //Build Email
+ emailMessage.prepareVariables();
+ email = emailMessage.generateHeaders() + "\r\n\r\n" + emailMessage.generateBody();
+ //Construct the http/https request object
+ params = buildKeyValPairs({
+ Action: 'SendRawEmail',
+ 'RawMessage.Data': (new Buffer(email)).toString('base64'),
+ Version: '2010-12-01',
+ Timestamp: ISODateString(date)
+ });
+ var reqObj = {
+ host: getHostname(config.ServiceUrl),
+ path: "/",
+ method: "POST",
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Content-Length': params.length,
+ 'Date': date.toUTCString(),
+ 'X-Amzn-Authorization':
+ 'AWS3-HTTPS AWSAccessKeyID='+config.AWSAccessKeyID+
+ ",Signature="+buildSignature(date.toUTCString(), config.AWSSecretKey)+
+ ",Algorithm=HmacSHA256"
+ }
+ };
+ //Execute the request on the correct protocol
+ if(/^https:/.test(config.ServiceUrl)) {
+ request = https.request(reqObj, buildResponseHandler(callback));
+ } else {
+ request = http.request(reqObj, buildResponseHandler(callback));
+ }
+ request.end(params);
+};

0 comments on commit 36f6831

Please sign in to comment.
Something went wrong with that request. Please try again.