最近我不得不使用 CloudFlare 隐藏我的 IP 地址,但由于我的 MX 记录指向我自己的域,我不能。
我知道Mailgun可以将所有电子邮件转发到 user@example.com 到Gmail,但我不希望这样。我希望电子邮件可以转发示例.com自己的SMTP服务器。
我决定使用Mailgun catch_all()
和forward("https://exmaple.com/incoming-email?key=SECRET_KEY")
,并为此编写了一些节点.js代码。
var nodemailer = require('nodemailer');
var express = require('express');
var multer = require('multer');
var router = express.Router();
var KEY = 'SECRET_KEY';
var ADDITIONAL_HEADERS = ['timestamp', 'token', 'signature', 'mime-version'];
var transporter = nodemailer.createTransport('smtp://127.0.0.1');
var storage = multer.memoryStorage();
var upload = multer({
storage: storage
});
router.post('/', upload.any(), function (req, res, next) {
if (!req.query.key || req.query.key !== KEY) {
res.sendStatus(403);
return;
}
console.log('Incoming mail: ', req.body.From);
req.body.to = req.body.To;
req.body.cc = req.body.Cc;
req.body.from = req.body.From;
req.body.date = req.body.Date;
req.body.references = req.body.References;
req.body.replyTo = req.body['Reply-To'];
req.body.inReplyTo = req.body['In-Reply-To'];
req.body.messageId = req.body['Message-Id'];
req.body.html = req.body['body-html'];
req.body.text = req.body['body-plain'];
req.body.headers = {};
for (var key in req.body) {
if (key.toLowerCase().indexOf('X-') !== -1 ||
ADDITIONAL_HEADERS.indexOf(key.toLowerCase()) !== -1) {
req.body.headers[key] = req.body[key];
}
}
if (req.files) {
req.body.attachments = req.files;
req.body.attachments.forEach(function (attachment) {
attachment.filename = attachment.originalname;
attachment.contentType = attachment.mimetype;
attachment.content = attachment.buffer;
});
}
transporter.sendMail(req.body, function (err, info) {
if (err) {
console.log(err);
res.status(400).send(err);
return;
}
console.log(info);
res.send(info);
});
});
module.exports = router;
如您所见,该代码能够将任何传入的电子邮件转发到本地主机SMTP服务器。使用关于的代码,我可以使用 user@example.com 接收电子邮件。收到的电子邮件将包含正确的发件人、收件人、抄送、主题和正文,甚至附件。
然而,一天后,我被迫取消订阅 Arch Linux 邮件列表,一个人通过电子邮件告诉我:
您的邮件服务器似乎配置错误,并且至少发送了 它从我们的邮件列表中收到的一些邮件返回到列表。它还 删除过程中的一些标头,以帮助邮递员检测此类标头 行为。由于缺少这些标头,邮递员将发送邮件 再次向所有人展示,导致一个永无止境的循环。
在我呼救后,我也收到了一些电子邮件,表明我在此期间无法收到来自邮件列表的任何电子邮件。
为什么会出错?在转发/包装过程中删除的电子邮件中的"一些标题"是什么?是Mailgun的问题还是我自己的问题?如果是我的问题,可以在上面的代码中添加什么?谢谢。
我发现当电子邮件是密件抄送给您时,邮件将如下所示:
- 收件人: announce@example-mailing-list.com
- 密件抄送:you@example.com
这样在使用问题中的代码时,邮件将由节点.js代码处理,然后邮件会使用 smtp://127.0.0.1
发送回 announce@example-mailing-list.com,造成无限循环。
我已经更新了我的代码,从收件人列表中查找我的域的所有电子邮件地址,并将它们设置为To
字段,并且无限循环不再出现。
例如,收件人列表将如下所示:announce@example-mailing-list.com, you@example.com
,所以我找到所有以 @example.com
结尾的电子邮件地址并将它们设置为To
字段。
警告:有些信息会丢失,比如我再也看不到电子邮件的原始To
字段。但是,您可以将原始To
字段追加到任何字段,例如 subject
。
var nodemailer = require('nodemailer');
var express = require('express');
var multer = require('multer');
var router = express.Router();
var MY_DOMAIN = 'example.com';
var KEY = 'SECRET_KEY;
var ADDITIONAL_HEADERS = ['timestamp', 'token', 'signature', 'mime-version',
'return-path', 'dkim-signature'
];
var transporter = nodemailer.createTransport('smtp://127.0.0.1');
var storage = multer.memoryStorage();
var upload = multer({
storage: storage
});
router.post('/', upload.any(), function (req, res, next) {
if (!req.query.key || req.query.key !== KEY) {
res.sendStatus(403);
return;
}
console.log('Incoming mail: ', req.body.From);
req.body.to = req.body.recipient.split(', ').filter(email => email.indexOf('@' + MY_DOMAIN) !== -1);
req.body.from = req.body.From;
req.body.date = req.body.Date;
req.body.references = req.body.References;
req.body.replyTo = req.body['Reply-To'];
req.body.inReplyTo = req.body['In-Reply-To'];
req.body.messageId = req.body['Message-Id'];
req.body.html = req.body['body-html'];
req.body.text = req.body['body-plain'];
req.body.headers = {};
for (var key in req.body) {
if (key.toLowerCase().indexOf('x-') !== -1 ||
ADDITIONAL_HEADERS.indexOf(key.toLowerCase()) !== -1) {
req.body.headers[key] = req.body[key];
}
}
console.log('Params: ' + JSON.stringify(req.body));
if (req.files) {
req.body.attachments = req.files;
req.body.attachments.forEach(function (attachment) {
attachment.filename = attachment.originalname;
attachment.contentType = attachment.mimetype;
attachment.content = attachment.buffer;
});
}
transporter.sendMail(req.body, function (err, info) {
if (err) {
console.log(err);
res.status(400).send(err);
return;
}
console.log(info);
res.send(info);
});
});
module.exports = router;
电子邮件不仅具有收件人标头,而且还具有SMTP RCPT TO
值。此值可能与电子邮件中包含的 To 标头不同。
请参阅:在 SMTP 中,RCPT TO: 和 TO: 必须匹配吗?
您的代码似乎使用邮件内容,并且似乎没有单独处理传输收件人(SMTP RCPT TO
)。我不知道 mailgun 是否提供此值。
只需将邮件提交到您的 smtp 服务器,沿途的某些库可能会从 To 标头中提取收件人,但是在邮件列表中,这通常是不正确的。