in DSNs, add a References header pointing to the message with deliverability issues

so mail user agents will show DSNs threaded/grouped with the original message.
we store the MessageID in the message queue, so we have the value within reach
when we need it.

i saw a references header in a DSN from gmail on a test account. makes sense to me.
This commit is contained in:
Mechiel Lukkien
2023-07-23 17:56:39 +02:00
parent c5747bd656
commit dcb0f0a82c
8 changed files with 50 additions and 27 deletions

View File

@ -46,7 +46,7 @@ func queueDSN(ctx context.Context, c *conn, rcptTo smtp.Path, m dsn.Message) err
// ../rfc/3464:433
const has8bit = false
const smtputf8 = false
if _, err := queue.Add(ctx, c.log, "", smtp.Path{}, rcptTo, has8bit, smtputf8, int64(len(buf)), nil, f, bufUTF8, true); err != nil {
if _, err := queue.Add(ctx, c.log, "", smtp.Path{}, rcptTo, has8bit, smtputf8, int64(len(buf)), m.MessageID, nil, f, bufUTF8, true); err != nil {
return err
}
err = f.Close()

View File

@ -1678,8 +1678,10 @@ func (c *conn) submit(ctx context.Context, recvHdrFor func(string) string, msgWr
// Add Message-Id header if missing.
// ../rfc/5321:4131 ../rfc/6409:751
if header.Get("Message-Id") == "" {
msgPrefix = append(msgPrefix, fmt.Sprintf("Message-Id: <%s>\r\n", mox.MessageIDGen(c.smtputf8))...)
messageID := header.Get("Message-Id")
if messageID == "" {
messageID = mox.MessageIDGen(c.smtputf8)
msgPrefix = append(msgPrefix, fmt.Sprintf("Message-Id: <%s>\r\n", messageID)...)
}
// ../rfc/6409:745
@ -1870,7 +1872,7 @@ func (c *conn) submit(ctx context.Context, recvHdrFor func(string) string, msgWr
}
msgSize := int64(len(xmsgPrefix)) + msgWriter.Size
if _, err := queue.Add(ctx, c.log, c.account.Name, *c.mailFrom, rcptAcc.rcptTo, msgWriter.Has8bit, c.smtputf8, msgSize, xmsgPrefix, dataFile, nil, i == len(c.recipients)-1); err != nil {
if _, err := queue.Add(ctx, c.log, c.account.Name, *c.mailFrom, rcptAcc.rcptTo, msgWriter.Has8bit, c.smtputf8, msgSize, messageID, xmsgPrefix, dataFile, nil, i == len(c.recipients)-1); err != nil {
// Aborting the transaction is not great. But continuing and generating DSNs will
// probably result in errors as well...
metricSubmission.WithLabelValues("queueerror").Inc()
@ -2560,10 +2562,11 @@ func (c *conn) deliver(ctx context.Context, recvHdrFor func(string) string, msgW
if len(deliverErrors) > 0 {
now := time.Now()
dsnMsg := dsn.Message{
SMTPUTF8: c.smtputf8,
From: smtp.Path{Localpart: "postmaster", IPDomain: deliverErrors[0].rcptTo.IPDomain},
To: *c.mailFrom,
Subject: "mail delivery failure",
SMTPUTF8: c.smtputf8,
From: smtp.Path{Localpart: "postmaster", IPDomain: deliverErrors[0].rcptTo.IPDomain},
To: *c.mailFrom,
Subject: "mail delivery failure",
References: messageID,
// Per-message details.
ReportingMTA: mox.Conf.Static.HostnameDomain.ASCII,