summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/app/bounces.py17
-rw-r--r--src/mailman/app/tests/test_bounces.py28
-rw-r--r--src/mailman/queue/bounce.py37
3 files changed, 39 insertions, 43 deletions
diff --git a/src/mailman/app/bounces.py b/src/mailman/app/bounces.py
index 62f24d39b..f216c959e 100644
--- a/src/mailman/app/bounces.py
+++ b/src/mailman/app/bounces.py
@@ -45,6 +45,7 @@ from mailman.core.i18n import _
from mailman.email.message import UserNotification
from mailman.interfaces.bounce import IBounceDetector
from mailman.interfaces.listmanager import IListManager
+from mailman.interfaces.membership import ISubscriptionService
from mailman.interfaces.pending import IPendable, IPendings
from mailman.utilities.email import split_email
from mailman.utilities.i18n import make
@@ -132,7 +133,6 @@ class _BaseVERPParser:
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.
@@ -163,7 +163,8 @@ class _BaseVERPParser:
elog.error('Bad VERP pattern: {0}'.format(self._pattern))
return set()
else:
- verp_matches.add(original_address)
+ if original_address is not None:
+ verp_matches.add(original_address)
return verp_matches
@@ -183,8 +184,16 @@ class ProbeVERP(_BaseVERPParser):
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
+ pendable = getUtility(IPendings).confirm(token)
+ if pendable is None:
+ # The token must have already been confirmed, or it may have been
+ # evicted from the database already.
+ return None
+ member_id = pendable['member_id']
+ member = getUtility(ISubscriptionService).get_member(member_id)
+ if member is None:
+ return None
+ return member.address.email
diff --git a/src/mailman/app/tests/test_bounces.py b/src/mailman/app/tests/test_bounces.py
index 47fadeb67..a79b1524c 100644
--- a/src/mailman/app/tests/test_bounces.py
+++ b/src/mailman/app/tests/test_bounces.py
@@ -32,7 +32,7 @@ import unittest
from zope.component import getUtility
-from mailman.app.bounces import StandardVERP, send_probe
+from mailman.app.bounces import StandardVERP, ProbeVERP, send_probe
from mailman.app.lifecycle import create_list
from mailman.app.membership import add_member
from mailman.config import config
@@ -330,14 +330,38 @@ http://example.com/anne@example.com test-owner@example.com""")
class TestProbe(unittest.TestCase):
- """Test VERP probing."""
+ """Test VERP probe parsing."""
layer = ConfigLayer
def setUp(self):
self._mlist = create_list('test@example.com')
+ self._member = add_member(self._mlist, 'anne@example.com',
+ 'Anne Person', 'xxx',
+ DeliveryMode.regular, 'en')
+ self._msg = message_from_string("""\
+From: bouncer@example.com
+To: anne@example.com
+Subject: You bounced
+Message-ID: <first>
+
+""")
+ def test_get_addresses(self):
+ # Be able to extract the probed address from the pending database
+ # based on the token in a probe bounce.
+ token = send_probe(self._member, self._msg)
+ # Simulate a bounce of the message in the virgin queue.
+ message = get_queue_messages('virgin')[0].msg
+ bounce = message_from_string("""\
+To: {0}
+From: mail-daemon@example.com
+""".format(message['From']))
+ addresses = ProbeVERP().get_verp(self._mlist, bounce)
+ self.assertEqual(addresses, set(['anne@example.com']))
+ # The pendable is no longer in the database.
+ self.assertEqual(getUtility(IPendings).confirm(token), None)
diff --git a/src/mailman/queue/bounce.py b/src/mailman/queue/bounce.py
index 35c27c6d6..fb8b0124a 100644
--- a/src/mailman/queue/bounce.py
+++ b/src/mailman/queue/bounce.py
@@ -18,12 +18,10 @@
"""Bounce queue runner."""
import os
-import re
import cPickle
import logging
import datetime
-from email.utils import parseaddr
from lazr.config import as_timedelta
from mailman.app.bounces import StandardVERP
@@ -31,7 +29,6 @@ from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.bounce import Stop
from mailman.queue import Runner
-from mailman.utilities.email import split_email
COMMASPACE = ', '
@@ -228,40 +225,6 @@ class BounceRunner(Runner, BounceMixin):
-def verp_probe(mlist, msg):
- bmailbox, bdomain = split_email(mlist.GetBouncesEmail())
- # Sadly not every MTA bounces VERP messages correctly, or consistently.
- # Fall back to Delivered-To: (Postfix), Envelope-To: (Exim) and
- # Apparently-To:, and then short-circuit if we still don't have anything
- # to work with. 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).
- vals = []
- for header in ('to', 'delivered-to', 'envelope-to', 'apparently-to'):
- vals.extend(msg.get_all(header, []))
- for field in vals:
- to = parseaddr(field)[1]
- if not to:
- continue # empty header
- mo = re.search(config.mta.verp_probe_regexp, to)
- if not mo:
- continue # no match of regexp
- try:
- if bmailbox <> mo.group('bounces'):
- continue # not a bounce to our list
- # Extract the token and see if there's an entry
- token = mo.group('token')
- data = mlist.pend_confirm(token, expunge=False)
- if data is not None:
- return token
- except IndexError:
- elog.error(
- "verp_probe_regexp doesn't yield the right match groups: %s",
- config.mta.verp_probe_regexp)
- return None
-
-
-
def maybe_forward(mlist, msg):
# Does the list owner want to get non-matching bounce messages?
# If not, simply discard it.