smtp_direct.py is dead and gone.
[mailman.git] / src / mailman / mta / verp.py
blobc53276bdc245c5c901de7756de44a3b53232f19c
1 # Copyright (C) 2009 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 from __future__ import absolute_import, unicode_literals
22 __metaclass__ = type
23 __all__ = [
24 'VERPDelivery',
25 'VERPMixin',
29 import logging
31 from mailman.config import config
32 from mailman.email.utils import split_email
33 from mailman.mta.base import IndividualDelivery
34 from mailman.utilities.string import expand
37 DOT = '.'
38 log = logging.getLogger('mailman.smtp')
42 class VERPMixin:
43 """Mixin for VERP functionality.
45 This works by overriding the base class's _get_sender() method to return
46 the VERP'd envelope sender. It expects the individual recipient's address
47 to be squirreled away in the message metadata.
48 """
49 def _get_sender(self, mlist, msg, msgdata):
50 """Return the recipient's address VERP encoded in the sender.
52 :param mlist: The mailing list being delivered to.
53 :type mlist: `IMailingList`
54 :param msg: The original message being delivered.
55 :type msg: `Message`
56 :param msgdata: Additional message metadata for this delivery.
57 :type msgdata: dictionary
58 """
59 sender = super(VERPMixin, self)._get_sender(mlist, msg, msgdata)
60 if msgdata.get('verp', False):
61 recipient = msgdata['recipient']
62 sender_mailbox, sender_domain = split_email(sender)
63 # Encode the recipient's address for VERP.
64 recipient_mailbox, recipient_domain = split_email(recipient)
65 if recipient_domain is None:
66 # The recipient address is not fully-qualified. We can't
67 # deliver it to this person, nor can we craft a valid verp
68 # header. I don't think there's much we can do except ignore
69 # this recipient.
70 log.info('Skipping VERP delivery to unqual recip: %s', recip)
71 return sender
72 return '{0}@{1}'.format(
73 expand(config.mta.verp_format, dict(
74 bounces=sender_mailbox,
75 local=recipient_mailbox,
76 domain=DOT.join(recipient_domain))),
77 DOT.join(sender_domain))
78 else:
79 return sender
81 def avoid_duplicates(self, mlist, msg, msgdata):
82 """Flag the message for duplicate avoidance.
84 We can flag the mail as a duplicate for each member, if they've
85 already received this message, as calculated by Message-ID. See
86 `AvoidDuplicates.py`_ for details.
87 """
88 recipient = msgdata['recipient']
89 del msg['x-mailman-copy']
90 if recipient in msgdata.get('add-dup-header', {}):
91 msg['X-Mailman-Copy'] = 'yes'
95 class VERPDelivery(VERPMixin, IndividualDelivery):
96 """Deliver a unique message to the MSA for each recipient."""
98 def __init__(self):
99 """See `IndividualDelivery`."""
100 super(VERPDelivery, self).__init__()
101 self.callbacks.append(self.avoid_duplicates)