Skip to content

Commit

Permalink
Switch pingeon email service to Postmark (#96)
Browse files Browse the repository at this point in the history
* Switch pingeon email service to Postmark

* Add default vars

* Add email default vars

* Add template maps

* Map template names with template ids
Refactor code generated vars

* Test empty config cases

* Fix tests

* Fix tests

* Add ability set email sender
  • Loading branch information
kostia-official authored Mar 24, 2017
1 parent 3fe4d68 commit 9cd44c9
Show file tree
Hide file tree
Showing 21 changed files with 250 additions and 171 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ PUBSUB_KEY - pub/sub provider secret key.

EMAIL_KEY - email provider secret key.
EMAIL_FROM - for example [email protected]
EMAIL_DEFAULT_VARS - defaults vars used in email templates
EMAIL_TEMPLATE_MAPS - map template name and template id.

PUSH_KEY - AWS key.
PUSH_SECRET - AWS secret.
Expand All @@ -47,6 +49,20 @@ DEFAULT_APP - default app from the list above.
SENTRY_DSN - DSN from getsentry.com
```
## Email
Pingeon pass own template variables to help you automate email sending:
- firstName - recipient's first name;
- toEmail - recipient's email;
- currentYear - guess what.
As template Pingeon can use template id or your own name. Just set in env var `EMAIL_TEMPLATE_MAPS`:
```json
{
"templateName" : "templateId"
}
```

## API

API Docs - [http://docs.pingeon.apiary.io](http://docs.pingeon.apiary.io)
Expand Down
11 changes: 10 additions & 1 deletion config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@
},
"email": {
"key": "EMAIL_KEY",
"from": "EMAIL_FROM"
"from": "EMAIL_FROM",
"defaultVars": {
"companyName": "test",
"companyLogo": "https://s-media-cache-ak0.pinimg.com/736x/3f/26/f7/3f26f736feb2c0878919db2cdbaee096.jpg"
},
"templatesMap": {
"alerts": "991101",
"broadcast-messages": "991102",
"reports": "1315901"
}
},
"push": {
"key": "PUSH_KEY",
Expand Down
4 changes: 3 additions & 1 deletion config/production.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
},
"email": {
"key": "EMAIL_KEY",
"from": "EMAIL_FROM"
"from": "EMAIL_FROM",
"defaultVars": "EMAIL_DEFAULT_VARS",
"templatesMap": "EMAIL_TEMPLATES_MAP"
},
"push": {
"key": "PUSH_KEY",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"mongoose": "4.4.10",
"mongoose-rename-id": "1.0.2",
"node-helpers": "~1.0.8",
"postmark": "1.2.1",
"promdash": "1.1.0",
"raven": "0.12.1",
"serve-favicon": "2.3.0",
Expand Down
47 changes: 0 additions & 47 deletions src/helpers/email.js

This file was deleted.

10 changes: 10 additions & 0 deletions src/helpers/email/get-recipient-name-parts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const Recipient = require('../../services/recipient/model');

module.exports = async function (recipientId) {
try {
const { firstName, lastName } = await Recipient.findOne({ _id: recipientId });
return { firstName, lastName };
} catch (err) {
return {};
}
};
6 changes: 6 additions & 0 deletions src/helpers/email/get-template-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const config = require('smart-config');

module.exports = function (templateName) {
const templatesMap = config.get('email.templatesMap') || {};
return templatesMap[templateName] || templateName;
};
12 changes: 12 additions & 0 deletions src/helpers/email/get-template-vars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const defaultVars = require('smart-config').get('email.defaultVars') || {};
const getRecipientNameParts = require('./get-recipient-name-parts');

module.exports = async function ({ vars = {}, recipientId, toEmail }) {
const nameParts = await getRecipientNameParts(recipientId);
const generatedVars = {
currentYear: new Date().getFullYear(),
...nameParts, toEmail
};
return { ...defaultVars, ...generatedVars, ...vars };
};

44 changes: 44 additions & 0 deletions src/helpers/email/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const debug = require('debug')('app:email');

const config = require('smart-config');
const emailConfig = config.get('email');
const { promisifyAll } = require('bluebird');
const postmark = require('postmark');
const getTemplateId = require('./get-template-id');
const getTemplateVars = require('./get-template-vars');
const client = promisifyAll(new postmark.Client(emailConfig.key));

const send = async({ email, from, to, cc, bcc, subject, message, template, vars, recipientId }) => {
try {
const toEmail = email || to;
const options = {
From: from || emailConfig.from,
To: toEmail,
Cc: cc,
Bcc: bcc
};

if (template) {
const templateId = getTemplateId(template);
const resultVars = await getTemplateVars({ vars, toEmail, recipientId });

return await client.sendEmailWithTemplateAsync({
TemplateId: templateId,
TemplateModel: resultVars,
...options
});
}

return await client.sendEmailAsync({
TextBody: message,
Subject: subject,
...options
});

} catch (err) {
debug(err);
return err;
}
};

module.exports = { send };
20 changes: 0 additions & 20 deletions src/helpers/mandrill-utils.js

This file was deleted.

9 changes: 0 additions & 9 deletions src/helpers/to-mandrill-vars.js

This file was deleted.

19 changes: 2 additions & 17 deletions src/services/provider/routes/email-notify-recipient.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
const debug = require('debug')('app:email-notify-recipient');
const RecipientProfile = require('../../recipient-profile/model');
const Recipient = require('../../recipient/model');
const emailHelper = require('../../../helpers/email');
const Promise = require('bluebird');
const _ = require('lodash');

async function addRecipientNameToVars(recipientId, vars) {
try {
const { firstName, lastName } = await Recipient.findOne({ _id: recipientId });
const nameVars = { FIRST_NAME: firstName, LAST_NAME: lastName };
return Object.assign({}, nameVars, vars);
} catch (err) {
debug(err);
return vars;
}
}

module.exports = async({ template, vars, recipientId, to, cc, bcc, message, subject }) => {
const resultVars = await addRecipientNameToVars(recipientId, vars);

module.exports = async({ recipientId, ...otherConfig }) => {
let res = await RecipientProfile.findOne({ recipientId, providerType: 'email' });
if (!res) {
debug('Recipient is not registered', { recipientId });
Expand All @@ -28,8 +14,7 @@ module.exports = async({ template, vars, recipientId, to, cc, bcc, message, subj
res = _.uniq(res);
res = await Promise.map(res, address => {
return emailHelper.send({
email: address, vars: resultVars,
template, to, cc, bcc, message, subject
email: address, recipientId, ...otherConfig
});
});
res = _.flatten(res);
Expand Down
6 changes: 3 additions & 3 deletions test/email-notify-recipient.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ describe('Email notify recipient', () => {
.send({ recipientId, template, vars })
.expect(201)
.expect(({ body }) => {
const { FIRST_NAME, LAST_NAME } = body[0].vars;
assert.equal(FIRST_NAME, firstName);
assert.equal(LAST_NAME, lastName);
const vars = body[0].TemplateModel;
assert.equal(vars.firstName, firstName);
assert.equal(vars.lastName, lastName);
})
);

Expand Down
42 changes: 32 additions & 10 deletions test/email.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,42 @@
require('./test-env');

const { isMatch } = require('lodash');
const emailProvider = require('../src/helpers/email');
const email = '[email protected]';
const template = 'thank-you-registering';
const vars = { completeregistration: 'some' };
const templatesMap = require('smart-config').get('email.templatesMap');
const email = '[email protected]';
const cc = email;
const bcc = email;
const template = 'alerts';
const vars = {
firstName: 'Constantine',
actionUrl: 'http://google.com',
message: 'Alerts test'
};
const message = 'Hello!';
const subject = 'Test!';

describe('Email send', function () {
this.timeout(100000);

it('should be sent', done => {
return emailProvider
.send({ email, template, vars })
.then(res => {
assert.ok(res);
done();
});
describe('message', () => {

it('should be sent', async() => {
const res = await emailProvider.send({ email, message, subject, cc, bcc });
assert.ok(isMatch(res.TextBody, message));
assert.ok(isMatch(res.Subject, subject));
});

});

describe('template', () => {

it('should be sent', async() => {
const res = await emailProvider.send({ subject, email, template, vars, cc, bcc });

assert.equal(res.TemplateId, templatesMap[template]);
assert.ok(isMatch(res.TemplateModel, vars));
});

});

});
55 changes: 55 additions & 0 deletions test/get-template-vars.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require('./test-env');
const { isMatch } = require('lodash');
const getTemplateVars = require('../src/helpers/email/get-template-vars');

let recipient = { firstName: 'John', lastName: 'Testerson' };
const defaultVars = require('smart-config').get('email.defaultVars');
const vars = {
actionUrl: 'http://some.com/any',
message: 'whatever'
};
const toEmail = '[email protected]';

describe('Get template vars', () => {

describe('User exist', () => {
before(() => request
.post('/recipients')
.send(recipient)
.expect(201)
.expect(({ body }) => {
recipient = body;
}));

it('should have all expected vars', async() => {
const resultVars = await getTemplateVars({ vars, toEmail, recipientId: recipient.id });

assert.equal(resultVars.firstName, recipient.firstName);
assert.equal(resultVars.lastName, recipient.lastName);
assert.equal(resultVars.currentYear, new Date().getFullYear());
assert.equal(resultVars.toEmail, toEmail);
assert.ok(isMatch(resultVars), defaultVars);
});
});

describe('User not exist', () => {

let resultVars;
before(async() => {
resultVars = await getTemplateVars({ vars, toEmail, recipientId: helpers.randomId() });
});

it('should have all expected vars', () => {
assert.equal(resultVars.currentYear, new Date().getFullYear());
assert.equal(resultVars.toEmail, toEmail);
assert.ok(isMatch(resultVars), defaultVars);
});

it('should not have user name', () => {
assert(!resultVars.firstName);
assert(!resultVars.lastName);
});

});

});
5 changes: 4 additions & 1 deletion test/global-mocks.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
const awsStub = require('./mocks/aws.stub');
const postmarkStub = require('./mocks/postmark.stub');

awsStub.register();
postmarkStub.register();

const sinon = require('sinon');
const pubsub = require('../src/helpers/pubsub');
const pubsubMocks = require('./mocks/pubsub.mock');

sinon.stub(pubsub, 'pub', pubsubMocks.pub);
sinon.stub(pubsub, 'sub', pubsubMocks.sub);
sinon.stub(require('../src/helpers/email'), 'send', require('./mocks/email.mock').send);
// sinon.stub(require('../src/helpers/email'), 'send', require('./mocks/email.mock').send);

module.exports = { awsStub };
Loading

0 comments on commit 9cd44c9

Please sign in to comment.