diff --git a/.travis.yml b/.travis.yml index 85977b5..df370cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,5 +2,3 @@ language: node_js node_js: - '4.1' - '4.0' -- '0.12' -- '0.10' diff --git a/CHANGELOG.md b/CHANGELOG.md index c65333b..fe5bb0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- Populate node-sparkpost's stackIdentity option + +### Updated +- Updated to `sparkpost@2.0.1`. ## [1.1.0] - 2016/11/10 ### Added diff --git a/examples/sendmail.js b/examples/sendmail.js index 87c8fea..4e03722 100644 --- a/examples/sendmail.js +++ b/examples/sendmail.js @@ -1,17 +1,17 @@ 'use strict'; /* eslint-disable no-console */ -var nodemailer = require('nodemailer') - , sparkPostTransport = require('nodemailer-sparkpost-transport') - , transporter = nodemailer.createTransport(sparkPostTransport({ - 'sparkPostApiKey': '', - 'options': { - 'open_tracking': true, - 'click_tracking': true, - 'transactional': true - }, - 'campaign_id': 'Nodemailer Demo' - })); +const nodemailer = require('nodemailer'); +const sparkPostTransport = require('nodemailer-sparkpost-transport'); +const transporter = nodemailer.createTransport(sparkPostTransport({ + 'sparkPostApiKey': '', + 'options': { + 'open_tracking': true, + 'click_tracking': true, + 'transactional': true + }, + 'campaign_id': 'Nodemailer Demo' +})); transporter.sendMail({ from: 'me@example.com', diff --git a/lib/sparkPostTransport.js b/lib/sparkPostTransport.js index e96197a..fe68460 100644 --- a/lib/sparkPostTransport.js +++ b/lib/sparkPostTransport.js @@ -1,12 +1,12 @@ 'use strict'; // Dependencies -var pkg = require('../package') - , SparkPost = require('sparkpost'); +const pkg = require('../package'); +const SparkPost = require('sparkpost'); // Constructor function SparkPostTransport(options) { - var opt; + let opt; // Set required properties this.name = 'SparkPost'; @@ -15,7 +15,9 @@ function SparkPostTransport(options) { // Set the SparkPost API Key (must have appropriate Transmission resource permissions) this.sparkPostApiKey = process.env.SPARKPOST_API_KEY || options.sparkPostApiKey; - this.sparkPostEmailClient = new SparkPost(this.sparkPostApiKey); + this.sparkPostEmailClient = new SparkPost(this.sparkPostApiKey, { + stackIdentity: `nodemailer-sparkpost-transport/${this.version}` + }); // Set any options which are valid for (opt in options) { @@ -26,8 +28,8 @@ function SparkPostTransport(options) { } function populateCustomFields(message, defaults, request) { - var data = message.data - , customFields = ['campaign_id', 'metadata', 'substitution_data', 'options', 'content', 'recipients']; + const data = message.data; + const customFields = ['campaign_id', 'metadata', 'substitution_data', 'options', 'content', 'recipients']; // Apply default SP-centric options and override if provided in mail object customFields.forEach(function(fld) { @@ -53,13 +55,10 @@ function populateFrom(inreq, outreq) { } function populateInlineStdFields(message, resolveme, request) { - var data = message.data; + const data = message.data; populateFrom(data, request); - // cc - // bcc - if (data.subject) { request.content.subject = data.subject; } @@ -76,19 +75,31 @@ function populateInlineStdFields(message, resolveme, request) { // headers } +function populateRecipients(request, msgData) { + if (msgData.to) { + request.recipients = emailList(msgData.to) || []; + } + + if (msgData.cc) { + request.cc = emailList(msgData.cc); + } + + if (msgData.bcc) { + request.bcc = emailList(msgData.bcc); + } +} + SparkPostTransport.prototype.send = function send(message, callback) { - var data = message.data - , request = { - content: {} - } - , resolveme = {}; + const data = message.data; + const request = { + content: {} + }; + const resolveme = {}; // Conventional nodemailer fields override SparkPost-specific ones and defaults populateCustomFields(message, this, request); - if (data.to) { - request.recipients = emailList(data.to) || []; - } + populateRecipients(request, data); if (data.raw) { resolveme.raw = 'email_rfc822'; @@ -100,17 +111,15 @@ SparkPostTransport.prototype.send = function send(message, callback) { }; SparkPostTransport.prototype.resolveAndSend = function(mail, toresolve, request, callback) { - var self = this - , keys = Object.keys(toresolve) - , srckey - , dstkey; + const self = this; + const keys = Object.keys(toresolve); if (keys.length === 0) { return this.sendWithSparkPost(request, callback); } - srckey = keys[0]; - dstkey = toresolve[keys[0]]; + const srckey = keys[0]; + const dstkey = toresolve[keys[0]]; delete toresolve[srckey]; @@ -121,7 +130,7 @@ SparkPostTransport.prototype.resolveAndSend = function(mail, toresolve, request, }; SparkPostTransport.prototype.loadContent = function(mail, key, callback) { - var content = mail.data[key]; + const content = mail.data[key]; if (typeof content === 'string') { return process.nextTick(function() { callback(null, content); @@ -136,22 +145,22 @@ SparkPostTransport.prototype.loadContent = function(mail, key, callback) { }; SparkPostTransport.prototype.sendWithSparkPost = function(transBody, callback) { - this.sparkPostEmailClient.transmissions.send({transmissionBody: transBody}, function(err, res) { + this.sparkPostEmailClient.transmissions.send(transBody, function(err, res) { if (err) { return callback(err); } // Example successful Sparkpost transmission response: // { "results": { "total_rejected_recipients": 0, "total_accepted_recipients": 1, "id": "66123596945797072" } } return callback(null, { - messageId: res.body.results.id, - accepted: res.body.results.total_accepted_recipients, - rejected: res.body.results.total_rejected_recipients + messageId: res.results.id, + accepted: res.results.total_accepted_recipients, + rejected: res.results.total_rejected_recipients }); }); }; function emailList(strOrLst) { - var lst = strOrLst; + let lst = strOrLst; if (typeof strOrLst === 'string') { lst = strOrLst.split(','); } @@ -171,3 +180,4 @@ function emailList(strOrLst) { module.exports = function(options) { return new SparkPostTransport(options); }; + diff --git a/package.json b/package.json index d57eb03..20b719f 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/SparkPost/nodemailer-sparkpost-transport", "dependencies": { - "sparkpost": "^1.3.8" + "sparkpost": "^2.1.0" }, "devDependencies": { "chai": "^3.5.0", diff --git a/test/sparkpostTransport.js b/test/sparkpostTransport.js index 02e5d2f..2833cac 100644 --- a/test/sparkpostTransport.js +++ b/test/sparkpostTransport.js @@ -1,13 +1,13 @@ 'use strict'; -var sinon = require('sinon') - , expect = require('chai').expect - , nodemailer = require('nodemailer') - , sparkPostTransport = require('../lib/sparkPostTransport.js') - , pkg = require('../package.json'); +const sinon = require('sinon'); +const expect = require('chai').expect; +const nodemailer = require('nodemailer'); +const sparkPostTransport = require('../lib/sparkPostTransport.js'); +const pkg = require('../package.json'); describe('SparkPost Transport', function() { - var transport = sparkPostTransport({sparkPostApiKey: '12345678901234567890'}); + const transport = sparkPostTransport({sparkPostApiKey: '12345678901234567890'}); it('should have a name and version property', function(done) { expect(transport).to.have.property('name', 'SparkPost'); @@ -22,7 +22,7 @@ describe('SparkPost Transport', function() { }); it('should be able to set options', function(done) { - var transport = sparkPostTransport({ + const transport = sparkPostTransport({ sparkPostApiKey: '12345678901234567890', campaign_id: 'sample_campaign', tags: ['new-account-notification'], @@ -51,34 +51,35 @@ describe('Send Method', function() { describe('SP-centric mail structure', function() { it('should be able to overload options at the transmission', function(done) { // Create the default transport - var transport = sparkPostTransport({ - sparkPostApiKey: '12345678901234567890', - campaign_id: 'sample_campaign', - tags: ['new-account-notification'], - metadata: {'source': 'event'}, - substitution_data: {'salutatory': 'Welcome to SparkPost!'}, - options: {'click_tracking': true, 'open_tracking': true}, - content: {'template_id': 'newAccountNotification'}, - recipients: [{'email': 'john.doe@example.com', 'name': 'John Doe'}] - }) + const transport = sparkPostTransport({ + sparkPostApiKey: '12345678901234567890', + campaign_id: 'sample_campaign', + tags: ['new-account-notification'], + metadata: {'source': 'event'}, + substitution_data: {'salutatory': 'Welcome to SparkPost!'}, + options: {'click_tracking': true, 'open_tracking': true}, + content: {'template_id': 'newAccountNotification'}, + recipients: [{'email': 'john.doe@example.com', 'name': 'John Doe'}] + }); + // Create the modified options for use with the above stub test - , overloadedTransmission = { - campaign_id: 'another_sample_campaign', - tags: ['alternative-tag'], - metadata: {'changedKey': 'value'}, - substitution_data: {'salutatory': 'And now...for something completely different'}, - options: {'click_tracking': false, 'open_tracking': false, 'transactional': true}, - recipients: [{ - list_id: 'myStoredRecipientTestList' - }], - content: { - template_id: 'someOtherTemplate' - } - }; + const overloadedTransmission = { + campaign_id: 'another_sample_campaign', + tags: ['alternative-tag'], + metadata: {'changedKey': 'value'}, + substitution_data: {'salutatory': 'And now...for something completely different'}, + options: {'click_tracking': false, 'open_tracking': false, 'transactional': true}, + recipients: [{ + list_id: 'myStoredRecipientTestList' + }], + content: { + template_id: 'someOtherTemplate' + } + }; // Stub the send method of the SDK out sinon.stub(transport, 'send', function(data, resolve) { - // Grab the transmissionBody from the send() payload for assertions + // Grab the transmission body from the send() payload for assertions expect(data.campaign_id).to.equal('another_sample_campaign'); expect(data.tags).to.deep.equal(['alternative-tag']); expect(data.metadata).to.deep.equal({'changedKey': 'value'}); @@ -110,22 +111,23 @@ describe('Send Method', function() { }); describe('conventional nodemailer mail structure', function() { - var sptrans + let sptrans , transport , mail , rcp1 , rcp2; - function checkTo(done) { - var req = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0] - , transBody = req.transmissionBody; + function checkRecipientsFromFld(mail, infld, val, outfld, done) { + mail[infld] = val; + transport.sendMail(mail, function() { + const transBody = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0]; - expect(req).to.have.keys('transmissionBody'); - expect(transBody).to.have.keys(['recipients', 'content']); - expect(transBody.recipients).to.have.length(2); - expect(transBody.recipients[0]).to.deep.equal({ address: rcp1 }); - expect(transBody.recipients[1]).to.deep.equal({ address: rcp2 }); - done(); + expect(transBody).to.include.keys(['recipients', 'content']); + expect(transBody[outfld]).to.have.length(2); + expect(transBody[outfld][0]).to.deep.equal({ address: rcp1 }); + expect(transBody[outfld][1]).to.deep.equal({ address: rcp2 }); + done(); + }); } beforeEach(function() { @@ -157,10 +159,8 @@ describe('Send Method', function() { it('should accept basic nodemailer mail content fields', function(done) { transport.sendMail(mail, function() { - var req = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0] - , transBody = req.transmissionBody; + const transBody = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0]; - expect(req).to.have.keys('transmissionBody'); expect(transBody).to.have.keys(['recipients', 'content']); expect(transBody.content.html).to.equal(mail.html); expect(transBody.content.text).to.equal(mail.text); @@ -181,10 +181,8 @@ describe('Send Method', function() { delete mail.from; mail.raw = 'rawmsg'; transport.sendMail(mail, function() { - var req = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0] - , transBody = req.transmissionBody; + const transBody = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0]; - expect(req).to.have.keys('transmissionBody'); expect(transBody).to.have.keys(['recipients', 'content']); expect(transBody.content).to.have.keys('email_rfc822'); expect(transBody.recipients).to.have.length(1); @@ -198,7 +196,7 @@ describe('Send Method', function() { it('should accept from as a string', function(done) { mail.from = 'me@here.com'; transport.sendMail(mail, function() { - var trans = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0].transmissionBody; + const trans = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0]; expect(trans.content.from).to.be.a('string'); done(); }); @@ -211,7 +209,7 @@ describe('Send Method', function() { }; transport.sendMail(mail, function() { - var trans = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0].transmissionBody; + const trans = sptrans.sparkPostEmailClient.transmissions.send.firstCall.args[0]; expect(trans.content.from).to.be.an('object'); expect(trans.content.from).to.have.property('name'); expect(trans.content.from.name).to.equal(mail.from.name); @@ -222,17 +220,27 @@ describe('Send Method', function() { }); it('should accept to as an array', function(done) { - mail.to = [rcp1, rcp2]; - transport.sendMail(mail, function() { - checkTo(done); - }); + checkRecipientsFromFld(mail, 'to', [rcp1, rcp2], 'recipients', done); }); it('should accept to as a string', function(done) { - mail.to = [rcp1, rcp2].join(','); - transport.sendMail(mail, function() { - checkTo(done); - }); + checkRecipientsFromFld(mail, 'to', [rcp1, rcp2].join(','), 'recipients', done); + }); + + it('should accept cc as an array', function(done) { + checkRecipientsFromFld(mail, 'cc', [rcp1, rcp2], 'cc', done); + }); + + it('should accept cc as a string', function(done) { + checkRecipientsFromFld(mail, 'cc', [rcp1, rcp2].join(','), 'cc', done); + }); + + it('should accept bcc as an array', function(done) { + checkRecipientsFromFld(mail, 'bcc', [rcp1, rcp2], 'bcc', done); + }); + + it('should accept bcc as a string', function(done) { + checkRecipientsFromFld(mail, 'bcc', [rcp1, rcp2].join(','), 'bcc', done); }); }); });