[Remail] [patch v2 10/11] remail: Add X-Original-From header

Thomas Gleixner tglx at linutronix.de
Sun Jun 18 22:13:53 CEST 2023


The 'From:' header mangling makes it unnecessarily hard to figure out the
name and email address of the person who posted to a list.

Save the original sender in the 'X-Original-From:' header.

Suggested-by: Linus Torvalds <torvalds at linux-foundation.org>
Suggested-by: Konstantin Ryabitsev <konstantin at linuxfoundation.org>
Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
Link: https://wiki.ietf.org/group/dmarc/XOriginalFrom
---
V2: Use X-Original-From and make it unconditional - Konstantin
---
 remail/mail.py     |   17 +++++++++++++++--
 remail/maillist.py |   10 ++++++----
 2 files changed, 21 insertions(+), 6 deletions(-)

--- a/remail/mail.py
+++ b/remail/mail.py
@@ -11,6 +11,7 @@ from email.generator import Generator
 from email.message import Message, EmailMessage
 from email.policy import EmailPolicy
 from email.policy import default as DefaultPolicy
+from email.headerregistry import UniqueSingleAddressHeader
 
 import smtplib
 import mailbox
@@ -75,13 +76,21 @@ import re
         if val:
             msgout[key] = val
 
-def send_mail(msg, account, mfrom, sender, listheaders, use_smtp, logger):
+def send_mail(msg, account, mfrom, sender, listheaders, use_smtp, logger,
+              origfrom=None):
     '''
     Send mail to the account. Make sure that the message is correct and all
     required headers and only necessary headers are in the outgoing mail.
     '''
 
-    # Convert to EmailMessage with default policy (utf-8=false) so both
+    # Clone the default policy (utf-8=false) and map the X-Original-From
+    # header to UniqueSingleAddressHeader. Otherwise this is treated as
+    # unspecified header.
+    policy = DefaultPolicy.clone()
+    policy.header_factory.map_to_type('X-Original-From',
+                                      UniqueSingleAddressHeader)
+
+    # Convert to EmailMessage with the modified default policy so both
     # smptlib.send_message() and the stdout dump keep the headers properly
     # encoded.
     parser = BytesFeedParser(policy=DefaultPolicy)
@@ -108,6 +117,10 @@ import re
     msg_copy_headers(msgout, msg, ['Content-Type', 'Content-Disposition',
                                    'Content-Transfer-Encoding',
                                    'Content-Language'])
+
+    if origfrom:
+        msgout['X-Original-From'] = origfrom
+
     msgout['Envelope-To'] = get_raw_email_addr(account.addr)
 
     # Set unixfrom with the current date/time
--- a/remail/maillist.py
+++ b/remail/maillist.py
@@ -86,11 +86,12 @@ import os
             self.gpg.encrypt(msg, account)
         return msg
 
-    def send_encrypted_mail(self, msg_plain, account, mfrom):
+    def send_encrypted_mail(self, msg_plain, account, mfrom, origfrom=None):
         try:
             msg_out = self.encrypt(msg_plain, account)
             send_mail(msg_out, account, mfrom, self.config.listaddrs.bounce,
-                      self.config.listheaders, self.use_smtp, self.logger)
+                      self.config.listheaders, self.use_smtp, self.logger,
+                      origfrom)
 
         except (RemailGPGException, RemailSmimeException) as ex:
             '''
@@ -243,7 +244,8 @@ import os
 
         msgid = msg.get('Message-Id', '<No ID>')
         msgto = msg.get('To')
-        msgfrom = get_raw_email_addr(msg.get('From'))
+        origfrom = msg.get('From')
+        msgfrom = get_raw_email_addr(origfrom)
         sinfo = sender_info(msg)
 
         # Archive the incoming mail
@@ -272,7 +274,7 @@ import os
         for account in dest.accounts.values():
             if not account.enabled:
                 continue
-            self.send_encrypted_mail(msg_plain, account, mfrom)
+            self.send_encrypted_mail(msg_plain, account, mfrom, origfrom)
         return True
 
     def handle_log(self):



More information about the Remail mailing list