You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by tv...@apache.org on 2013/11/07 21:33:46 UTC

git commit: [#5182] ticket:375 Filter out incoming autoreplies

Updated Branches:
  refs/heads/master 7077c28e1 -> 97e80d971


[#5182] ticket:375 Filter out incoming autoreplies


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/97e80d97
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/97e80d97
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/97e80d97

Branch: refs/heads/master
Commit: 97e80d971d731bf0d0d26761c5e5fcf74f59f307
Parents: 7077c28
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Nov 1 14:18:12 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Thu Nov 7 20:32:54 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/mail_util.py        | 19 +++++++++++
 Allura/allura/tasks/mail_tasks.py     |  3 ++
 Allura/allura/tests/test_mail_util.py | 52 ++++++++++++++++++++++++++++--
 Allura/allura/tests/test_tasks.py     | 23 +++++++++++++
 4 files changed, 94 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/97e80d97/Allura/allura/lib/mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 6eb6bf0..b3e3b11 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -74,6 +74,25 @@ def AddrHeader(fromaddr):
     return addrheader
 
 
+def is_autoreply(msg):
+    '''Returns True, if message is an autoreply
+
+    Detection based on suggestions from
+    https://github.com/opennorth/multi_mail/wiki/Detecting-autoresponders
+    '''
+    h = msg['headers']
+    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') == '<>'
+    )
+
+
 def parse_address(addr):
     userpart, domain = addr.split('@')
     # remove common domain suffix

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/97e80d97/Allura/allura/tasks/mail_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/mail_tasks.py b/Allura/allura/tasks/mail_tasks.py
index a33c560..9b7fbd5 100644
--- a/Allura/allura/tasks/mail_tasks.py
+++ b/Allura/allura/tasks/mail_tasks.py
@@ -43,6 +43,9 @@ def route_email(
     except: # pragma no cover
         log.exception('Parse Error: (%r,%r,%r)', peer, mailfrom, rcpttos)
         return
+    if mail_util.is_autoreply(msg):
+        log.info('Skipping autoreply message: %s', msg['headers'])
+        return
     mail_user = mail_util.identify_sender(peer, mailfrom, msg['headers'], msg)
     with h.push_config(c, user=mail_user):
         log.info('Received email from %s', c.user.username)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/97e80d97/Allura/allura/tests/test_mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index bb22ac6..d604a72 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -22,13 +22,13 @@ from email.MIMEMultipart import MIMEMultipart
 from email.MIMEText import MIMEText
 from email import header
 
-from nose.tools import raises, assert_equal
+from nose.tools import raises, assert_equal, assert_false, assert_true
 from ming.orm import ThreadLocalORMSession
 
 from alluratest.controller import setup_basic_test, setup_global_objects
 from allura.lib.utils import ConfigProxy
 
-from allura.lib.mail_util import parse_address, parse_message, Header
+from allura.lib.mail_util import parse_address, parse_message, Header, is_autoreply
 from allura.lib.exceptions import AddressException
 from allura.tests import decorators as td
 
@@ -125,4 +125,50 @@ class TestHeader(object):
 
     def test_name_addr(self):
         our_header = Header(u'"теснятся"', u'<da...@b.com>')
-        assert_equal(str(our_header), '=?utf-8?b?ItGC0LXRgdC90Y/RgtGB0Y8i?= <da...@b.com>')
\ No newline at end of file
+        assert_equal(str(our_header), '=?utf-8?b?ItGC0LXRgdC90Y/RgtGB0Y8i?= <da...@b.com>')
+
+
+class TestIsAutoreply(object):
+
+    def setUp(self):
+        self.msg = {'headers': {}}
+
+    def test_empty(self):
+        assert_false(is_autoreply(self.msg))
+
+    def test_gmail(self):
+        self.msg['headers']['Auto-Submitted'] = 'auto-replied'
+        self.msg['headers']['Precedence'] = 'bulk'
+        self.msg['headers']['X-Autoreply'] = 'yes'
+        assert_true(is_autoreply(self.msg))
+
+    def test_qmail(self):
+        self.msg['headers']['Delivered-To'] = 'Autoresponder'
+        assert_true(is_autoreply(self.msg))
+
+    def test_mailtraq(self):
+        self.msg['headers']['X-POST-MessageClass'] = '9; Autoresponder'
+        assert_true(is_autoreply(self.msg))
+
+    def test_firstclass(self):
+        self.msg['headers']['X-FC-MachineGenerated'] = 'true'
+        assert_true(is_autoreply(self.msg))
+
+    def test_domain_technologies_control(self):
+        self.msg['headers']['X-AutoReply-From'] = 'something'
+        self.msg['headers']['X-Mail-Autoreply'] = 'something'
+        assert_true(is_autoreply(self.msg))
+
+    def test_communicate_pro(self):
+        self.msg['headers']['X-Autogenerated'] = 'Forward'
+        assert_true(is_autoreply(self.msg))
+
+    def test_boxtrapper_cpanel(self):
+        self.msg['headers']['Preference'] = 'auto_reply'
+        self.msg['headers']['X-Precedence'] = 'auto_reply'
+        self.msg['headers']['X-Autorespond'] = 'auto_reply'
+        assert_true(is_autoreply(self.msg))
+
+    def test_return_path(self):
+        self.msg['headers']['Return-Path'] = '<>'
+        assert_true(is_autoreply(self.msg))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/97e80d97/Allura/allura/tests/test_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 0cf5e60..9015f66 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -355,6 +355,29 @@ class TestMailTasks(unittest.TestCase):
             assert args[0] == 'Page'
             assert len(args) == 2
 
+    @td.with_tool('test', 'Tickets', 'bugs')
+    def test_receive_autoresponse(self):
+        message = '''Date: Wed, 30 Oct 2013 01:38:40 -0700
+From: <te...@sf.net>
+To: <1...@bugs.test.p.in.sf.net>
+Message-ID: <super-unique-id>
+Subject: Not here Re: Message notification
+Precedence: bulk
+X-Autoreply: yes
+Auto-Submitted: auto-replied
+
+I'm not here'''
+        import forgetracker
+        c.user = M.User.by_username('test-admin')
+        with mock.patch.object(forgetracker.tracker_main.ForgeTrackerApp, 'handle_message') as hm:
+            mail_tasks.route_email(
+                '0.0.0.0',
+                c.user.email_addresses[0],
+                ['1@bugs.test.p.in.sf.net'],
+                message)
+            assert_equal(hm.call_count, 0)
+
+
 class TestNotificationTasks(unittest.TestCase):
 
     def setUp(self):