You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by cc...@apache.org on 2026/10/14 21:54:04 UTC

(allura) 01/01: [#8626] Make inbound email auto-reply verification case insensitive

This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch cc/8626b
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 40b88335bab41efa71a3e1f1fd2be99cf1a25978
Author: Carlos Cruz <ca...@slashdotmedia.com>
AuthorDate: Wed Oct 14 21:48:07 2026 +0000

    [#8626] Make inbound email auto-reply verification case insensitive
---
 Allura/allura/lib/mail_util.py        | 21 ++++++++++++---------
 Allura/allura/tests/test_mail_util.py | 21 +++++++++++++++++++++
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 5f574dd9d..fc7b9a36f 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -116,16 +116,19 @@ def is_autoreply(msg):
     Detection based on suggestions from
     https://github.com/opennorth/multi_mail/wiki/Detecting-autoresponders
     '''
-    h = msg['headers']
+    # header names are case-insensitive, but msg['headers'] is a plain dict
+    h = {str(name).lower(): value for name, value in msg['headers'].items()}
+    # RFC 3834: any Auto-Submitted keyword other than "no" marks an automatic message
+    auto_submitted = str(h.get('auto-submitted', '')).split(';')[0].strip().lower()
     return (
-        h.get('Auto-Submitted') == 'auto-replied'
-        or h.get('X-POST-MessageClass') == '9; Autoresponder'
-        or h.get('Delivered-To') == 'Autoresponder'
-        or h.get('X-FC-MachineGenerated') == 'true'
-        or h.get('X-AutoReply-From') is not None
-        or h.get('X-Autogenerated') in ['Forward', 'Group', 'Letter', 'Mirror', 'Redirect', 'Reply']
-        or h.get('X-Precedence') == 'auto_reply'
-        or h.get('Return-Path') == '<>'
+        auto_submitted not in ('', 'no')
+        or h.get('x-post-messageclass') == '9; Autoresponder'
+        or h.get('delivered-to') == 'Autoresponder'
+        or h.get('x-fc-machinegenerated') == 'true'
+        or h.get('x-autoreply-from') is not None
+        or h.get('x-autogenerated') in ['Forward', 'Group', 'Letter', 'Mirror', 'Redirect', 'Reply']
+        or h.get('x-precedence') == 'auto_reply'
+        or h.get('return-path') == '<>'
     )
 
 
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index c74f8d85b..23470c731 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -303,6 +303,27 @@ def test_return_path(self):
         self.msg['headers']['Return-Path'] = '<>'
         assert is_autoreply(self.msg)
 
+    def test_header_name_case_insensitive(self):
+        self.msg['headers']['auto-submitted'] = 'auto-replied'
+        assert is_autoreply(self.msg)
+
+    def test_auto_submitted_auto_generated(self):
+        self.msg['headers']['auto-submitted'] = 'auto-generated'
+        assert is_autoreply(self.msg)
+
+    def test_auto_submitted_keyword_with_params(self):
+        self.msg['headers']['Auto-Submitted'] = 'Auto-Replied; owner-email="a@b.com"'
+        assert is_autoreply(self.msg)
+
+    def test_auto_submitted_no(self):
+        self.msg['headers']['Auto-Submitted'] = 'No'
+        assert not is_autoreply(self.msg)
+
+    def test_parsed_message_lowercase_header(self):
+        msg = parse_message(
+            'From: <a...@b.com>\nMessage-ID: <a...@b.com>\nauto-submitted: auto-generated\n\nbody')
+        assert is_autoreply(msg)
+
 
 class TestIdentifySender: