我已经阅读了http://www.jwz.org/doc/threading.html等一些很棒的在线资源,并且似乎任何电子邮件都使用Message-ID
标头发送,那么对它的任何回复包括命名该ID的In-Reply-To
和可以命名父消息ID的列表的In-Reply-To
,并且当在线程视图中查看电子邮件列表时,电子邮件客户端使用该信息来构建线程。如何使发送的电子邮件在GMail收件人的视图中显示为与Message-ID,In-Reply-To和引用
我的问题是:是否可以将一系列电子邮件发送给带有伪造标题的收件人,以使它们显示在线索中,而收件人不回复它们?如果是这样,为什么我的下面的尝试不工作?
我们有一个系统发送与我们系统中特定实体有关的几封电子邮件。假设我们多次销售小工具和电子邮件用户关于每个小工具。我们希望针对特定窗口小部件ID的所有电子邮件在我们用户的电子邮件客户端中显示为电子邮件线索。
这里的旅行似乎是通常发送电子邮件,然后回复。我们的系统只是想发送几封电子邮件,并伪造In-Reply-To和References头,以欺骗电子邮件客户端在树中显示它们。
我使用的消息ID的格式是: 'foobar的' +为widgetid +序列
- 为widgetid =唯一的号码每个插件例如1234
- 序列=每我们发送电子邮件时递增的序列号
第一电子邮件:
- 邮件ID
<[email protected]>
- 在-回复:不设置
- 参考:未提供
第二封电子邮件:
- 邮件ID
<[email protected]>
- 在-回复:
<[email protected]>
- 参考文献:
<[email protected]>
第三电子邮件:
- 邮件ID
<[email protected]>
- 在 - 回复:
<[email protected]>
个 - 参考文献:
<[email protected]> <[email protected]>
(顺便说一下,包括消息ID的@server.com
部分似乎是至关重要的。没有这个,使用例如foobar-123-0
,我们的SMTP服务器只是忽略了它,并用它自己的自动生成的消息ID)
电子邮件正确地显示在Thunderbird中的一棵树,而不是在Gmail中,他们只是前一后在收件箱中列出的一个,而其他的谈话是正确地穿过他们旁边。我不知道我是否搞错了,Thunderbird的数据不好,或者Gmail需要一些额外的非标准糖,我不提供。
这里是我的node.js测试脚本:
/*jshint dojo:true */
/*global console:true */
'use strict';
var Q = require('q'),
nconf = require('nconf'),
optimist = require('optimist'),
nodemailer = require('nodemailer');
console.log('Started to run.');
var argv = optimist.argv,
config = nconf.argv().env().file('conf.json'),
smtpConfig = config.get('smtp'),
smtpTransport = nodemailer.createTransport('SMTP', {
service: smtpConfig.service, // 'Gmail',
auth: {
user: smtpConfig.user, //'[email protected]',
pass: smtpConfig.pass //'xyz'
}
}),
rand = Math.floor(Math.random() * 5000), // a random enough unique id
messageIdPrefix = 'foobar-' + rand + '-';
var promises = [],
references = '';
for (var i = 0 ; i < 3 ; i ++) {
// Prepare email content
var subject = 'This is test email ' + i,
htmlMessage = '<h1>Am I threaded? Email ' + i + '</h1><p>???</p>',
textMessage = 'Am I threaded? Email ' + i + '\n\n???';
var recipients = '[email protected]';
// Each email in this sequence has a common prefix
// In Reply To should be the single immediate parent message id
// References should list all parents, top most first
var messageId = messageIdPrefix + i + '@server.com',
inReplyTo = (i > 0) ? ('<' + (messageIdPrefix + (i-1)) + '@server.com>') : false;
// setup e-mail data with unicode symbols
var mailOptions = {
from: config.get('ourEmail'),
to: recipients,
subject: subject,
text: textMessage,
html: htmlMessage,
messageId: messageId,
inReplyTo: inReplyTo,
references: references,
headers: {
// 'in-Reply-To': inReplyTo
}
};
// send mail with defined transport object
var q = Q.defer();
promises.push(q.promise);
smtpTransport.sendMail(mailOptions, function (error, response) {
if (error) {
console.error(error);
q.reject('error');
} else {
console.log('Message sent: ' + response.message);
q.resolve('yay!');
}
});
// next time round loop, if any, includes this id in the references list
references = (references ? (references + ' ') : '') + messageId;
}
Q.all(promises).then(function (results) {
console.log('All done, closing mail connection: ', results);
smtpTransport.close(); // shut down the connection pool, no more messages
});
需要像conf文件:
{
"ourEmail": "[email protected]",
"smtp": {
"service": "Gmail",
"user": "[email protected]",
"pass": "ilikecheese"
}
}
奖励积分,请提示,为何我尝试使用Q.all
似乎没有不尽管所有电子邮件都正确发送,但火和脚本仍未完全退出:)
谢谢。本周我们已经注意到了这种行为,当时我们将来自测试平台的所有外发电子邮件发送到一个电子邮件帐户。其中有几个是同样的行为,“X做Y”,但通常会去许多不同的个人账户。在同一个Gmail收件箱中查看时,它们全部都是线程化的。因此,我想所有的主题都必须足够相似,即“Re:”和“Fwd:”,其他的主题将被忽略,但基本上主题字符串匹配用于gmail?然后:)我们的计划,然后:) – Neek
在其他问题链接的接受的答案确实表明“在回复”标题也被考虑,我可以通过查看我今天看到的一些邮件列表线程来确认。一个人通过在他的回复中忽略了“in-reply-to”标题多次拆分该线程。所有的消息都有相同的主题,但没有正确的线程,直到他修复了他的客户端,因此它包含了“回复内容”标题。 – TwoD