diff options
Diffstat (limited to 'node_modules/nodemailer/lib/template-sender.js')
| -rw-r--r-- | node_modules/nodemailer/lib/template-sender.js | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/node_modules/nodemailer/lib/template-sender.js b/node_modules/nodemailer/lib/template-sender.js new file mode 100644 index 0000000..8963ea0 --- /dev/null +++ b/node_modules/nodemailer/lib/template-sender.js @@ -0,0 +1,129 @@ +'use strict'; + +var shared = require('nodemailer-shared'); + +module.exports = templateSender; + +// expose for testing +module.exports.render = render; + +/** + * Create template based e-mail sender + * + * @param {Object} transport Nodemailer transport object to use for actual sending + * @param {Object} templates Either an object with template strings or an external renderer + * @param {Object} [defaults] Default fields set for every mail sent using this sender + * @return {Function} Template based sender + */ +function templateSender(transport, templates, defaults) { + templates = templates || {}; + defaults = defaults || {}; + + // built in renderer + var defaultRenderer = function (context, callback) { + var rendered = {}; + Object.keys(templates).forEach(function (key) { + rendered[key] = render(templates[key], { + escapeHtml: key === 'html' + }, context); + }); + callback(null, rendered); + }; + + // actual renderer + var renderer = (typeof templates.render === 'function' ? templates.render.bind(templates) : defaultRenderer); + + return function (fields, context, callback) { + + var promise; + + if (!callback && typeof Promise === 'function') { + promise = new Promise(function (resolve, reject) { + callback = shared.callbackPromise(resolve, reject); + }); + } + + // render data + renderer(context, function (err, rendered) { + if (err) { + return callback(err); + } + var mailData = mix(defaults, fields, rendered); + setImmediate(function () { + transport.sendMail(mailData, callback); + }); + }); + + return promise; + }; +} + +/** + * Merges multiple objects into one. Assumes single level, except 'headers' + */ +function mix( /* obj1, obj2, ..., objN */ ) { + var args = Array.prototype.slice.call(arguments); + var result = {}; + + args.forEach(function (arg) { + Object.keys(arg || {}).forEach(function (key) { + if (key === 'headers') { + if (!result.headers) { + result.headers = {}; + } + Object.keys(arg[key]).forEach(function (hKey) { + if (!(hKey in result.headers)) { + result.headers[hKey] = arg[key][hKey]; + } + }); + } else if (!(key in result)) { + result[key] = arg[key]; + } + }); + }); + + return result; +} + +/** + * Renders a template string using provided context. Values are marked as {{key}} in the template. + * + * @param {String} str Template string + * @param {Object} options Render options. options.escapeHtml=true escapes html specific characters + * @param {Object} context Key-value pairs for the template, eg {name: 'User Name'} + * @return {String} Rendered template + */ +function render(str, options, context) { + str = (str || '').toString(); + context = context || {}; + options = options || {}; + + var re = /\{\{[ ]*([^{}\s]+)[ ]*\}\}/g; + + return str.replace(re, function (match, key) { + var value; + if (context.hasOwnProperty(key)) { + value = context[key].toString(); + if (options.escapeHtml) { + value = value.replace(/["'&<>]/g, function (char) { + switch (char) { + case '&': + return '&'; + case '<': + return '<'; + case '>': + return '>'; + case '"': + return '"'; + case '\'': + return '''; + default: + return char; + } + }); + } + return value; + } + return match; + }); +} |
