Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Amazon SES Engine support and example #38

Merged
merged 5 commits into from
Aug 12, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions examples/example_ses.js
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 1 addition & 1 deletion examples/example.js → examples/example_smtp.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:[
{
Expand Down
106 changes: 106 additions & 0 deletions lib/engines/SES.js
Original file line number Diff line number Diff line change
@@ -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);
};