Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

I gave that email a file attachment. Emails love file attachments

  • Loading branch information...
commit 42dc25e7179559909f87721fbe418e51196d7020 1 parent 8799d80
@partkyle partkyle authored
View
38 lib/email.js
@@ -3,6 +3,7 @@
var querystring = require('querystring');
var https = require('https');
var _ = require('underscore');
+var fs = require('fs');
var SmtpapiHeaders = require('./smtpapi_headers');
function EmailHeaders() {
@@ -24,6 +25,7 @@ function Email(params) {
replyto: '',
date: new Date(),
files: {},
+ file_data: {},
headers: new EmailHeaders()
};
@@ -76,6 +78,25 @@ Email.prototype.addFile = function(filename, filepath) {
this.files[filename] = filepath;
}
+Email.prototype.processFiles = function(callback) {
+ var self = this;
+ var attachments_count = _.size(this.files);
+ _(this.files).each(function(v, k) {
+ fs.readFile(v, function(error, data) {
+ attachments_count--;
+ if (error) {
+ return callback(false, error);
+ } else {
+ self.file_data[k] = data;
+ }
+
+ if (attachments_count == 0) {
+ callback(true);
+ }
+ });
+ });
+}
+
Email.prototype.toWebFormat = function() {
var data = {
to: this.to,
@@ -85,10 +106,7 @@ Email.prototype.toWebFormat = function() {
text: this.text,
html: this.html,
bcc: this.bcc,
- replyto: this.replyto,
- date: this.date,
- files: this.files,
- headers: this.headers
+ replyto: this.replyto
};
// there needs to be at least 1 to address.
@@ -113,6 +131,14 @@ Email.prototype.toSmtpFormat = function() {
}
};
+ if (_.size(this.file_data) > 0) {
+ var attachments = [];
+ _(this.file_data).each(function(v, k) {
+ attachments.push({filename: k, contents: v});
+ });
+ data.attachments = attachments;
+ }
+
// there needs to be at least 1 to address.
// If it is missing, just copy the sender.
if (_.isEmpty(data.to)) {
@@ -122,4 +148,8 @@ Email.prototype.toSmtpFormat = function() {
return data;
}
+Email.prototype.hasFiles = function() {
+ return _(this.files).size() > 0;
+}
+
module.exports = Email;
View
132 lib/sendgrid.js
@@ -4,6 +4,9 @@ var querystring = require('querystring');
var https = require('https');
var nodemailer = require('nodemailer');
var _ = require('underscore');
+var fs = require('fs');
+var path = require('path');
+var mime = require('mime');
var Email = require('./email');
@@ -12,6 +15,8 @@ function SendGrid(credentials) {
this.api_key = credentials.api_key;
}
+var boundary = Math.random();
+
/*
* Sends an email and returns true if the
* message was sent successfully.
@@ -19,35 +24,68 @@ function SendGrid(credentials) {
* @returns {Boolean}
*/
SendGrid.prototype.send = function(email, callback) {
+ var self = this;
+
if (email.constructor !== Email) {
email = new Email(email);
}
- var post_data = this.getPostData(email);
- var options = {
- host: 'sendgrid.com',
- path: '/api/mail.send.json',
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Content-Length': post_data.length
+
+ function send_rest() {
+ var post_data;
+ var options = {
+ host: 'sendgrid.com',
+ path: '/api/mail.send.json',
+ method: 'POST',
+ };
+ if (email.hasFiles()) {
+ post_data = self.getMultipartData(email);
+ var length = 0;
+ for (var buf in post_data) {
+ length += post_data[buf].length;
+ }
+ options.headers = {
+ 'Content-Type': 'multipart/form-data; boundary=' + boundary,
+ 'Content-Length': length
+ };
+ } else {
+ post_data = self.getPostData(email);
+ options.headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Content-Length': post_data.length
+ };
}
- };
- var request = https.request(options, function(res) {
- res.setEncoding('utf8');
- res.on('data', function(chunk) {
- var json = JSON.parse(chunk);
- callback.call(null, json.message == 'success', json.errors);
+ var request = https.request(options, function(res) {
+ res.setEncoding('utf8');
+ res.on('data', function(chunk) {
+ var json = JSON.parse(chunk);
+ callback.call(null, json.message == 'success', json.errors);
+ });
});
- });
- request.write(post_data);
- request.end();
+ for (var key in post_data) {
+ request.write(post_data[key]);
+ }
+ request.end();
+ }
+
+ if (email.hasFiles()) {
+ email.processFiles(function(success, message) {
+ if (success) {
+ send_rest();
+ } else {
+ callback(false, message);
+ }
+ });
+ } else {
+ send_rest();
+ }
};
SendGrid.prototype.smtp = function(email, callback) {
var self = this;
+ // SMTP settings
nodemailer.SMTP = {
host: 'smtp.sendgrid.net',
use_authentication: true,
@@ -56,24 +94,70 @@ SendGrid.prototype.smtp = function(email, callback) {
pass: this.api_key
};
+ function send_smtp() {
+ nodemailer.send_mail(email.toSmtpFormat(), function(error, success) {
+ callback.call(self, success, error);
+ });
+ }
+
if (email.constructor !== Email) {
email = new Email(email);
}
- nodemailer.send_mail(email.toSmtpFormat(), function(error, success) {
- callback.call(self, success, error);
- });
-}
+ if (_.size(email.files) > 0) {
+ email.processFiles(function(success, message) {
+ if (success) {
+ send_smtp();
+ } else {
+ callback(false, message);
+ }
+ });
+ } else {
+ send_smtp();
+ }
+};
-SendGrid.prototype.getPostData = function(params) {
+SendGrid.prototype.getPostData = function(email) {
var data = {
api_user: this.api_user,
api_key: this.api_key
}
- _.extend(data, params.toWebFormat());
+
+ _.extend(data, email.toWebFormat());
return querystring.stringify(data);
};
-module.exports = SendGrid;
+SendGrid.prototype.getMultipartData = function(email) {
+ var data = [];
+ data.push(new Buffer(encodeField(boundary, 'api_user', this.api_user)));
+ data.push(new Buffer(encodeField(boundary, 'api_key', this.api_key)));
+
+ _(email.toWebFormat()).each(function(v, k) {
+ data.push(new Buffer(encodeField(boundary, k, v)));
+ });
+
+ _(email.files).each(function(filepath, filename) {
+ data.push(encodeFile(boundary, mime.lookup(filepath), 'files[' + filename + ']', path.basename(filepath)));
+ data.push(new Buffer(email.file_data[filename]));
+ data.push(new Buffer('\r\n'));
+ });
+
+ return data;
+};
+
+function encodeField(boundary,name,value) {
+ var return_part = "--" + boundary + "\r\n";
+ return_part += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n";
+ return_part += value + "\r\n";
+ return return_part;
+}
+
+function encodeFile(boundary,type,name,filename) {
+ var return_part = "--" + boundary + "\r\n";
+ return_part += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n";
+ return_part += "Content-Type: " + type + "\r\n";
+ return return_part;
+}
+module.exports = SendGrid;
View
4 package.json
@@ -12,7 +12,9 @@
},
"dependencies": {
"underscore": ">=1.2.4",
- "nodemailer": "*"
+ "nodemailer": "*",
+ "mime": "*",
+ "restler": "*"
},
"devDependencies": {
"mocha": ">= 0.9.0",
View
BIN  test/assets/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
1  test/assets/secret.txt
@@ -0,0 +1 @@
+this is a secret. shhhhhhhh.
View
50 test/integration/attachments.test.js
@@ -0,0 +1,50 @@
+var SendGrid = require('../../lib/sendgrid');
+var Email = require('../../lib/Email');
+
+var credentials = {
+ api_user: 'kylep',
+ api_key: 'testing'
+}
+
+describe('attachments', function(){
+ var sendgrid;
+ beforeEach(function() {
+ sendgrid = new SendGrid(credentials);
+ });
+
+ it('should be able to send files via web', function(done) {
+ var mail = new Email({
+ to: 'kyle.partridge@sendgrid.com',
+ from: 'david.tomberlin@sendgrid.com',
+ subject: '(Web) File attachments',
+ text: 'test of files',
+ files: {
+ 'Logo.png': __dirname + '/../assets/logo.png',
+ 'Secret.txt': __dirname + '/../assets/secret.txt'
+ }
+ });
+
+ sendgrid.send(mail, function(success, message) {
+ if (!success) assert.ok(false, message);
+ done();
+ });
+ });
+
+ it('should be able to send files via Smtp', function(done) {
+ var mail = new Email({
+ to: 'kyle.partridge@sendgrid.com',
+ from: 'david.tomberlin@sendgrid.com',
+ subject: '(Smtp) File attachments',
+ text: 'test of files',
+ files: {
+ 'Logo.png': __dirname + '/../assets/logo.png',
+ 'Secret.txt': __dirname + '/../assets/secret.txt'
+ }
+ });
+
+ sendgrid.smtp(mail, function(success, message) {
+ if (!success) assert.ok(false, message);
+ done();
+ });
+ });
+});
View
1  test/lib/email.test.js
@@ -1,4 +1,5 @@
var Email = require('../../lib/email');
+var querystring = require('querystring')
var text_params = {
to: 'david.tomberlin@sendgrid.com',
View
2  test/lib/sendgrid.test.js
@@ -3,7 +3,7 @@ var Email = require('../../lib/email');
var credentials = {
api_user: 'kylep',
- api_key: 'nope'
+ api_key: 'testing'
}
var text_params = {
Please sign in to comment.
Something went wrong with that request. Please try again.