Clean up the mta directory.
[mailman.git] / src / mailman / mta / verp.py
blob87c6609a00ee72d8fdd83511fae658f19b23d731
1 # Copyright (C) 2009-2016 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
8 # any later version.
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 # more details.
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
18 """VERP delivery."""
20 import logging
22 from mailman import public
23 from mailman.config import config
24 from mailman.mta.base import IndividualDelivery
25 from mailman.utilities.email import split_email
26 from mailman.utilities.string import expand
29 DOT = '.'
30 log = logging.getLogger('mailman.smtp')
33 @public
34 class VERPMixin:
35 """Mixin for VERP functionality.
37 This works by overriding the base class's _get_sender() method to return
38 the VERP'd envelope sender. It expects the individual recipient's address
39 to be squirreled away in the message metadata.
40 """
41 def _get_sender(self, mlist, msg, msgdata):
42 """Return the recipient's address VERP encoded in the sender.
44 :param mlist: The mailing list being delivered to.
45 :type mlist: `IMailingList`
46 :param msg: The original message being delivered.
47 :type msg: `Message`
48 :param msgdata: Additional message metadata for this delivery.
49 :type msgdata: dictionary
50 """
51 sender = super()._get_sender(mlist, msg, msgdata)
52 if msgdata.get('verp', False):
53 log.debug('VERPing %s', msg.get('message-id'))
54 recipient = msgdata['recipient']
55 sender_mailbox, sender_domain = split_email(sender)
56 # Encode the recipient's address for VERP.
57 recipient_mailbox, recipient_domain = split_email(recipient)
58 if recipient_domain is None:
59 # The recipient address is not fully-qualified. We can't
60 # deliver it to this person, nor can we craft a valid verp
61 # header. I don't think there's much we can do except ignore
62 # this recipient.
63 log.info('Skipping VERP delivery to unqual recip: %s',
64 recipient)
65 return sender
66 return '{0}@{1}'.format(
67 expand(config.mta.verp_format, dict(
68 bounces=sender_mailbox,
69 local=recipient_mailbox,
70 domain=DOT.join(recipient_domain))),
71 DOT.join(sender_domain))
72 else:
73 return sender
75 def avoid_duplicates(self, mlist, msg, msgdata):
76 """Flag the message for duplicate avoidance.
78 We can flag the mail as a duplicate for each member, if they've
79 already received this message, as calculated by Message-ID. See
80 `AvoidDuplicates.py`_ for details.
81 """
82 recipient = msgdata['recipient']
83 del msg['x-mailman-copy']
84 if recipient in msgdata.get('add-dup-header', {}):
85 msg['X-Mailman-Copy'] = 'yes'
88 @public
89 class VERPDelivery(VERPMixin, IndividualDelivery):
90 """Deliver a unique message to the MSA for each recipient."""
92 def __init__(self):
93 """See `IndividualDelivery`."""
94 super().__init__()
95 self.callbacks.append(self.avoid_duplicates)