Return-Path: X-Original-To: apmail-incubator-allura-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-allura-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 94EB910769 for ; Thu, 7 Nov 2013 20:33:46 +0000 (UTC) Received: (qmail 75252 invoked by uid 500); 7 Nov 2013 20:33:46 -0000 Delivered-To: apmail-incubator-allura-commits-archive@incubator.apache.org Received: (qmail 75236 invoked by uid 500); 7 Nov 2013 20:33:46 -0000 Mailing-List: contact allura-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: allura-dev@incubator.apache.org Delivered-To: mailing list allura-commits@incubator.apache.org Received: (qmail 75228 invoked by uid 99); 7 Nov 2013 20:33:46 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 07 Nov 2013 20:33:46 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 4775231D729; Thu, 7 Nov 2013 20:33:46 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: tvansteenburgh@apache.org To: allura-commits@incubator.apache.org Message-Id: <285c041b87b24e35aae6e1d98b1eb9be@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: git commit: [#5182] ticket:375 Filter out incoming autoreplies Date: Thu, 7 Nov 2013 20:33:46 +0000 (UTC) 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 Authored: Fri Nov 1 14:18:12 2013 +0000 Committer: Tim Van Steenburgh 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'') - assert_equal(str(our_header), '=?utf-8?b?ItGC0LXRgdC90Y/RgtGB0Y8i?= ') \ No newline at end of file + assert_equal(str(our_header), '=?utf-8?b?ItGC0LXRgdC90Y/RgtGB0Y8i?= ') + + +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: +To: <1@bugs.test.p.in.sf.net> +Message-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):