summaryrefslogtreecommitdiff
path: root/src/mailman/app/bounces.py
diff options
context:
space:
mode:
authorBarry Warsaw2011-05-03 09:44:54 -0400
committerBarry Warsaw2011-05-03 09:44:54 -0400
commit4a183b61905b00cd23ffe4c2ecc2d5a1b5004ebd (patch)
tree020a7b7c992f54add9d3b5fd9d8ae99547bfe4c2 /src/mailman/app/bounces.py
parenteb7fca85f0b2a1a18daca761a5f5f6d9ffb76a43 (diff)
downloadmailman-4a183b61905b00cd23ffe4c2ecc2d5a1b5004ebd.tar.gz
mailman-4a183b61905b00cd23ffe4c2ecc2d5a1b5004ebd.tar.zst
mailman-4a183b61905b00cd23ffe4c2ecc2d5a1b5004ebd.zip
* Fix setup.py version regexp.
* Move get_verp() to class-based for easy overridding. Hook up StandardVERP but not yet ProbeVERP. * Use uuid.uuid4() to get unique id.
Diffstat (limited to 'src/mailman/app/bounces.py')
-rw-r--r--src/mailman/app/bounces.py106
1 files changed, 68 insertions, 38 deletions
diff --git a/src/mailman/app/bounces.py b/src/mailman/app/bounces.py
index 8d2526a66..8c42ede46 100644
--- a/src/mailman/app/bounces.py
+++ b/src/mailman/app/bounces.py
@@ -21,8 +21,8 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
+ 'StandardVERP',
'bounce_message',
- 'get_verp',
'scan_message',
]
@@ -39,6 +39,7 @@ from mailman.config import config
from mailman.core.i18n import _
from mailman.email.message import UserNotification
from mailman.interfaces.bounce import IBounceDetector
+from mailman.interfaces.pending import IPendings
from mailman.utilities.email import split_email
from mailman.utilities.string import oneline
@@ -103,46 +104,75 @@ def scan_message(mlist, msg):
-def get_verp(mlist, msg):
- """Extract a set of VERP bounce addresses.
+class _BaseVERPParser:
+ """Base class for parsing VERP messages.
Sadly not every MTA bounces VERP messages correctly, or consistently.
First, the To: header is checked, then Delivered-To: (Postfix),
Envelope-To: (Exim) and Apparently-To:. Note that there can be multiple
- Delivered-To: headers so we need to search them all (and we don't worry
- about false positives for forwarded email, because only one should match
- `verp_regexp`).
-
- :param mlist: The mailing list being checked.
- :type mlist: `IMailingList`
- :param msg: The message being parsed.
- :type msg: `email.message.Message`
- :return: The set of addresses extracted from the VERP headers.
- :rtype: set of strings
+ headers so we need to search them all
"""
- cre = re.compile(config.mta.verp_regexp, re.IGNORECASE)
- blocal, bdomain = split_email(mlist.bounces_address)
- values = set()
- verp_matches = set()
- for header in ('to', 'delivered-to', 'envelope-to', 'apparently-to'):
- values.update(msg.get_all(header, []))
- for field in values:
- address = parseaddr(field)[1]
- if not address:
- # This header was empty.
- continue
- mo = cre.search(address)
- if not mo:
- # This did not match the VERP regexp.
- continue
- try:
- if blocal != mo.group('bounces'):
- # This was not a bounce to our mailing list.
+
+ def __init__(self, pattern):
+ self._pattern = pattern
+ self._cre = re.compile(pattern, re.IGNORECASE)
+
+ def _get_addresses(self, match_object):
+ raise NotImplementedError
+
+ def get_verp(self, mlist, msg):
+ """Extract a set of VERP bounce addresses.
+
+
+ :param mlist: The mailing list being checked.
+ :type mlist: `IMailingList`
+ :param msg: The message being parsed.
+ :type msg: `email.message.Message`
+ :return: The set of addresses extracted from the VERP headers.
+ :rtype: set of strings
+ """
+ blocal, bdomain = split_email(mlist.bounces_address)
+ values = set()
+ verp_matches = set()
+ for header in ('to', 'delivered-to', 'envelope-to', 'apparently-to'):
+ values.update(msg.get_all(header, []))
+ for field in values:
+ address = parseaddr(field)[1]
+ if not address:
+ # This header was empty.
continue
- original_address = '{0}@{1}'.format(*mo.group('local', 'domain'))
- except IndexError:
- elog.error("verp_regexp doesn't yield the right match groups")
- return set()
- else:
- verp_matches.add(original_address)
- return verp_matches
+ mo = self._cre.search(address)
+ if not mo:
+ # This did not match the VERP regexp.
+ continue
+ try:
+ if blocal != mo.group('bounces'):
+ # This was not a bounce to our mailing list.
+ continue
+ original_address = self._get_address(mo)
+ except IndexError:
+ elog.error('Bad VERP pattern: {0}'.format(self._pattern))
+ return set()
+ else:
+ verp_matches.add(original_address)
+ return verp_matches
+
+
+
+class StandardVERP(_BaseVERPParser):
+ def __init__(self):
+ super(StandardVERP, self).__init__(config.mta.verp_regexp)
+
+ def _get_address(self, match_object):
+ return '{0}@{1}'.format(*match_object.group('local', 'domain'))
+
+
+class ProbeVERP(_BaseVERPParser):
+ def __init__(self):
+ super(ProbeVERP, self).__init__(config.mta.verp_probe_regexp)
+
+ def _get_address(self, match_object):
+ # Extract the token and get the matching address.
+ token = match_object.group('token')
+ op, address, bmsg = getUtility(IPendings).confirm(token)
+ return address