Skip to content

Commit

Permalink
feat: allow personalization of the From name & email for each email r…
Browse files Browse the repository at this point in the history
…ecipient (#1312)

* feat: allow personalization of the From name & email for each email recipient
  • Loading branch information
Bilal Boussayoud committed Oct 18, 2021
1 parent a3307fd commit a068f9d
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/use-cases/README.md
Expand Up @@ -4,6 +4,7 @@ This documentation provides examples for specific Twilio SendGrid v3 API use cas
* [Send a Single Email to a Single Recipient](single-email-single-recipient.md)
* [Send a Single Email to Multiple Recipients](single-email-multiple-recipients.md)
* [Send Multiple Emails to Multiple Recipients](multiple-emails-multiple-recipients.md)
* [Send Multiple Emails with Personalizations](multiple-emails-personalizations.md)
* [CC, BCC and Reply To](cc-bcc-reply-to.md)
* [Flexible Email Address Fields](flexible-address-fields.md)
* [Handling Success/Failure/Errors](success-failure-errors.md)
Expand Down
39 changes: 39 additions & 0 deletions docs/use-cases/multiple-emails-personalizations.md
@@ -0,0 +1,39 @@
# Send Multiple Emails with Personalizations

Personalizations are an array of objects, each representing a separate email, that allow you to customize the metadata of each email sent within a request. The below example shows how multiple emails, each with varying metadata, are sent with personalizations.

Refer to [the Sendgrid documentation](https://docs.sendgrid.com/for-developers/sending-email/personalizations) for more details about personalizations.
```js
const sgMail = require('@sendgrid/mail');
const sgHelpers = require('@sendgrid/helpers');
const Personalization = sgHelpers.classes.Personalization;

sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
from: 'sender1@example.org',
subject: 'Hello world',
text: 'Hello plain world!',
html: '<p>Hello HTML world!</p>',
personalizations: []
};

const personalization1 = new Personalization();
personalization1.setTo(['recipient2@example.org', 'recipient3@example.org']);
personalization1.setCc('recipient4@example.org');
msg.personalizations.push(personalization1);

const personalization2 = new Personalization();
personalization2.setTo(['recipient5@example.org', 'recipient6@example.org', 'recipient7@example.org']);
personalization2.setFrom('sender2@example.org');
personalization2.setCc('recipient8@example.org');
msg.personalizations.push(personalization2);

const personalization3 = new Personalization();
personalization3.setTo('recipient9@example.org');
personalization3.setFrom('sender3@example.org');
personalization3.setCc('recipient10@example.org');
personalization3.setSubject('Greetings world');
msg.personalizations.push(personalization3);

sgMail.send(msg);
```
7 changes: 7 additions & 0 deletions packages/helpers/classes/personalization.d.ts
Expand Up @@ -2,6 +2,7 @@ import { EmailData, EmailJSON } from "./email-address";

export interface PersonalizationData {
to: EmailData | EmailData[],
from?: EmailData,
cc?: EmailData | EmailData[],
bcc?: EmailData | EmailData[],
subject?: string;
Expand All @@ -14,6 +15,7 @@ export interface PersonalizationData {

export interface PersonalizationJSON {
to: EmailJSON | EmailJSON[];
from?: EmailJSON;
cc?: EmailJSON[];
bcc?: EmailJSON[];
headers?: { [key: string]: string; };
Expand Down Expand Up @@ -44,6 +46,11 @@ export default class Personalization {
*/
setTo(to: EmailData | EmailData[]): void;

/**
* Set from
*/
setFrom(from: EmailData): void;

/**
* Add a single to
*/
Expand Down
18 changes: 16 additions & 2 deletions packages/helpers/classes/personalization.js
Expand Up @@ -53,12 +53,13 @@ class Personalization {

//Extract properties from data
const {
to, cc, bcc, subject, headers, customArgs, sendAt,
to, from, cc, bcc, subject, headers, customArgs, sendAt,
substitutions, substitutionWrappers, dynamicTemplateData,
} = data;

//Set data
this.setTo(to);
this.setFrom(from);
this.setCc(cc);
this.setBcc(bcc);
this.setSubject(subject);
Expand Down Expand Up @@ -109,6 +110,16 @@ class Personalization {
this.to = EmailAddress.create(to);
}

/**
* Set from
* */
setFrom(from) {
if (typeof from === 'undefined') {
return;
}
this.from = EmailAddress.create(from);
}

/**
* Add a single to
*/
Expand Down Expand Up @@ -309,7 +320,7 @@ class Personalization {

//Get data from self
const {
to, cc, bcc, subject, headers, customArgs, sendAt,
to, from, cc, bcc, subject, headers, customArgs, sendAt,
substitutions, substitutionWrappers, dynamicTemplateData,
} = this;

Expand Down Expand Up @@ -347,6 +358,9 @@ class Personalization {
if (typeof sendAt !== 'undefined') {
json.sendAt = sendAt;
}
if (typeof from !== 'undefined') {
json.from = from;
}

//Return as snake cased object
return toSnakeCase(json, ['substitutions', 'dynamicTemplateData', 'customArgs', 'headers']);
Expand Down
Expand Up @@ -3,6 +3,7 @@
- setSubject() - set-subject.spec.js
- setSendAt() - set-send-at.spec.js
- setTo() - set-to.spec.js
- setFrom() - set-from.spec.js
- addTo() - add-to.spec.js
- setCc() - set-cc.spec.js
- addCc() - add-cc.spec.js
Expand Down
Expand Up @@ -23,6 +23,7 @@ describe('Personalization', function() {
//Data
const data = {
to: 'to@example.org',
from: 'from@example.org',
cc: ['cc1@example.org', 'cc2@example.org'],
bcc: ['bcc1@example.org', 'bcc2@example.org'],
subject: 'Test',
Expand All @@ -47,6 +48,7 @@ describe('Personalization', function() {
it('should have set all properties', () => {
p.fromData(data);
expect(p.to[0].email).to.equal('to@example.org');
expect(p.from.email).to.equal('from@example.org');
expect(p.cc[0].email).to.equal('cc1@example.org');
expect(p.cc[1].email).to.equal('cc2@example.org');
expect(p.bcc[0].email).to.equal('bcc1@example.org');
Expand Down
45 changes: 45 additions & 0 deletions packages/helpers/classes/personalization_specs/set-from.spec.js
@@ -0,0 +1,45 @@
'use strict';

/**
* Dependencies
*/
const Personalization = require('../personalization');
const EmailAddress = require('../email-address');

/**
* Tests
*/
describe('Personalization', function() {

//Create new personalization before each test
let p;
beforeEach(function() {
p = new Personalization();
});

//Set from
describe('setFrom()', function() {
it('should accept string values', function() {
p.setFrom('test@example.org');
expect(p.from).to.be.an.instanceof(EmailAddress);
expect(p.from.email).to.equal('test@example.org');
});
it('should properly update from value', function() {
p.setFrom('test1@example.com');
p.setFrom('test2@example.com');
p.setFrom('test3@example.com');
p.setFrom('test4@example.com');
expect(p.from.email).to.equal('test4@example.com');
});
it('should accept no input', function() {
expect(function() {
p.setFrom();
}).not.to.throw(Error);
});
it('should not overwrite value with no input', function() {
p.setFrom('test@example.org');
p.setFrom();
expect(p.from.email).to.equal('test@example.org');
});
});
});
Expand Up @@ -31,6 +31,13 @@ describe('Personalization', function() {
expect(json.to[0]).to.be.an.instanceof(EmailAddress);
expect(json.to[0].email).to.equal('test@example.org');
});
it('should set the from field', function() {
p.setFrom('testfrom@example.org');
const json = p.toJSON();
expect(json).to.have.property('from');
expect(json.from).to.be.an.instanceof(EmailAddress);
expect(json.from.email).to.equal('testfrom@example.org');
});
it('should set the cc field', function() {
p.setCc('testcc@example.org');
const json = p.toJSON();
Expand Down
1 change: 1 addition & 0 deletions test/typescript/helpers.ts
Expand Up @@ -10,6 +10,7 @@ new helpers.classes.EmailAddress({ name: "Some One", email: "someone@example.org

new helpers.classes.Personalization({
to: "someone@example.org",
from: "somebody@example.org",
subject: "Hello Some One",
dynamicTemplateData: {
translations: {
Expand Down

0 comments on commit a068f9d

Please sign in to comment.