Skip to content

Commit d745867

Browse files
authored
Merge pull request #194 from SparkPost/cc-and-bcc
added CC and BCC sugar
2 parents 0db0a1a + 4b304a7 commit d745867

File tree

6 files changed

+367
-2
lines changed

6 files changed

+367
-2
lines changed

docs/resources/transmissions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This library provides easy access to the [Transmissions](https://developers.spar
1515
* **send(transmission[, options, callback])**<br />
1616
Sends a message by creating a new transmission
1717
* `transmission` - an object of [transmission attributes](https://developers.sparkpost.com/api/transmissions#header-transmission-attributes)
18+
* `transmission.cc` - Recipients to receive a carbon copy of the transmission
19+
* `transmission.bcc` - Recipients to discreetly receive a carbon copy of the transmission
1820
* `options.num_rcpt_errors` - maximum number of recipient errors returned
1921

2022
## Examples
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
var key = 'YOURAPIKEY'
4+
, SparkPost = require('sparkpost')
5+
, client = new SparkPost(key)
6+
, transmission = {
7+
recipients: [
8+
{
9+
address: {
10+
11+
name: 'Original Recipient'
12+
},
13+
substitution_data: {
14+
recipient_type: 'Original'
15+
}
16+
}
17+
],
18+
bcc: [
19+
{
20+
address: {
21+
22+
},
23+
substitution_data: {
24+
recipient_type: 'BCC'
25+
}
26+
}
27+
],
28+
content: {
29+
from: {
30+
name: 'Node BCC Test',
31+
32+
},
33+
subject: 'Example email using bcc',
34+
text: 'An example email using bcc with SparkPost to the {{recipient_type}} recipient.',
35+
html: '<p>An example email using bcc with SparkPost to the {{recipient_type}} recipient.</p>'
36+
}
37+
};
38+
39+
// Promise
40+
client.transmissions.send(transmission)
41+
.then(data => {
42+
console.log('Congrats! You sent an email with bcc using SparkPost!');
43+
console.log(data);
44+
})
45+
.catch(err => {
46+
console.log('Whoops! Something went wrong');
47+
console.log(err);
48+
});
49+
50+
// Callback
51+
client.transmissions.send(transmission, function(err, data) {
52+
if (err) {
53+
console.log('Whoops! Something went wrong');
54+
console.log(err);
55+
} else {
56+
console.log('Congrats! You sent an email with bcc using SparkPost!');
57+
console.log(data);
58+
}
59+
});

examples/transmissions/send_with_cc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@ client.transmissions.send(transmission, function(err, data) {
5959
console.log('Congrats! You sent an email with cc using SparkPost!');
6060
console.log(data);
6161
}
62-
});
62+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use strict';
2+
3+
var key = 'YOURAPIKEY'
4+
, SparkPost = require('sparkpost')
5+
, client = new SparkPost(key)
6+
, transmission = {
7+
recipients: [
8+
{
9+
address: {
10+
11+
name: 'Original Recipient'
12+
},
13+
substitution_data: {
14+
recipient_type: 'Original'
15+
}
16+
},
17+
],
18+
cc: [
19+
{
20+
address: {
21+
22+
name: 'Carbon Copy Recipient',
23+
},
24+
substitution_data: {
25+
recipient_type: 'CC'
26+
}
27+
}
28+
],
29+
content: {
30+
from: {
31+
name: 'Node CC Test',
32+
33+
},
34+
subject: 'Example email using cc',
35+
text: 'An example email using cc with SparkPost to the {{recipient_type}} recipient.',
36+
html: '<p>An example email using cc with SparkPost to the {{recipient_type}} recipient.</p>'
37+
}
38+
};
39+
40+
// Promise
41+
client.transmissions.send(transmission)
42+
.then(data => {
43+
console.log('Congrats! You sent an email with cc using SparkPost!');
44+
console.log(data);
45+
})
46+
.catch(err => {
47+
console.log('Whoops! Something went wrong');
48+
console.log(err);
49+
});
50+
51+
// Callback
52+
client.transmissions.send(transmission, function(err, data) {
53+
if (err) {
54+
console.log('Whoops! Something went wrong');
55+
console.log(err);
56+
} else {
57+
console.log('Congrats! You sent an email with cc using SparkPost!');
58+
console.log(data);
59+
}
60+
});

lib/transmissions.js

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
const _ = require('lodash');
34
const api = 'transmissions';
45
const Promise = require('./Promise');
56

@@ -59,7 +60,6 @@ module.exports = function(client) {
5960
* @returns {Promise}
6061
*/
6162
send: function(transmission, options, callback) {
62-
6363
// Handle optional options argument
6464
if (typeof options === 'function') {
6565
callback = options;
@@ -70,6 +70,8 @@ module.exports = function(client) {
7070
return Promise.reject(new Error('transmission object is required')).asCallback(callback);
7171
}
7272

73+
transmission = formatPayload(transmission);
74+
7375
const reqOpts = {
7476
uri: api,
7577
json: transmission,
@@ -81,3 +83,95 @@ module.exports = function(client) {
8183
};
8284

8385
};
86+
87+
function formatPayload(originalTransmission) {
88+
const transmission = _.cloneDeep(originalTransmission);
89+
90+
// don't format the payload if we are not given an array of recipients
91+
if (!_.isArray(transmission.recipients)) {
92+
return transmission;
93+
}
94+
95+
// format all the original recipients to be in the object format
96+
transmission.recipients = _.map(transmission.recipients, (recipient) => {
97+
recipient.address = addressToObject(recipient.address);
98+
99+
return recipient;
100+
});
101+
102+
// add the CC headers
103+
if (_.isArray(transmission.cc)) {
104+
_.set(transmission, 'content.headers.CC', generateCCHeader(transmission));
105+
}
106+
107+
const headerTo = generateHeaderTo(transmission.recipients);
108+
109+
transmission.recipients = addListToRecipients(transmission, 'cc', headerTo);
110+
transmission.recipients = addListToRecipients(transmission, 'bcc', headerTo);
111+
112+
delete transmission.cc;
113+
delete transmission.bcc;
114+
115+
return transmission;
116+
}
117+
118+
function addListToRecipients(transmission, listName, headerTo) {
119+
if (!_.isArray(transmission[listName])) {
120+
return transmission.recipients;
121+
}
122+
123+
return transmission.recipients.concat(_.map(transmission[listName], (recipient) => {
124+
recipient.address = addressToObject(recipient.address);
125+
126+
recipient.address.header_to = headerTo;
127+
128+
// remove name from address - name is only put in the header for cc and not at all for bcc
129+
if (_.has(recipient.address, 'name')) {
130+
delete recipient.address.name;
131+
}
132+
133+
return recipient;
134+
}));
135+
}
136+
137+
function generateCCHeader(transmission) {
138+
return _.map(transmission.cc, (ccRecipient) => addressToString(ccRecipient.address)).join(', ');
139+
}
140+
141+
function generateHeaderTo(recipients) {
142+
// 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
143+
const originalRecipients = _.filter(recipients, (recipient) => !_.has(recipient.address, 'header_to'));
144+
145+
return _.map(originalRecipients, (recipient) => addressToString(recipient.address)).join(', ');
146+
}
147+
148+
function addressToString(address) {
149+
if (_.isPlainObject(address)) {
150+
if (_.has(address, 'name')) {
151+
address = `"${address.name}" <${address.email}>`;
152+
} else {
153+
address = address.email;
154+
}
155+
}
156+
157+
return address;
158+
}
159+
160+
function addressToObject(address) {
161+
let addressObject = address;
162+
163+
if (_.isString(address)) {
164+
addressObject = {};
165+
166+
const matches = /"?(.[^"]*)?"?\s*<(.+)>/gi.exec(address);
167+
168+
if (matches) {
169+
addressObject.name = matches[1];
170+
addressObject.email = matches[2];
171+
} else {
172+
addressObject.email = address;
173+
}
174+
}
175+
176+
return addressObject;
177+
}

0 commit comments

Comments
 (0)