Code

ignore incoming email with "Precedence: bulk" (sf patch 843489)
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 4 Dec 2003 23:34:25 +0000 (23:34 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 4 Dec 2003 23:34:25 +0000 (23:34 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2013 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
doc/index.txt
roundup/mailgw.py
test/test_mailgw.py

index 836f5af24db8068da6d79851f61f4dfe0364e473..069021acb39e5f9e0a4bf9a70d33afd91cb599da 100644 (file)
@@ -19,6 +19,7 @@ Feature:
   alphabetically (sf feature 790512).
 - added script for copying user(s) from tracker to tracker (sf patch
   828963)
+- ignore incoming email with "Precedence: bulk" (sf patch 843489)
 
 Fixed:
 - mysql documentation fixed to note requirement of 4.0+ and InnoDB
index 87d94a1ee9044f9a3bce66f03fa3b72e0bcdc8b8..819dd9e826064dfeaa8901666b09dcfd8d32172b 100644 (file)
@@ -58,6 +58,7 @@ Titus Brown,
 Roch'e Compaan,
 Paul F. Dubois,
 Jeff Epler,
+Tom Epperly,
 Hernan Martinez Foffani,
 Ajit George,
 Frank Gibbons,
index 50a3c548884685eb2a0e7a2c0d4ac3a85abe87b6..468333ec42bd4eca5deb6d89bb1ae0cb12f1aea4 100644 (file)
@@ -73,7 +73,7 @@ are calling the create() method to create a new node). If an auditor raises
 an exception, the original message is bounced back to the sender with the
 explanatory message given in the exception. 
 
-$Id: mailgw.py,v 1.138 2003-11-13 03:41:38 richard Exp $
+$Id: mailgw.py,v 1.139 2003-12-04 23:34:25 richard Exp $
 """
 
 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
@@ -92,14 +92,22 @@ class MailUsageError(ValueError):
     pass
 
 class MailUsageHelp(Exception):
-    pass
-
-class MailLoop(Exception):
-    """ We've seen this message before... """
+    """ We need to send the help message to the user. """
     pass
 
 class Unauthorized(Exception):
     """ Access denied """
+    pass
+
+class IgnoreMessage(Exception):
+    """ A general class of message that we should ignore. """
+    pass
+class IgnoreBulk(IgnoreMessage):
+        """ This is email from a mailing list or from a vacation program. """
+        pass
+class IgnoreLoop(IgnoreMessage):
+        """ We've seen this message before... """
+        pass
 
 def initialiseSecurity(security):
     ''' Create some Permissions and Roles on the security object
@@ -300,53 +308,7 @@ class MailGW:
         sendto = message.getaddrlist('resent-from')
         if not sendto:
             sendto = message.getaddrlist('from')
-        if sendto:
-            if not self.trapExceptions:
-                return self.handle_message(message)
-            try:
-                return self.handle_message(message)
-            except MailUsageHelp:
-                # bounce the message back to the sender with the usage message
-                fulldoc = '\n'.join(string.split(__doc__, '\n')[2:])
-                sendto = [sendto[0][1]]
-                m = ['']
-                m.append('\n\nMail Gateway Help\n=================')
-                m.append(fulldoc)
-                self.mailer.bounce_message(message, sendto, m,
-                    subject="Mail Gateway Help")
-            except MailUsageError, value:
-                # bounce the message back to the sender with the usage message
-                fulldoc = '\n'.join(string.split(__doc__, '\n')[2:])
-                sendto = [sendto[0][1]]
-                m = ['']
-                m.append(str(value))
-                m.append('\n\nMail Gateway Help\n=================')
-                m.append(fulldoc)
-                self.mailer.bounce_message(message, sendto, m)
-            except Unauthorized, value:
-                # just inform the user that he is not authorized
-                sendto = [sendto[0][1]]
-                m = ['']
-                m.append(str(value))
-                self.mailer.bounce_message(message, sendto, m)
-            except MailLoop:
-                # XXX we should use a log file here...
-                return
-            except:
-                # bounce the message back to the sender with the error message
-                # XXX we should use a log file here...
-                sendto = [sendto[0][1], self.instance.config.ADMIN_EMAIL]
-                m = ['']
-                m.append('An unexpected error occurred during the processing')
-                m.append('of your message. The tracker administrator is being')
-                m.append('notified.\n')
-                m.append('----  traceback of failure  ----')
-                s = cStringIO.StringIO()
-                import traceback
-                traceback.print_exc(None, s)
-                m.append(s.getvalue())
-                self.mailer.bounce_message(message, sendto, m)
-        else:
+        if not sendto:
             # very bad-looking message - we don't even know who sent it
             # XXX we should use a log file here...
             sendto = [self.instance.config.ADMIN_EMAIL]
@@ -358,6 +320,56 @@ class MailGW:
             m.append('')
             self.mailer.bounce_message(message, sendto, m,
                 subject='Badly formed message from mail gateway')
+            return
+
+        # try normal message-handling
+        if not self.trapExceptions:
+            return self.handle_message(message)
+        try:
+            return self.handle_message(message)
+        except MailUsageHelp:
+            # bounce the message back to the sender with the usage message
+            fulldoc = '\n'.join(string.split(__doc__, '\n')[2:])
+            sendto = [sendto[0][1]]
+            m = ['']
+            m.append('\n\nMail Gateway Help\n=================')
+            m.append(fulldoc)
+            self.mailer.bounce_message(message, sendto, m,
+                subject="Mail Gateway Help")
+        except MailUsageError, value:
+            # bounce the message back to the sender with the usage message
+            fulldoc = '\n'.join(string.split(__doc__, '\n')[2:])
+            sendto = [sendto[0][1]]
+            m = ['']
+            m.append(str(value))
+            m.append('\n\nMail Gateway Help\n=================')
+            m.append(fulldoc)
+            self.mailer.bounce_message(message, sendto, m)
+        except Unauthorized, value:
+            # just inform the user that he is not authorized
+            sendto = [sendto[0][1]]
+            m = ['']
+            m.append(str(value))
+            self.mailer.bounce_message(message, sendto, m)
+        except IgnoreMessage:
+            # XXX we should use a log file here...
+            # do not take any action
+            # this exception is thrown when email should be ignored
+            return
+        except:
+            # bounce the message back to the sender with the error message
+            # XXX we should use a log file here...
+            sendto = [sendto[0][1], self.instance.config.ADMIN_EMAIL]
+            m = ['']
+            m.append('An unexpected error occurred during the processing')
+            m.append('of your message. The tracker administrator is being')
+            m.append('notified.\n')
+            m.append('----  traceback of failure  ----')
+            s = cStringIO.StringIO()
+            import traceback
+            traceback.print_exc(None, s)
+            m.append(s.getvalue())
+            self.mailer.bounce_message(message, sendto, m)
 
     def get_part_data_decoded(self,part):
         encoding = part.getencoding()
@@ -397,7 +409,11 @@ class MailGW:
         '''
         # detect loops
         if message.getheader('x-roundup-loop', ''):
-            raise MailLoop
+            raise IgnoreLoop
+
+        # detect Precedence: Bulk
+        if (message.getheader('precedence', '') == 'bulk'):
+            raise IgnoreBulk
 
         # XXX Don't enable. This doesn't work yet.
 #  "[^A-z.]tracker\+(?P<classname>[^\d\s]+)(?P<nodeid>\d+)\@some.dom.ain[^A-z.]"
index 5ffc55e5351c6882a88bf63c11442de839b6949c..bf8c440b614dd3c4994c9b95f8657ebc4453a067 100644 (file)
@@ -8,7 +8,7 @@
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 #
-# $Id: test_mailgw.py,v 1.62 2003-11-13 03:41:38 richard Exp $
+# $Id: test_mailgw.py,v 1.63 2003-12-04 23:34:25 richard Exp $
 
 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822
 
@@ -18,7 +18,8 @@ if not os.environ.has_key('SENDMAILDEBUG'):
     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
 
-from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, parseContent
+from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
+    parseContent, IgnoreLoop, IgnoreBulk
 from roundup import init, instance, rfc2822
 
 
@@ -961,7 +962,36 @@ This is a test submission of a new issue.
         l.sort()
         self.assertEqual(l, [self.richard_id, self.mary_id])
         return nodeid
-    
+
+
+    def testDejaVu(self):
+        self.assertRaises(IgnoreLoop, self._send_mail,
+            '''Content-Type: text/plain;
+  charset="iso-8859-1"
+From: Chef <chef@bork.bork.bork>
+X-Roundup-Loop: hello
+To: issue_tracker@your.tracker.email.domain.example
+Cc: richard@test
+Message-Id: <dummy_test_message_id>
+Subject: Re: [issue] Testing...
+
+Hi, I've been mis-configured to loop messages back to myself.
+''')
+
+    def testItsBulkStupid(self):
+        self.assertRaises(IgnoreBulk, self._send_mail,
+            '''Content-Type: text/plain;
+  charset="iso-8859-1"
+From: Chef <chef@bork.bork.bork>
+Precedence: bulk
+To: issue_tracker@your.tracker.email.domain.example
+Cc: richard@test
+Message-Id: <dummy_test_message_id>
+Subject: Re: [issue] Testing...
+
+Hi, I'm on holidays, and this is a dumb auto-responder.
+''')
+
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(MailgwTestCase))