Permalink
Browse files

Fully functional SES engine, and new example for configuring it.

  • Loading branch information...
1 parent cf9ffc2 commit 11fb3ef560b87e1c25e8bc15c2179df5647ea6f5 @dfellis dfellis committed Aug 12, 2011
Showing with 181 additions and 32 deletions.
  1. +70 −0 examples/example_ses.js
  2. +74 −0 examples/example_smtp.js
  3. +37 −32 lib/engines/SES.js
View
@@ -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
@@ -0,0 +1,74 @@
+var nodemailer = require('../lib/mail');
+
+// Set up SMTP server settings
+nodemailer.SMTP = {
+ host: 'smtp.gmail.com',
+ port: 465,
+ use_authentication: true,
+ ssl: true,
+ user: undefined,
+ pass: undefined,
+ debug: true
+}
+console.log('SMTP Configured')
+// unique cid value for the embedded image
+var cid = Date.now() + '.image.png';
+
+// Message object
+var message = {
+ sender: 'Sender Name <from@example.com>',
+ to: '"Receiver Name" <to@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
@@ -20,38 +20,34 @@ function getHostname(url) {
//Custom keyValPair construction that ignores "special" config keys
function buildKeyValPairs(config) {
+ var keys = Object.keys(config).sort();
var keyValPairs = [];
- for(var key in config) {
- if(key != "ServiceUrl" && key != "AWSSecretKey") {
- keyValPairs.push((encodeURIComponent(key) + "=" + encodeURIComponent(config[key])));
+ for(var k in keys) {
+ if(keys[k] != "ServiceUrl") {
+ keyValPairs.push((encodeURIComponent(keys[k]) + "=" + encodeURIComponent(config[keys[k]])));
}
}
return keyValPairs.join("&");
}
-//Following the SES.pm signature implementation since Amazon's documentation sucks
-function buildV2Signature(config) {
- var sha256 = crypto.createHash('sha256', config.AWSSecretKey);
- sha256.update(
- "GET\n" +
- getHostname(config.ServiceUrl) +
- "\n/\n" +
- buildKeyValPairs(config)
- );
+//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 = "";
- console.log(response);
+ response.setEncoding('utf8');
//Re-assembles response data
response.on('data', function(d) {
- body += d;
+ body += d.toString();
});
//Performs error handling and executes callback, if it exists
- response.on('close', function(err) {
+ response.on('end', function(err) {
if(err instanceof Error) {
return callback && callback(err, null);
}
@@ -67,35 +63,44 @@ function buildResponseHandler(callback) {
//Constructs the email to be send and sends it to Amazon SES
exports.send = function(emailMessage, config, callback) {
var email = "";
- var path = "/?";
- var hostname = "";
+ 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";
- config.Timestamp = config.Timestamp || ISODateString(new Date());
//Build Email
emailMessage.prepareVariables();
email = emailMessage.generateHeaders() + "\r\n\r\n" + emailMessage.generateBody();
- //Unchangeable configuration settings for SES
- delete config.instanceId;
- config.Version = '2010-12-01';
- config.SignatureVersion = '2';
- config.SignatureMethod = 'HmacSHA256';
- config.Action = 'SendRawEmail';
- config['RawMessage.Data'] = (new Buffer(email)).toString('base64');
- config.Signature = buildV2Signature(config);
//Construct the http/https request object
- path += buildKeyValPairs(config);
- hostname = getHostname(config.ServiceUrl);
- var reqObj = {hostname: hostname, path: path};
- console.log(reqObj);
+ 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)) {
- https.get(reqObj, buildResponseHandler(callback));
+ request = https.request(reqObj, buildResponseHandler(callback));
} else {
- http.get(reqObj, buildResponseHandler(callback));
+ request = http.request(reqObj, buildResponseHandler(callback));
}
+ request.end(params);
};

0 comments on commit 11fb3ef

Please sign in to comment.