summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Handlers/ToOutgoing.py2
-rw-r--r--Mailman/docs/outgoing.txt150
-rw-r--r--Mailman/testing/test_handlers.py42
3 files changed, 151 insertions, 43 deletions
diff --git a/Mailman/Handlers/ToOutgoing.py b/Mailman/Handlers/ToOutgoing.py
index 8db969fa5..ff263e9a3 100644
--- a/Mailman/Handlers/ToOutgoing.py
+++ b/Mailman/Handlers/ToOutgoing.py
@@ -37,7 +37,7 @@ def process(mlist, msg, msgdata):
#
# Note that the verp flag may already be set, e.g. by mailpasswds using
# VERP_PASSWORD_REMINDERS. Preserve any existing verp flag.
- if msgdata.has_key('verp'):
+ if 'verp' in msgdata:
pass
elif mlist.personalize:
if config.VERP_PERSONALIZED_DELIVERIES:
diff --git a/Mailman/docs/outgoing.txt b/Mailman/docs/outgoing.txt
new file mode 100644
index 000000000..4dbc480fb
--- /dev/null
+++ b/Mailman/docs/outgoing.txt
@@ -0,0 +1,150 @@
+The outgoing handler
+====================
+
+Mailman's outgoing queue is used as the wrapper around SMTP delivery to the
+upstream mail server. The ToOutgoing handler does little more than drop the
+message into the outgoing queue, after calculating whether the message should
+be VERP'd or not. VERP means Variable Envelope Return Path; we're using that
+term somewhat incorrectly, but within the spirit of the standard, which
+basically describes how to encode the recipient's address in the originator
+headers for unambigous bounce processing.
+
+ >>> from Mailman.Handlers.ToOutgoing import process
+ >>> from Mailman.Message import Message
+ >>> from Mailman.Queue.Switchboard import Switchboard
+ >>> from Mailman.configuration import config
+ >>> from Mailman.database import flush
+ >>> from email import message_from_string
+ >>> mlist = config.list_manager.create('_xtest@example.com')
+ >>> flush()
+ >>> switchboard = Switchboard(config.OUTQUEUE_DIR)
+
+ >>> def queue_size():
+ ... size = len(switchboard.files)
+ ... for filebase in switchboard.files:
+ ... msg, msgdata = switchboard.dequeue(filebase)
+ ... switchboard.finish(filebase)
+ ... return size
+
+Craft a message destined for the outgoing queue. Include some random metadata
+as if this message had passed through some other handlers.
+
+ >>> msg = message_from_string("""\
+ ... Subject: Here is a message
+ ...
+ ... Something of great import.
+ ... """, Message)
+
+When certain conditions are met, the message will be VERP'd. For example, if
+the message metadata already has a VERP key, this message will be VERP'd.
+
+ >>> msgdata = dict(foo=1, bar=2, verp=True)
+ >>> process(mlist, msg, msgdata)
+ >>> print msg.as_string()
+ Subject: Here is a message
+ <BLANKLINE>
+ Something of great import.
+ >>> msgdata['verp']
+ True
+
+While the queued message will not be changed, the queued metadata will have an
+additional key set: the mailing list name.
+
+ >>> filebase = switchboard.files[0]
+ >>> qmsg, qmsgdata = switchboard.dequeue(filebase)
+ >>> switchboard.finish(filebase)
+ >>> print qmsg.as_string()
+ Subject: Here is a message
+ <BLANKLINE>
+ Something of great import.
+ >>> sorted(qmsgdata.items())
+ [('_parsemsg', False),
+ ('bar', 2), ('foo', 1),
+ ('listname', '_xtest@example.com'),
+ ('received_time', ...),
+ ('verp', True), ('version', 3)]
+ >>> queue_size()
+ 0
+
+If the list is set to personalize deliveries, and the global configuration
+option to VERP personalized deliveries is set, then the message will be
+VERP'd.
+
+ >>> mlist.personalize = True
+ >>> flush()
+ >>> config.VERP_PERSONALIZED_DELIVERIES = True
+ >>> msgdata = dict(foo=1, bar=2)
+ >>> process(mlist, msg, msgdata)
+ >>> msgdata['verp']
+ True
+ >>> queue_size()
+ 1
+
+However, if the global configuration variable prohibits VERP'ing, even
+personalized lists will not VERP.
+
+ >>> config.VERP_PERSONALIZED_DELIVERIES = False
+ >>> msgdata = dict(foo=1, bar=2)
+ >>> process(mlist, msg, msgdata)
+ >>> print msgdata.get('verp')
+ None
+ >>> queue_size()
+ 1
+
+If the list is not personalized, then the message may still be VERP'd based on
+the global configuration variable VERP_DELIVERY_INTERVAL. This variable tells
+Mailman how often to VERP even non-personalized mailing lists. It can be set
+to zero, which means non-personalized messages will never be VERP'd.
+
+ >>> mlist.personalize = False
+ >>> flush()
+ >>> config.VERP_DELIVERY_INTERVAL = 0
+ >>> msgdata = dict(foo=1, bar=2)
+ >>> process(mlist, msg, msgdata)
+ >>> print msgdata.get('verp')
+ None
+ >>> queue_size()
+ 1
+
+If the interval is set to 1, then every message will be VERP'd.
+
+ >>> config.VERP_DELIVERY_INTERVAL = 1
+ >>> for i in range(10):
+ ... msgdata = dict(foo=1, bar=2)
+ ... process(mlist, msg, msgdata)
+ ... print i, msgdata['verp']
+ 0 True
+ 1 True
+ 2 True
+ 3 True
+ 4 True
+ 5 True
+ 6 True
+ 7 True
+ 8 True
+ 9 True
+ >>> queue_size()
+ 10
+
+If the interval is set to some other number, then one out of that many posts
+will be VERP'd.
+
+ >>> config.VERP_DELIVERY_INTERVAL = 3
+ >>> for i in range(10):
+ ... mlist.post_id = i
+ ... flush()
+ ... msgdata = dict(foo=1, bar=2)
+ ... process(mlist, msg, msgdata)
+ ... print i, msgdata.get('verp', False)
+ 0 True
+ 1 False
+ 2 False
+ 3 True
+ 4 False
+ 5 False
+ 6 True
+ 7 False
+ 8 False
+ 9 True
+ >>> queue_size()
+ 10
diff --git a/Mailman/testing/test_handlers.py b/Mailman/testing/test_handlers.py
index 1b1105dd9..8b1f11e98 100644
--- a/Mailman/testing/test_handlers.py
+++ b/Mailman/testing/test_handlers.py
@@ -44,7 +44,6 @@ from Mailman.Handlers import Scrubber
# Don't test handlers such as SMTPDirect and Sendmail here
from Mailman.Handlers import ToArchive
from Mailman.Handlers import ToDigest
-from Mailman.Handlers import ToOutgoing
@@ -390,51 +389,10 @@ Content-Transfer-Encoding: 7bit
-class TestToOutgoing(TestBase):
- def setUp(self):
- TestBase.setUp(self)
- # We're going to want to inspect this queue directory
- self._sb = Switchboard(config.OUTQUEUE_DIR)
- # Save and set this value
- self._interval = config.VERP_DELIVERY_INTERVAL
- config.VERP_DELIVERY_INTERVAL = 1
-
- def tearDown(self):
- # Restore this value
- config.VERP_DELIVERY_INTERVAL = self._interval
- for f in os.listdir(config.OUTQUEUE_DIR):
- os.unlink(os.path.join(config.OUTQUEUE_DIR, f))
- TestBase.tearDown(self)
-
- def test_outgoing(self):
- eq = self.assertEqual
- msg = email.message_from_string("""\
-Subject: About Mailman
-
-It rocks!
-""")
- msgdata = {'foo': 1, 'bar': 2}
- ToOutgoing.process(self._mlist, msg, msgdata)
- files = self._sb.files()
- eq(len(files), 1)
- msg2, data = self._sb.dequeue(files[0])
- eq(msg.as_string(unixfrom=0), msg2.as_string(unixfrom=0))
- eq(len(data), 7)
- eq(data['foo'], 1)
- eq(data['bar'], 2)
- eq(data['version'], 3)
- eq(data['listname'], '_xtest@example.com')
- eq(data['verp'], 1)
- # Clock skew makes this unreliable
- #self.failUnless(data['received_time'] <= time.time())
-
-
-
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestApprove))
suite.addTest(unittest.makeSuite(TestScrubber))
suite.addTest(unittest.makeSuite(TestToArchive))
suite.addTest(unittest.makeSuite(TestToDigest))
- suite.addTest(unittest.makeSuite(TestToOutgoing))
return suite