From 3dd37d8e6750dc1cc55f0073ee2cd25ccecee87e Mon Sep 17 00:00:00 2001 From: Geoffroy Lesage Date: Wed, 5 Oct 2016 22:11:43 -0500 Subject: [PATCH 1/4] Upgrade to new Sendgrid NodeJS 4.x (including support for categories) --- README.md | 13 +- examples/simple.js | 13 +- package.json | 57 ++++---- src/sendgrid-transport.js | 240 +++++++++++++------------------- test/sendgrid-transport-test.js | 18 +-- 5 files changed, 140 insertions(+), 201 deletions(-) diff --git a/README.md b/README.md index 397c79e..25f3f00 100644 --- a/README.md +++ b/README.md @@ -28,16 +28,6 @@ var options = { api_key: 'SENDGRID_APIKEY' } } - -// or - -// username + password -var options = { - auth: { - api_user: 'SENDGRID_USERNAME', - api_key: 'SENDGRID_PASSWORD' - } -} var mailer = nodemailer.createTransport(sgTransport(options)); ``` @@ -52,7 +42,8 @@ var email = { from: 'roger@tacos.com', subject: 'Hi there', text: 'Awesome sauce', - html: 'Awesome sauce' + html: 'Awesome sauce', + categories: ['Welcome Email', 'Receipt Email'] }; mailer.sendMail(email, function(err, res) { diff --git a/examples/simple.js b/examples/simple.js index d705398..5b07205 100644 --- a/examples/simple.js +++ b/examples/simple.js @@ -3,8 +3,7 @@ var sgTransport = require('../src/sendgrid-transport.js'); var options = { auth: { - api_user: process.env['SENDGRID_USERNAME'], - api_key: process.env['SENDGRID_PASSWORD'] + api_key: process.env['SENDGRID_API_KEY'] } } @@ -16,17 +15,15 @@ var email = { subject: 'Hi there', text: 'Awesome sauce', html: 'Awesome sauce', - attachments: [ - { + attachments: [{ filename: 'test.txt', path: __dirname + '/test.txt' - } - ] + }] }; mailer.sendMail(email, function(err, res) { - if (err) { - console.log(err) + if (err) { + console.log(err) } console.log(res); }); diff --git a/package.json b/package.json index 013844d..ea1a951 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,31 @@ { - "name": "nodemailer-sendgrid-transport", - "version": "0.2.0", - "description": "SendGrid transport for Nodemailer", - "main": "src/sendgrid-transport.js", - "scripts": { - "test": "mocha" - }, - "repository": { - "type": "git", - "url": "git://github.com/sendgrid/nodemailer-sendgrid-transport.git" - }, - "keywords": [ - "Nodemailer", - "SendGrid" - ], - "author": "SendGrid (sendgrid.com)", - "contributors": [ - "Eddie Zaneski " - ], - "license": "MIT", - "dependencies": { - "sendgrid": "^1.8.0" - }, - "devDependencies": { - "chai": "^1.9.1", - "mocha": "^1.20.1" - } + "name": "nodemailer-sendgrid-transport", + "version": "0.3.0", + "description": "SendGrid transport for Nodemailer", + "main": "src/sendgrid-transport.js", + "scripts": { + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git://github.com/sendgrid/nodemailer-sendgrid-transport.git" + }, + "keywords": [ + "Nodemailer", + "SendGrid" + ], + "author": "SendGrid (sendgrid.com)", + "contributors": [ + "Eddie Zaneski ", + "Geoffroy Lesage " + ], + "license": "MIT", + "dependencies": { + "sendgrid": "4.5.0" + }, + "devDependencies": { + "chai": "^1.9.1", + "mocha": "^1.20.1" + } } diff --git a/src/sendgrid-transport.js b/src/sendgrid-transport.js index 4a29255..432a1e4 100644 --- a/src/sendgrid-transport.js +++ b/src/sendgrid-transport.js @@ -1,169 +1,123 @@ 'use strict'; -var SendGrid = require('sendgrid'); var packageData = require('../package.json'); module.exports = function(options) { - return new SendGridTransport(options); + return new SendGridTransport(options); }; function SendGridTransport(options) { - options = options || {}; - - this.options = options; - this.name = 'SendGrid'; - this.version = packageData.version; - - if (!this.options.auth.api_user) { - // api key - this.sendgrid = SendGrid(this.options.auth.api_key); - } else { - // username + password - this.sendgrid = SendGrid(this.options.auth.api_user, this.options.auth.api_key); - } + options = options || {}; + + this.options = options; + this.name = 'SendGrid'; + this.version = packageData.version; + + this.sendgrid = require('sendgrid')(this.options.auth.api_key); } // if in "name" format, reformat to just address@example.com function trimReplyTo(a) { if (a.indexOf('<') >= 0 && a.indexOf('>') > 0) { - return a.substring(a.indexOf('<')+1, a.indexOf('>')); - } + return a.substring(a.indexOf('<') + 1, a.indexOf('>')); + } return a; } SendGridTransport.prototype.send = function(mail, callback) { - var email = mail.data; - - // reformat replyTo to replyto - if (email.replyTo) { - email.replyto = trimReplyTo(email.replyTo); - } - - // fetch envelope data from the message object - var addresses = mail.message.getAddresses(); - var from = [].concat(addresses.from || addresses.sender || addresses['reply-to'] || []).shift(); - var to = [].concat(addresses.to || []); - var cc = [].concat(addresses.cc || []); - var bcc = [].concat(addresses.bcc || []); - - // populate from and fromname - if (from) { - if (from.address) { - email.from = from.address; - } - - if (from.name) { - email.fromname = from.name; - } - } - - // populate to and toname arrays - email.to = to.map(function(rcpt) { - return rcpt.address || ''; - }); - - email.toname = to.map(function(rcpt) { - return rcpt.name || ''; - }); - - // populate cc and bcc arrays - email.cc = cc.map(function(rcpt) { - return rcpt.address || ''; - }); - - email.bcc = bcc.map(function(rcpt) { - return rcpt.address || ''; - }); - - // a list for processing attachments - var contents = []; - - // email.text could be a stream or a file, so store it for processing - if (email.text) { - contents.push({ - obj: email, - key: 'text' - }); - } - - // email.html could be a stream or a file, so store it for processing - if (email.html) { - contents.push({ - obj: email, - key: 'html' - }); - } - - // store attachments for processing, to fetch files, urls and streams - email.files = email.attachments; - [].concat(email.files || []).forEach(function(attachment, i) { - contents.push({ - obj: email.files, - key: i, - isAttachment: true - }); - }); - - // fetch values for text/html/attachments as strings or buffers - // this is an asynchronous action, so we'll handle it with a simple recursion - var _self = this; - var pos = 0; - var resolveContent = function() { - - // if all parts are processed, send out the e-mail - if (pos >= contents.length) { - return _self.sendgrid.send(email, function(err, json) { - callback(err, json); - }); - } + // fetch envelope data from the message object + var subject = mail.data.subject || ''; + var addresses = mail.message.getAddresses(); + var from = [].concat(addresses.from || addresses.sender || addresses['reply-to'] || []).shift(); + var to = [].concat(addresses.to || []); + var cc = [].concat(addresses.cc || []); + var bcc = [].concat(addresses.bcc || []); + var categories = [].concat(mail.data.categories || []); + + var email = { + personalizations: [], + content: [], + from: {} + }; + + // populate from and fromname + if (from) { + if (from.address) { + email.from.email = from.address; + } - // get the next element from the processing list - var file = contents[pos++]; - /* - We need to store a pointer to the original attachment object in case - resolveContent replaces it with the Stream value - */ - var prevObj = file.obj[file.key]; - // ensure the object is an actual attachment object, not a string, buffer or a stream - if (prevObj instanceof Buffer ||  typeof prevObj === 'string' || (prevObj && typeof prevObj.pipe === 'function')) { - prevObj = { - content: prevObj - }; + if (from.name) { + email.from.name = from.name; + } } - // use the helper function to convert file paths, urls and streams to strings or buffers - mail.resolveContent(file.obj, file.key, function(err, content) { - if (err) { - return callback(err); - } - - if (!file.isAttachment) { - // overwrites email.text and email.html content - file.obj[file.key] = content; - } else { - - // If the object is a String or a Buffer then it is most likely replaces by resolveContent - if (file.obj[file.key] instanceof Buffer ||  typeof file.obj[file.key] === 'string') { - file.obj[file.key] = prevObj; + // populate to and toname arrays + if (to && Array.isArray(to) && to.length > 0) { + var recipients = { + to: to.map(function(rcpt) { + return { + email: rcpt.address || '', + name: rcpt.name || '' + } + }), + subject: subject } - file.obj[file.key].content = content; - if (file.obj[file.key].path) { - if (!file.obj[file.key].filename) { - // try to detect the required filename from the path - file.obj[file.key].filename = file.obj[file.key].path.split(/[\\\/]/).pop(); - } - delete file.obj[file.key].path; + + // populate cc arrays + if (cc && Array.isArray(cc) && cc.length > 0) { + var ccs = cc.map(function(rcpt) { + if (typeof rcpt === "string") return { + email: rcpt + }; + return { + email: rcpt.address || '', + name: rcpt.name || '' + }; + }); + recipients.cc = ccs; } - // set default filename if filename and content-type are not set (allowed for Nodemailer but not for SendGrid) - if (!file.obj[file.key].filename && !file.obj[file.key].contentType) { - file.obj[file.key].filename = 'attachment-' + pos + '.bin'; + + // populate bcc arrays + if (bcc && Array.isArray(bcc) && bcc.length > 0) { + var bccs = bcc.map(function(rcpt) { + if (typeof rcpt === "string") return { + email: rcpt + }; + return { + email: rcpt.address || '', + name: rcpt.name || '' + }; + }); + recipients.bcc = bccs; } - } - resolveContent(); - }); - }; + email.personalizations.push(recipients); + } + + // populate categories + if (categories && Array.isArray(categories) && categories.length > 0) { + email.categories = categories; + } + + // populate plain text content + if (mail.data.text) { + email.content.push({ + value: mail.data.text, + type: 'text/plain' + }); + } + + // populate html content + if (mail.data.html) { + email.content.push({ + value: mail.data.html, + type: 'text/html' + }); + } - // start the recursive function - resolveContent(); + this.sendgrid.API(this.sendgrid.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: email, + }), callback); }; diff --git a/test/sendgrid-transport-test.js b/test/sendgrid-transport-test.js index a637cf0..d52c2d9 100644 --- a/test/sendgrid-transport-test.js +++ b/test/sendgrid-transport-test.js @@ -6,16 +6,12 @@ var pkg = require('../package.json'); var transport = null; describe('sendgrid-transport', function() { - it('should take an api_user and api_key', function() { - transport = sgTransport({ 'auth': { api_user: 'test', api_key: 'test' } }) - }); + it('should take an apikey', function() { + transport = sgTransport({ 'auth': { api_key: 'test' } }) + }); - it('should take an apikey', function() { - transport = sgTransport({ 'auth': { api_key: 'test' } }) - }); - - it('should have a name and version', function() { - expect(transport.name).to.eq('SendGrid') - expect(transport.version).to.eq(pkg.version) - }); + it('should have a name and version', function() { + expect(transport.name).to.eq('SendGrid') + expect(transport.version).to.eq(pkg.version) + }); }); From f5fc29bd25e5f2b0bf40c0f81e32661dccb61072 Mon Sep 17 00:00:00 2001 From: Geoffroy Lesage Date: Fri, 14 Oct 2016 09:46:50 -0500 Subject: [PATCH 2/4] set indentation to 2 spaces --- .jsbeautifyrc | 4 + package.json | 58 +++++----- src/sendgrid-transport.js | 194 ++++++++++++++++---------------- test/sendgrid-transport-test.js | 20 ++-- 4 files changed, 142 insertions(+), 134 deletions(-) create mode 100644 .jsbeautifyrc diff --git a/.jsbeautifyrc b/.jsbeautifyrc new file mode 100644 index 0000000..ed65814 --- /dev/null +++ b/.jsbeautifyrc @@ -0,0 +1,4 @@ +{ + "indent_size":2, + "indent_with_tabs":false +} \ No newline at end of file diff --git a/package.json b/package.json index ea1a951..f2bea06 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,31 @@ { - "name": "nodemailer-sendgrid-transport", - "version": "0.3.0", - "description": "SendGrid transport for Nodemailer", - "main": "src/sendgrid-transport.js", - "scripts": { - "test": "mocha" - }, - "repository": { - "type": "git", - "url": "git://github.com/sendgrid/nodemailer-sendgrid-transport.git" - }, - "keywords": [ - "Nodemailer", - "SendGrid" - ], - "author": "SendGrid (sendgrid.com)", - "contributors": [ - "Eddie Zaneski ", - "Geoffroy Lesage " - ], - "license": "MIT", - "dependencies": { - "sendgrid": "4.5.0" - }, - "devDependencies": { - "chai": "^1.9.1", - "mocha": "^1.20.1" - } + "name": "nodemailer-sendgrid-transport", + "version": "0.3.0", + "description": "SendGrid transport for Nodemailer", + "main": "src/sendgrid-transport.js", + "scripts": { + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git://github.com/sendgrid/nodemailer-sendgrid-transport.git" + }, + "keywords": [ + "Nodemailer", + "SendGrid" + ], + "author": "SendGrid (sendgrid.com)", + "contributors": [ + "Eddie Zaneski ", + "Geoffroy Lesage " + ], + "license": "MIT", + "dependencies": { + "sendgrid": "4.5.0" + }, + "devDependencies": { + "chai": "^1.9.1", + "mocha": "^1.20.1" + } } diff --git a/src/sendgrid-transport.js b/src/sendgrid-transport.js index 432a1e4..f04561f 100644 --- a/src/sendgrid-transport.js +++ b/src/sendgrid-transport.js @@ -3,121 +3,121 @@ var packageData = require('../package.json'); module.exports = function(options) { - return new SendGridTransport(options); + return new SendGridTransport(options); }; function SendGridTransport(options) { - options = options || {}; + options = options || {}; - this.options = options; - this.name = 'SendGrid'; - this.version = packageData.version; + this.options = options; + this.name = 'SendGrid'; + this.version = packageData.version; - this.sendgrid = require('sendgrid')(this.options.auth.api_key); + this.sendgrid = require('sendgrid')(this.options.auth.api_key); } // if in "name" format, reformat to just address@example.com function trimReplyTo(a) { - if (a.indexOf('<') >= 0 && a.indexOf('>') > 0) { - return a.substring(a.indexOf('<') + 1, a.indexOf('>')); - } - return a; + if (a.indexOf('<') >= 0 && a.indexOf('>') > 0) { + return a.substring(a.indexOf('<') + 1, a.indexOf('>')); + } + return a; } SendGridTransport.prototype.send = function(mail, callback) { - // fetch envelope data from the message object - var subject = mail.data.subject || ''; - var addresses = mail.message.getAddresses(); - var from = [].concat(addresses.from || addresses.sender || addresses['reply-to'] || []).shift(); - var to = [].concat(addresses.to || []); - var cc = [].concat(addresses.cc || []); - var bcc = [].concat(addresses.bcc || []); - var categories = [].concat(mail.data.categories || []); - - var email = { - personalizations: [], - content: [], - from: {} - }; - - // populate from and fromname - if (from) { - if (from.address) { - email.from.email = from.address; - } - - if (from.name) { - email.from.name = from.name; - } + // fetch envelope data from the message object + var subject = mail.data.subject || ''; + var addresses = mail.message.getAddresses(); + var from = [].concat(addresses.from || addresses.sender || addresses['reply-to'] || []).shift(); + var to = [].concat(addresses.to || []); + var cc = [].concat(addresses.cc || []); + var bcc = [].concat(addresses.bcc || []); + var categories = [].concat(mail.data.categories || []); + + var email = { + personalizations: [], + content: [], + from: {} + }; + + // populate from and fromname + if (from) { + if (from.address) { + email.from.email = from.address; } - // populate to and toname arrays - if (to && Array.isArray(to) && to.length > 0) { - var recipients = { - to: to.map(function(rcpt) { - return { - email: rcpt.address || '', - name: rcpt.name || '' - } - }), - subject: subject - } - - // populate cc arrays - if (cc && Array.isArray(cc) && cc.length > 0) { - var ccs = cc.map(function(rcpt) { - if (typeof rcpt === "string") return { - email: rcpt - }; - return { - email: rcpt.address || '', - name: rcpt.name || '' - }; - }); - recipients.cc = ccs; - } - - // populate bcc arrays - if (bcc && Array.isArray(bcc) && bcc.length > 0) { - var bccs = bcc.map(function(rcpt) { - if (typeof rcpt === "string") return { - email: rcpt - }; - return { - email: rcpt.address || '', - name: rcpt.name || '' - }; - }); - recipients.bcc = bccs; - } - - email.personalizations.push(recipients); + if (from.name) { + email.from.name = from.name; } - - // populate categories - if (categories && Array.isArray(categories) && categories.length > 0) { - email.categories = categories; + } + + // populate to and toname arrays + if (to && Array.isArray(to) && to.length > 0) { + var recipients = { + to: to.map(function(rcpt) { + return { + email: rcpt.address || '', + name: rcpt.name || '' + } + }), + subject: subject } - // populate plain text content - if (mail.data.text) { - email.content.push({ - value: mail.data.text, - type: 'text/plain' - }); + // populate cc arrays + if (cc && Array.isArray(cc) && cc.length > 0) { + var ccs = cc.map(function(rcpt) { + if (typeof rcpt === "string") return { + email: rcpt + }; + return { + email: rcpt.address || '', + name: rcpt.name || '' + }; + }); + recipients.cc = ccs; } - // populate html content - if (mail.data.html) { - email.content.push({ - value: mail.data.html, - type: 'text/html' - }); + // populate bcc arrays + if (bcc && Array.isArray(bcc) && bcc.length > 0) { + var bccs = bcc.map(function(rcpt) { + if (typeof rcpt === "string") return { + email: rcpt + }; + return { + email: rcpt.address || '', + name: rcpt.name || '' + }; + }); + recipients.bcc = bccs; } - this.sendgrid.API(this.sendgrid.emptyRequest({ - method: 'POST', - path: '/v3/mail/send', - body: email, - }), callback); -}; + email.personalizations.push(recipients); + } + + // populate categories + if (categories && Array.isArray(categories) && categories.length > 0) { + email.categories = categories; + } + + // populate plain text content + if (mail.data.text) { + email.content.push({ + value: mail.data.text, + type: 'text/plain' + }); + } + + // populate html content + if (mail.data.html) { + email.content.push({ + value: mail.data.html, + type: 'text/html' + }); + } + + this.sendgrid.API(this.sendgrid.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: email, + }), callback); +}; \ No newline at end of file diff --git a/test/sendgrid-transport-test.js b/test/sendgrid-transport-test.js index d52c2d9..aa3b1d4 100644 --- a/test/sendgrid-transport-test.js +++ b/test/sendgrid-transport-test.js @@ -6,12 +6,16 @@ var pkg = require('../package.json'); var transport = null; describe('sendgrid-transport', function() { - it('should take an apikey', function() { - transport = sgTransport({ 'auth': { api_key: 'test' } }) - }); + it('should take an apikey', function() { + transport = sgTransport({ + 'auth': { + api_key: 'test' + } + }) + }); - it('should have a name and version', function() { - expect(transport.name).to.eq('SendGrid') - expect(transport.version).to.eq(pkg.version) - }); -}); + it('should have a name and version', function() { + expect(transport.name).to.eq('SendGrid') + expect(transport.version).to.eq(pkg.version) + }); +}); \ No newline at end of file From 834ae29ebe8fd79b83fd63de264b103c045613ac Mon Sep 17 00:00:00 2001 From: Geoffroy Lesage Date: Sat, 15 Oct 2016 19:13:58 -0500 Subject: [PATCH 3/4] Updated dependency to Sendgrid 4.7.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f2bea06..637d67b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodemailer-sendgrid-transport", - "version": "0.3.0", + "version": "0.3.1", "description": "SendGrid transport for Nodemailer", "main": "src/sendgrid-transport.js", "scripts": { @@ -22,7 +22,7 @@ ], "license": "MIT", "dependencies": { - "sendgrid": "4.5.0" + "sendgrid": "4.7.0" }, "devDependencies": { "chai": "^1.9.1", From 539a222ed43b3c1694044f7c67ad09ee2213cc37 Mon Sep 17 00:00:00 2001 From: Geoffroy Lesage Date: Mon, 13 Feb 2017 20:48:33 -0600 Subject: [PATCH 4/4] Updated sendgrid-nodejs for error logging --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 637d67b..fcd78ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodemailer-sendgrid-transport", - "version": "0.3.1", + "version": "0.3.2", "description": "SendGrid transport for Nodemailer", "main": "src/sendgrid-transport.js", "scripts": { @@ -22,7 +22,7 @@ ], "license": "MIT", "dependencies": { - "sendgrid": "4.7.0" + "sendgrid": "git+https://github.com/glesage/sendgrid-nodejs.git" }, "devDependencies": { "chai": "^1.9.1",