From 3a6842c296e5eb3083ce942bce9172bfc74a2a4c Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Sun, 29 May 2016 17:51:10 +0200 Subject: [PATCH] Use nodemailer template engine --- src/dao/email.js | 120 ++++++++++++++++----------------- src/dao/message.json | 7 ++ test/integration/email-test.js | 4 +- 3 files changed, 68 insertions(+), 63 deletions(-) create mode 100644 src/dao/message.json diff --git a/src/dao/email.js b/src/dao/email.js index e79e694..2f6ff5d 100644 --- a/src/dao/email.js +++ b/src/dao/email.js @@ -19,6 +19,7 @@ const log = require('npmlog'); const util = require('../service/util'); +const message = require('./message.json'); /** * A simple wrapper around Nodemailer to send verification emails @@ -35,12 +36,12 @@ class Email { /** * Create an instance of the reusable nodemailer SMTP transport. - * @param {string} host The SMTP server's hostname e.g. 'smtp.gmail.com' - * @param {Object} auth Auth credential e.g. { user:'user@gmail.com', pass:'pass' } - * @param {Object} sender The message 'FROM' field e.g. { name:'Your Support', email:'noreply@exmple.com' } - * @param {string} port (optional) The SMTP server's SMTP port. Defaults to 465. - * @param {boolean} secure (optional) If TSL should be used. Defaults to true. - * @param {boolean} requireTLS (optional) If TSL is mandatory. Defaults to true. + * @param {string} host SMTP server's hostname: 'smtp.gmail.com' + * @param {Object} auth Auth credential: { user:'user@gmail.com', pass:'pass' } + * @param {Object} sender message 'FROM' field: { name:'Your Support', email:'noreply@exmple.com' } + * @param {string} port (optional) SMTP server's SMTP port. Defaults to 465. + * @param {boolean} secure (optional) if TSL should be used. Defaults to true. + * @param {boolean} requireTLS (optional) if TSL is mandatory. Defaults to true. */ init(options) { this._transport = this._mailer.createTransport({ @@ -54,31 +55,38 @@ class Email { } /** - * A generic method to send an email message via nodemail. - * @param {Object} from The sender user id object e.g. { name:'Jon Smith', email:'j@smith.com' } - * @param {Object} to The recipient user id object e.g. { name:'Jon Smith', email:'j@smith.com' } - * @param {string} subject The message subject - * @param {string} text The message plaintext body - * @param {string} html The message html body - * @yield {Object} The reponse object containing SMTP info + * A generic method to send an email message via nodemailer. + * @param {Object} from sender user id object: { name:'Jon Smith', email:'j@smith.com' } + * @param {Object} to recipient user id object: { name:'Jon Smith', email:'j@smith.com' } + * @param {string} subject message subject + * @param {string} text message plaintext body template + * @param {string} html message html body template + * @param {Object} params (optional) nodermailer template parameters + * @yield {Object} reponse object containing SMTP info */ *send(options) { - let mailOptions = { - from: { - name: options.from.name, - address: options.from.email - }, - to: { - name: options.to.name, - address: options.to.email - }, + let template = { subject: options.subject, text: options.text, html: options.html }; + let sender = { + from: { + name: options.from.name, + address: options.from.email + } + }; + let recipient = { + to: { + name: options.to.name, + address: options.to.email + } + }; + let params = options.params || {}; try { - let info = yield this._transport.sendMail(mailOptions); + let sendFn = this._transport.templateSender(template, sender); + let info = yield sendFn(recipient, params); log.silly('email', 'Email sent.', info); return info; } catch(error) { @@ -92,32 +100,45 @@ class Email { * ownership. If the primary email address is provided, only one email * will be sent out. Otherwise all of the PGP key's user IDs will be * verified, resulting in an email sent per user ID. - * @param {Array} userIds The user id documents containing the nonces - * @param {Array} primaryEmail (optional) The user's primary email address - * @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' } + * @param {Array} userIds user id documents containing the nonces + * @param {Array} primaryEmail (optional) user's primary email address + * @param {Object} origin Required for links to the keyserver: { protocol:'https', host:'openpgpkeys@example.com' } * @yield {undefined} */ - *sendVerification(options) { + *sendVerifyKey(options) { let primaryEmail = options.primaryEmail, userIds = options.userIds, origin = options.origin; let primaryUserId = userIds.find(uid => uid.email === primaryEmail); if (primaryUserId) { // send only one email to the primary user id - return yield this._sendVerificationHelper(primaryUserId, origin); + return yield this._sendVerifyKeyHelper(primaryUserId, origin); } for (let uid of userIds) { - yield this._sendVerificationHelper(uid, origin); + yield this._sendVerifyKeyHelper(uid, origin); } } /** - * Help method to send a verification message - * @param {Object} userId The user id document - * @param {Object} origin The origin of the server - * @yield {Object} The send response from the SMTP server + * Helper function to send a verification message + * @param {Object} userId user id document + * @param {Object} origin origin of the server + * @yield {Object} send response from the SMTP server */ - *_sendVerificationHelper(userId, origin) { - let message = this._createVerifyMessage(userId, origin); + *_sendVerifyKeyHelper(userId, origin) { + let msg = { + from: this._sender, + to: userId, + subject: message.verifyKey.subject, + text: message.verifyKey.text, + html: message.verifyKey.html, + params: { + name: userId.name, + protocol: origin.protocol, + host: origin.host, + keyid: encodeURIComponent(userId.keyid), + nonce: encodeURIComponent(userId.nonce) + } + }; try { - let info = yield this.send(message); + let info = yield this.send(msg); if (!this._checkResponse(info)) { log.warn('email', 'Verification mail may not have been received.', info); } @@ -127,34 +148,11 @@ class Email { } } - /** - * Helper function to create a verification message object. - * @param {Object} userId The user id document - * @param {Object} origin The origin of the server - * @return {Object} The message object - */ - _createVerifyMessage(userId, origin) { - let verifyLink = origin.protocol + '://' + origin.host + - '/api/v1/verify/?keyid=' + encodeURIComponent(userId.keyid) + - '&nonce=' + encodeURIComponent(userId.nonce); - let text = `Hey${userId.name ? ' ' + userId.name : ''}, - -please click here to verify your key: ${verifyLink} -`; - - return { - from: this._sender, - to: userId, - subject: 'Verify Your Key', - text: text - }; - } - /** * Check if the message was sent successfully according to SMTP * reply codes: http://www.supermailer.de/smtp_reply_codes.htm - * @param {Object} info The info object return from nodemailer - * @return {boolean} If the message was received by the user + * @param {Object} info info object return from nodemailer + * @return {boolean} if the message was received by the user */ _checkResponse(info) { return /^2/.test(info.response); diff --git a/src/dao/message.json b/src/dao/message.json new file mode 100644 index 0000000..de71166 --- /dev/null +++ b/src/dao/message.json @@ -0,0 +1,7 @@ +{ + "verifyKey": { + "subject": "Verify Your Key", + "text": "Hello {{name}},\n\nplease click here to verify your key: {{protocol}}://{{host}}/api/v1/verify/?keyid={{keyid}}&nonce={{nonce}}", + "html": "" + } +} \ No newline at end of file diff --git a/test/integration/email-test.js b/test/integration/email-test.js index b91fe2b..10a39b9 100644 --- a/test/integration/email-test.js +++ b/test/integration/email-test.js @@ -48,7 +48,7 @@ describe('Email Integration Tests', function() { }); }); - describe("sendVerification", function() { + describe("sendVerifyKey", function() { it('should work', function *() { let options = { userIds: [{ @@ -63,7 +63,7 @@ describe('Email Integration Tests', function() { host: 'localhost:' + config.server.port } }; - yield email.sendVerification(options); + yield email.sendVerifyKey(options); }); });