Skip to content

Commit

Permalink
Merge pull request #194 from SparkPost/cc-and-bcc
Browse files Browse the repository at this point in the history
added CC and BCC sugar
  • Loading branch information
avigoldman committed Dec 19, 2016
2 parents 0db0a1a + 4b304a7 commit d745867
Show file tree
Hide file tree
Showing 6 changed files with 367 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/resources/transmissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ This library provides easy access to the [Transmissions](https://developers.spar
* **send(transmission[, options, callback])**<br />
Sends a message by creating a new transmission
* `transmission` - an object of [transmission attributes](https://developers.sparkpost.com/api/transmissions#header-transmission-attributes)
* `transmission.cc` - Recipients to receive a carbon copy of the transmission
* `transmission.bcc` - Recipients to discreetly receive a carbon copy of the transmission
* `options.num_rcpt_errors` - maximum number of recipient errors returned

## Examples
Expand Down
59 changes: 59 additions & 0 deletions examples/transmissions/send_with_bcc_sugar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use strict';

var key = 'YOURAPIKEY'
, SparkPost = require('sparkpost')
, client = new SparkPost(key)
, transmission = {
recipients: [
{
address: {
email: 'original.recipient@example.com',
name: 'Original Recipient'
},
substitution_data: {
recipient_type: 'Original'
}
}
],
bcc: [
{
address: {
email: 'bcc.recipient@example.com',
},
substitution_data: {
recipient_type: 'BCC'
}
}
],
content: {
from: {
name: 'Node BCC Test',
email: 'from@example.com'
},
subject: 'Example email using bcc',
text: 'An example email using bcc with SparkPost to the {{recipient_type}} recipient.',
html: '<p>An example email using bcc with SparkPost to the {{recipient_type}} recipient.</p>'
}
};

// Promise
client.transmissions.send(transmission)
.then(data => {
console.log('Congrats! You sent an email with bcc using SparkPost!');
console.log(data);
})
.catch(err => {
console.log('Whoops! Something went wrong');
console.log(err);
});

// Callback
client.transmissions.send(transmission, function(err, data) {
if (err) {
console.log('Whoops! Something went wrong');
console.log(err);
} else {
console.log('Congrats! You sent an email with bcc using SparkPost!');
console.log(data);
}
});
2 changes: 1 addition & 1 deletion examples/transmissions/send_with_cc.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ client.transmissions.send(transmission, function(err, data) {
console.log('Congrats! You sent an email with cc using SparkPost!');
console.log(data);
}
});
});
60 changes: 60 additions & 0 deletions examples/transmissions/send_with_cc_sugar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use strict';

var key = 'YOURAPIKEY'
, SparkPost = require('sparkpost')
, client = new SparkPost(key)
, transmission = {
recipients: [
{
address: {
email: 'original.recipient@example.com',
name: 'Original Recipient'
},
substitution_data: {
recipient_type: 'Original'
}
},
],
cc: [
{
address: {
email: 'cc.recipient@example.com',
name: 'Carbon Copy Recipient',
},
substitution_data: {
recipient_type: 'CC'
}
}
],
content: {
from: {
name: 'Node CC Test',
email: 'from@example.com'
},
subject: 'Example email using cc',
text: 'An example email using cc with SparkPost to the {{recipient_type}} recipient.',
html: '<p>An example email using cc with SparkPost to the {{recipient_type}} recipient.</p>'
}
};

// Promise
client.transmissions.send(transmission)
.then(data => {
console.log('Congrats! You sent an email with cc using SparkPost!');
console.log(data);
})
.catch(err => {
console.log('Whoops! Something went wrong');
console.log(err);
});

// Callback
client.transmissions.send(transmission, function(err, data) {
if (err) {
console.log('Whoops! Something went wrong');
console.log(err);
} else {
console.log('Congrats! You sent an email with cc using SparkPost!');
console.log(data);
}
});
96 changes: 95 additions & 1 deletion lib/transmissions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const _ = require('lodash');
const api = 'transmissions';
const Promise = require('./Promise');

Expand Down Expand Up @@ -59,7 +60,6 @@ module.exports = function(client) {
* @returns {Promise}
*/
send: function(transmission, options, callback) {

// Handle optional options argument
if (typeof options === 'function') {
callback = options;
Expand All @@ -70,6 +70,8 @@ module.exports = function(client) {
return Promise.reject(new Error('transmission object is required')).asCallback(callback);
}

transmission = formatPayload(transmission);

const reqOpts = {
uri: api,
json: transmission,
Expand All @@ -81,3 +83,95 @@ module.exports = function(client) {
};

};

function formatPayload(originalTransmission) {
const transmission = _.cloneDeep(originalTransmission);

// don't format the payload if we are not given an array of recipients
if (!_.isArray(transmission.recipients)) {
return transmission;
}

// format all the original recipients to be in the object format
transmission.recipients = _.map(transmission.recipients, (recipient) => {
recipient.address = addressToObject(recipient.address);

return recipient;
});

// add the CC headers
if (_.isArray(transmission.cc)) {
_.set(transmission, 'content.headers.CC', generateCCHeader(transmission));
}

const headerTo = generateHeaderTo(transmission.recipients);

transmission.recipients = addListToRecipients(transmission, 'cc', headerTo);
transmission.recipients = addListToRecipients(transmission, 'bcc', headerTo);

delete transmission.cc;
delete transmission.bcc;

return transmission;
}

function addListToRecipients(transmission, listName, headerTo) {
if (!_.isArray(transmission[listName])) {
return transmission.recipients;
}

return transmission.recipients.concat(_.map(transmission[listName], (recipient) => {
recipient.address = addressToObject(recipient.address);

recipient.address.header_to = headerTo;

// remove name from address - name is only put in the header for cc and not at all for bcc
if (_.has(recipient.address, 'name')) {
delete recipient.address.name;
}

return recipient;
}));
}

function generateCCHeader(transmission) {
return _.map(transmission.cc, (ccRecipient) => addressToString(ccRecipient.address)).join(', ');
}

function generateHeaderTo(recipients) {
// if a recipient has a header_to then it is cc'd or bcc'd and we don't want it in the header_to value
const originalRecipients = _.filter(recipients, (recipient) => !_.has(recipient.address, 'header_to'));

return _.map(originalRecipients, (recipient) => addressToString(recipient.address)).join(', ');
}

function addressToString(address) {
if (_.isPlainObject(address)) {
if (_.has(address, 'name')) {
address = `"${address.name}" <${address.email}>`;
} else {
address = address.email;
}
}

return address;
}

function addressToObject(address) {
let addressObject = address;

if (_.isString(address)) {
addressObject = {};

const matches = /"?(.[^"]*)?"?\s*<(.+)>/gi.exec(address);

if (matches) {
addressObject.name = matches[1];
addressObject.email = matches[2];
} else {
addressObject.email = address;
}
}

return addressObject;
}
Loading

0 comments on commit d745867

Please sign in to comment.