Как сделать так, чтобы отправленные электронные письма отображались в виде потока в представлении получателя GMail с помощью идентификатора сообщения, In-Reply-To и ссылок

Я прочитал несколько замечательных интернет-ресурсов, таких как http://www.jwz.org/doc/threading.html, и кажется, что любое электронное письмо отправляется с Message-ID заголовок, затем любые ответы на него включают In-Reply-To называя этот идентификатор и Refences который может называть список идентификаторов родительского сообщения, и почтовые клиенты используют эту информацию для создания потоков при просмотре списка электронных писем в многопоточном представлении.

У меня вопрос: можно ли отправлять серию электронных писем получателю с поддельными заголовками, чтобы они появлялись в цепочке без ответа получателя? Если так, то почему моя попытка ниже не работает?

У нас есть система, которая отправляет несколько электронных писем, относящихся к конкретному объекту в нашей системе. Допустим, мы продаем виджеты и по электронной почте пользователям несколько раз о каждом виджете. Мы хотим, чтобы все электронные письма с определенным идентификатором виджета отображались как цепочка сообщений в почтовых клиентах нашего пользователя.

Похоже, что в этом случае обычные письма отправляются, а затем отправляются ответы. Наша система просто хочет отправить несколько электронных писем и подделать заголовки In-Reply-To и References, чтобы заставить почтовых клиентов отображать их в дереве.

Формат идентификатора сообщения, который я использую: "foobar" + widgetId + sequence

  • widgetId = число, уникальное для каждого виджета, например, 1234
  • sequence = порядковый номер, увеличиваемый каждый раз, когда мы отправляем письмо

Первое электронное письмо:

  • Message-ID <foobar-1234-0@server.com>
  • In-Reply-To: не предоставляется
  • Рекомендации: не предоставляются

Второе письмо:

  • Message-ID <foobar-1234-1@server.com>
  • В ответ на: <foobar-1234-0@server.com>
  • Рекомендации: <foobar-1234-0@server.com>

Третье письмо:

  • Message-ID <foobar-1234-2@server.com>
  • В ответ на: <foobar-1234-1@server.com>
  • Рекомендации: <foobar-1234-0@server.com> <foobar-1234-1@server.com>

(кстати, включая @server.com часть идентификатора сообщения представляется жизненно важной. Без этого, используя, например, foobar-123-0наш SMTP-сервер просто проигнорировал его и использовал свой собственный автоматически сгенерированный идентификатор сообщения)

Электронные письма правильно отображаются в 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
});

Требуется файл conf вроде:

{
    "ourEmail": "me@server.com",
    "smtp": {
        "service": "Gmail",
        "user": "me@server.com",
        "pass": "ilikecheese"
    }
}

Для получения бонусных баллов, пожалуйста, укажите, почему моя попытка использовать Q.all похоже, не запускается, и скрипт не завершается корректно, несмотря на правильную отправку всех писем:)

1 ответ

Решение

Ответ на то, почему они не врезаны в Gmail, заключается в том, что потоки Gmail выполняются в соответствии с темой сообщений (это не основано на поле "in-reply-to" или "reference" в заголовке).

См. Ответы на этот вопрос о stackexchange для получения дополнительной информации о том, как Gmail выполняет потоки: https://webapps.stackexchange.com/questions/965/how-does-gmail-decide-to-thread-email-messages..

В вашем случае темы "Это тестовое электронное письмо 1", "Это тестовое электронное письмо 2" и "Это тестовое электронное письмо 3", которые не будут вызывать многопоточность по правилам использования Gmail.

Другие вопросы по тегам