如何使发送的电子邮件在GMail收件人的视图中显示为带有Message-ID,In-Reply-To和References的线程

Nee*_*eek 10 email gmail email-headers email-threading nodemailer

我已经阅读了一些很棒的在线资源,比如http://www.jwz.org/doc/threading.html,似乎任何电子邮件都是通过Message-ID标题发送的,然后对它的任何回复包括In-Reply-To命名该ID以及Refences哪些可以命名父级消息ID列表,电子邮件客户端在查看线程视图中的电子邮件列表时使用此信息构造线程.

我的问题是:是否可以将一系列电子邮件发送给带有伪标题的收件人,以使它们出现在一个没有收件人回复的线程中?如果是这样,为什么下面的尝试不起作用?

我们有一个系统可以发送几封与我们系统中特定实体相关的电子邮件.假设我们多次向每个小部件销售小部件和电子邮件用户.我们希望特定小部件ID的所有电子邮件在我们用户的电子邮件客户端中显示为电子邮件主题.

这里的旅行似乎通常是发送电子邮件,然后回复.我们的系统只是想发送几封电子邮件,并伪造In-Reply-To和References标题,以诱骗电子邮件客户端在树中显示它们.

我正在使用的Message-ID格式是:'foobar'+ widgetId + sequence

  • widgetId =每个小部件唯一的数字,例如1234
  • sequence =每次发送电子邮件时递增的序号

第一封邮箱:

  • 邮件ID <foobar-1234-0@server.com>
  • In-Reply-To:未提供
  • 参考文献:未提供

第二封邮箱:

  • 邮件ID <foobar-1234-1@server.com>
  • 在-回复: <foobar-1234-0@server.com>
  • 参考文献: <foobar-1234-0@server.com>

第三封邮箱:

  • 邮件ID <foobar-1234-2@server.com>
  • 在-回复: <foobar-1234-1@server.com>
  • 参考文献: <foobar-1234-0@server.com> <foobar-1234-1@server.com>

(顺便说一句,包括@server.com消息ID 的部分似乎是至关重要的.没有它,使用例如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, //'blah@gmail.com',
                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 = 'recipient@server.com';

    // 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
});
Run Code Online (Sandbox Code Playgroud)

需要一个conf文件,如:

{
    "ourEmail": "me@server.com",
    "smtp": {
        "service": "Gmail",
        "user": "me@server.com",
        "pass": "ilikecheese"
    }
}
Run Code Online (Sandbox Code Playgroud)

对于奖励积分,请提示为什么我的尝试使用Q.all似乎没有触发并且脚本不会干净地退出,尽管正确发送所有电子邮件:)

pee*_*eol 7

他们没有在Gmail中加入线程的答案是因为Gmail的线程是根据邮件的主题完成的(它不是基于标题中的"in-reply-to"或"references"字段).

有关Gmail如何进行线程处理的详细信息,请参阅stackexchange上此问题的答案:https://webapps.stackexchange.com/questions/965/how-does-gmail-decide-to-thread-email-messages ..

您的案例中的主题是"这是测试邮件1","这是测试邮件2"和"这是测试邮件3",它不会导致Gmail使用的规则进行线程化.

  • 在链接的另一个问题中接受的答案确实表明也会考虑"回复"标题,我可以通过查看今天看到的一些邮件列表主题来确认.一个人通过在他的回复中省略"回复"标题多次拆分线程.所有消息都具有相同的主题,但在他修复了客户端之前没有正确的线程,因此它包含了"in-reply-to"标题. (3认同)