5 Variable Envelope Return Path (VERP_) delivery is an alternative to bulk_
6 delivery, where an individual message is crafted uniquely for each recipient.
8 .. _VERP: http://en.wikipedia.org/wiki/Variable_envelope_return_path
11 The cost of enabling VERP is that Mailman must send to the upstream MTA, one
12 message per recipient. Under bulk delivery, an exact copy of one message can
13 be sent to many recipients, greatly reducing the bandwidth for delivery.
15 In Mailman, enabling VERP delivery for bounce detection brings with it a side
16 benefit: the message which must be crafted uniquely for each recipient, can be
17 further personalized to include all kinds of information unique to that
18 recipient. In the simplest case, the message can contain footer information,
19 e.g. pointing the user to their account URL or including a user-specific
20 unsubscription link. In theory, VERP delivery means we can do sophisticated
21 `mail merge`_ operations.
23 .. _`mail merge`: http://en.wikipedia.org/wiki/Mail_merge
25 Mailman's use of the term VERP really means "message personalization".
27 >>> from mailman.mta.verp import VERPDelivery
28 >>> verp = VERPDelivery()
30 Delivery strategies must implement the proper interface.
32 >>> from mailman.interfaces.mta import IMailTransportAgentDelivery
33 >>> from zope.interface.verify import verifyObject
34 >>> verifyObject(IMailTransportAgentDelivery, verp)
41 The message metadata specifies the set of recipients to send this message to.
42 If there are no recipients, there's nothing to do.
44 >>> mlist = create_list('test@example.com')
45 >>> msg = message_from_string("""\
46 ... From: aperson@example.org
47 ... To: test@example.com
49 ... Message-ID: <aardvark>
54 >>> verp.deliver(mlist, msg, {})
56 >>> len(list(smtpd.messages))
59 >>> verp.deliver(mlist, msg, dict(recipients=set()))
61 >>> len(list(smtpd.messages))
68 Each recipient of the message gets an individual, personalized copy of the
69 message, with their email address encoded into the envelope sender. This is
70 so the return path will point back to Mailman but allow for decoding of the
71 intended recipient's delivery address.
73 >>> recipients = set([
74 ... 'aperson@example.com',
75 ... 'bperson@example.com',
76 ... 'cperson@example.com',
79 VERPing is only actually done if the metadata requests it.
81 >>> msgdata = dict(recipients=recipients, verp=True)
82 >>> verp.deliver(mlist, msg, msgdata)
84 >>> messages = list(smtpd.messages)
88 >>> from operator import itemgetter
89 >>> for message in sorted(messages, key=itemgetter('x-rcptto')):
90 ... print message.as_string()
91 ... print '----------'
92 From: aperson@example.org
95 Message-ID: <aardvark>
96 Sender: test-bounces+aperson=example.com@example.com
97 Errors-To: test-bounces+aperson=example.com@example.com
99 X-MailFrom: test-bounces+aperson=example.com@example.com
100 X-RcptTo: aperson@example.com
104 From: aperson@example.org
107 Message-ID: <aardvark>
108 Sender: test-bounces+bperson=example.com@example.com
109 Errors-To: test-bounces+bperson=example.com@example.com
111 X-MailFrom: test-bounces+bperson=example.com@example.com
112 X-RcptTo: bperson@example.com
116 From: aperson@example.org
119 Message-ID: <aardvark>
120 Sender: test-bounces+cperson=example.com@example.com
121 Errors-To: test-bounces+cperson=example.com@example.com
123 X-MailFrom: test-bounces+cperson=example.com@example.com
124 X-RcptTo: cperson@example.com
129 The deliverer made a copy of the original message, so it wasn't changed.
131 >>> print msg.as_string()
132 From: aperson@example.org
135 Message-ID: <aardvark>