UNPKG

postmailer

Version:

HTTP POST -> SMTP proxy, as Express middleware

99 lines (86 loc) 3.2 kB
var mime = require('mime'); var nodemailer = require('nodemailer'); var directTransport = require('nodemailer-direct-transport'); function commaSplit(string) { return string.match(/([^,]|"([^"]|\\.)*")+/g) || []; } function emailFromUrls(urls) { for (var i = 0; i < urls.length; i++) { if (/^mailto\:/.test(urls[i])) { return urls[i].replace('mailto:', ''); } } return null; } function sendWithNodemailer(hub, options) { options = options || {}; var maxInline = options.maxInline || 500*1024; // 500kb maximum inline document var transport = nodemailer.createTransport(options.transport || directTransport()); transport.on('log', function (message) { hub.emit('log', message); }); hub.handle('mail', function (mail, next) { var hub = this; var email = emailFromUrls(mail.target.urls); if (!email) return next(); // Replace URLs with email addresses var messageHeaders = {}; function transformField(value) { if (Array.isArray(value)) return value.map(transformField); return value.replace(/<([^<>]+\:\/\/[^<>]+)>/g, function (original, url) { var match = hub.canonical(url); var email = emailFromUrls(match.urls); if (email) return '<' + email + '>'; return original; }); } for (var key in mail.headers) { messageHeaders[key] = transformField(mail.headers[key]); } // Envelope sender var sender = (messageHeaders['sender'] || commaSplit(messageHeaders['from'])[0]); // strip name and <> sender = sender.replace(/^\s*"([^"\\]|\\.)*"/, '').replace(/(^[^<]*<|>[^>]*$)/g, ''); var nodeMail = { from: messageHeaders['from'], to: [email], cc: messageHeaders['cc'] ? commaSplit(messageHeaders['cc']) : [], subject: messageHeaders['subject'] || '', headers: mail.headers, envelope: { /* only send to the "to" address, don't include CC/BCC */ from: sender, to: email } }; nodeMail.headers['to'] = nodeMail.headers['to'] || (JSON.stringify(mail.target.name) + ' <' + mail.target.email + '>'); // Format as inline text, inline HTML, inline image (with HTML) or attachment var inline = mail.length && mail.length < maxInline && mail.filename; var contentType = mail.headers['content-type'] || 'text/plain'; if (inline && /^text\/plain($|\s|;)/.test(contentType)) { nodeMail.text = copyStream(request); } else if (inline && /^text\/html($|\s|;)/.test(contentType)) { nodeMail.html = copyStream(request); } else { var filename = mail.filename || ('attachment.' + mime.extension(contentType)); var cid = null; if (/^image\//.test(contentType) && inline) { cid = crypto.pseudoRandomBytes(16).toString('hex') + '-' + email; nodeMail.html = '<img src="cid:' + cid + '" style="max-width: 100%; max-height: 100%" alt="' + filename.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt') + '"/>'; } nodeMail.attachments = [{ contentType: contentType, content: mail.message, cid: cid, filename: filename }]; } hub.emit('log', 'Forwarding to ' + nodeMail.to); transport.sendMail(nodeMail, function (error) { if (error) { hub.emit('error', error); return next(); } }); }); } module.exports = sendWithNodemailer;