postmailer
Version:
HTTP POST -> SMTP proxy, as Express middleware
99 lines (86 loc) • 3.2 kB
JavaScript
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, '&').replace(/"/g, '"').replace(/</g, '<') + '"/>';
}
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;