Hi,

I had a few users explain that the bounces they sometimes get are so hard to understand...

To make life easier for them I added some messages to the templates so that they can read their errors in their native language. That helped, but users were still not always clear, which specific message a bounce related to. It seems reading error messages is hard...

Thus I had a quick look at the postfix/src/bounce and see how I could improve matters.

Attached is a small patch against postfix-3.6-20200830 that parses the Message-Id header from bounce_info->orig_fp, stores it in bounce_info->orig_msgid and then later adds a Reply-To and a References header with this Message-Id to the generated DSN message.

This allows MUAs to clearer show which original message a bounce is referring to and hopefully make life even easier for users.

Would this seem like a sensible feature for inclusion in postfix?

My code was only a quick change and it's been a while since I last wrote C-code, so if you got any pointers how to improve matters or if there's an easier way to extract a Message-Id header, I'd be happy to try to improve the code.

Cheers,
 andreas
diff --git a/postfix/src/bounce/bounce_notify_util.c 
b/postfix/src/bounce/bounce_notify_util.c
index 7c79ca0..6668cb3 100644
--- a/postfix/src/bounce/bounce_notify_util.c
+++ b/postfix/src/bounce/bounce_notify_util.c
@@ -206,6 +206,7 @@
 #include <deliver_completed.h>
 #include <dsn_mask.h>
 #include <smtputf8.h>
+#include <header_opts.h>
 
 /* Application-specific. */
 
@@ -266,6 +267,7 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
     bounce_info->arrival_time = 0;
     bounce_info->orig_offs = 0;
     bounce_info->message_size = 0;
+    bounce_info->orig_msgid = vstring_alloc(100);
     bounce_info->rcpt_buf = rcpt_buf;
     bounce_info->dsn_buf = dsn_buf;
     bounce_info->log_handle = log_handle;
@@ -351,20 +353,44 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
                                      mail_addr_mail_daemon(), 0);
            }
 
+            /*
+             * Extract Message-ID from original mail
+             */
+           else if (rec_type == REC_TYPE_NORM || rec_type == REC_TYPE_CONT) {
+
+               const HEADER_OPTS *hdr;
+               char *cp;
+
+               /* We've reached the body */
+               if (VSTRING_LEN(bounce_info->buf) == 0)
+                   break;
+
+               /* Discard input that does not look like a key-value header */
+               if (vstring_memchr(bounce_info->buf, ':') == 0)
+                   continue;
+
+               if ((hdr = header_opts_find(vstring_str(bounce_info->buf))) != 0
+                   && hdr->type == HDR_MESSAGE_ID) {
+                       cp = STR(bounce_info->buf) + strlen(hdr->name) + 1;
+                       while (ISSPACE(*cp))
+                           cp++;
+                       vstring_strcpy(bounce_info->orig_msgid, cp);
+               }
+           }
            /*
             * Backwards compatibility: no data offset in SIZE record.
             */
-           else if (rec_type == REC_TYPE_MESG) {
+           else if (rec_type == REC_TYPE_MESG && bounce_info->orig_offs == 0) {
                /* XXX Future: sender+recipient after message content. */
                if (VSTRING_LEN(bounce_info->sender) == 0)
                    msg_warn("%s: no sender before message content record",
                             bounce_info->queue_id);
                bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
-               break;
            }
            if (bounce_info->orig_offs > 0
                && bounce_info->arrival_time > 0
-               && VSTRING_LEN(bounce_info->sender) > 0)
+               && VSTRING_LEN(bounce_info->sender) > 0
+               && VSTRING_LEN(bounce_info->orig_msgid) > 0)
                break;
        }
     }
@@ -474,6 +500,16 @@ int     bounce_header(VSTREAM *bounce, BOUNCE_INFO 
*bounce_info,
                            STR(quote_822_local(bounce_info->buf, dest)),
                            postmaster_copy);
 
+
+    /*
+     * References and Reply-To header that references the original message-id
+     * for better threading in MUAs.
+     */
+    if (VSTRING_LEN(bounce_info->orig_msgid) > 0) {
+       post_mail_fprintf(bounce, "References: %s", 
STR(bounce_info->orig_msgid));
+       post_mail_fprintf(bounce, "In-Reply-To: %s", 
STR(bounce_info->orig_msgid));
+    }
+
     /*
      * Auto-Submitted header, as per RFC 3834.
      */
diff --git a/postfix/src/bounce/bounce_service.h 
b/postfix/src/bounce/bounce_service.h
index f8cc4d6..40793f2 100644
--- a/postfix/src/bounce/bounce_service.h
+++ b/postfix/src/bounce/bounce_service.h
@@ -80,6 +80,7 @@ typedef struct {
     long    orig_offs;                 /* start of content */
     time_t  arrival_time;              /* time of arrival */
     long    message_size;              /* size of content */
+    VSTRING *orig_msgid;               /* original message-id */
     RCPT_BUF *rcpt_buf;                        /* recipient info */
     DSN_BUF *dsn_buf;                  /* delivery status info */
     BOUNCE_LOG *log_handle;            /* open logfile */

Reply via email to