summaryrefslogtreecommitdiff
path: root/Mailman/Queue/BounceRunner.py
diff options
context:
space:
mode:
authorbwarsaw2002-03-26 22:23:46 +0000
committerbwarsaw2002-03-26 22:23:46 +0000
commit2fe1861353e855b08f76a13c0f75e50a6f25009d (patch)
tree916d4fdf76e400730b4a93e07e44057842177b33 /Mailman/Queue/BounceRunner.py
parent6a2313d0b69c49cee21b2a7a6a6f31f5c3393d5f (diff)
downloadmailman-2fe1861353e855b08f76a13c0f75e50a6f25009d.tar.gz
mailman-2fe1861353e855b08f76a13c0f75e50a6f25009d.tar.zst
mailman-2fe1861353e855b08f76a13c0f75e50a6f25009d.zip
Diffstat (limited to 'Mailman/Queue/BounceRunner.py')
-rw-r--r--Mailman/Queue/BounceRunner.py209
1 files changed, 97 insertions, 112 deletions
diff --git a/Mailman/Queue/BounceRunner.py b/Mailman/Queue/BounceRunner.py
index 5013b8e77..9317df4fe 100644
--- a/Mailman/Queue/BounceRunner.py
+++ b/Mailman/Queue/BounceRunner.py
@@ -31,50 +31,43 @@ from Mailman.Logging.Syslog import syslog
class BounceRunner(Runner):
QDIR = mm_cfg.BOUNCEQUEUE_DIR
+ # We only do bounce processing once per minute.
+ SLEEPTIME = 60
def _dispose(self, mlist, msg, msgdata):
outq = get_switchboard(mm_cfg.OUTQUEUE_DIR)
- # BAW: Not all the functions of this qrunner require the list to be
- # locked. Still, it's more convenient to lock it here and now and
- # deal with lock failures in one place.
- try:
- mlist.Lock(timeout=mm_cfg.LIST_LOCK_TIMEOUT)
- except LockFile.TimeOutError:
- # Oh well, try again later
- return 1
- try:
- # There are a few possibilities here:
- #
- # - the message could have been VERP'd in which case, we know
- # exactly who the message was destined for. That make our job
- # easy.
- # - the message could have been originally destined for a list
- # owner, but a list owner address itself bounced. That's bad,
- # and for now we'll simply log the problem and attempt to
- # deliver the message to the site owner.
- #
- # All messages to list-owner@vdom.ain have their envelope sender
- # set to site-owner@dom.ain (no virtual domain). Is this a bounce
- # for a message to a list owner, coming to the site owner?
- if msg.get('to', '') == Utils.get_site_email(extra='-owner'):
- # Send it on to the site owners, but craft the envelope sender
- # to be the -loop detection address, so if /they/ bounce, we
- # won't get stuck in a bounce loop.
- outq.enqueue(msg, msgdata,
- recips=[Utils.get_site_email()],
- envsender=Utils.get_site_email(extra='loop'),
- )
- # List isn't doing bounce processing?
- if not mlist.bounce_processing:
- return
- # If VERPing, the method will take care of things.
- elif self.__verpbounce(mlist, msg):
- mlist.Save()
- return
- # Otherwise do bounce detection of the original message
- elif self.__scanbounce(mlist, msg):
- mlist.Save()
- return
+ # There are a few possibilities here:
+ #
+ # - the message could have been VERP'd in which case, we know exactly
+ # who the message was destined for. That make our job easy.
+ # - the message could have been originally destined for a list owner,
+ # but a list owner address itself bounced. That's bad, and for now
+ # we'll simply log the problem and attempt to deliver the message to
+ # the site owner.
+ #
+ # All messages to list-owner@vdom.ain have their envelope sender set
+ # to site-owner@dom.ain (no virtual domain). Is this a bounce for a
+ # message to a list owner, coming to the site owner?
+ if msg.get('to', '') == Utils.get_site_email(extra='-owner'):
+ # Send it on to the site owners, but craft the envelope sender to
+ # be the -loop detection address, so if /they/ bounce, we won't
+ # get stuck in a bounce loop.
+ outq.enqueue(msg, msgdata,
+ recips=[Utils.get_site_email()],
+ envsender=Utils.get_site_email(extra='loop'),
+ )
+ # List isn't doing bounce processing?
+ if not mlist.bounce_processing:
+ return
+ # Try VERP detection first, since it's quick and easy
+ addrs = verp_bounce(mlist, msg)
+ if not addrs:
+ # That didn't give us anything useful, so try the old fashion
+ # bounce matching modules
+ addrs = BouncerAPI.ScanMessages(mlist, msg)
+ # If that still didn't return us any useful addresses, then send it on
+ # or discard it.
+ if not addrs:
# Does the list owner want to get non-matching bounce messages?
# If not, simply discard it.
if mlist.bounce_unrecognized_goes_to_list_owner:
@@ -91,79 +84,71 @@ class BounceRunner(Runner):
else:
syslog('bounce', 'discarding unrecognized, message-id: %s',
msg.get('message-id', 'n/a'))
- finally:
- mlist.Unlock()
-
- def __verpbounce(self, mlist, msg):
- bmailbox, bdomain = Utils.ParseEmail(mlist.getListAddress('bounces'))
- # Sadly not every MTA bounces VERP messages correctly. Fall back to
- # Delivered-to: 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', '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(mm_cfg.VERP_REGEXP, to)
- if not mo:
- continue # no match of regexp
- try:
- if bmailbox <> mo.group('bounces'):
- continue # not a bounce to our list
- # All is good
- addr = '%s@%s' % mo.group('mailbox', 'host')
- except IndexError:
- syslog('error',
- "VERP_REGEXP doesn't yield the right match groups: %s",
- mm_cfg.VERP_REGEXP)
- return 0
- # Now, if this message has come to the site list, then search not
- # only it, but all the mailing lists on the system, registering a
- # bounce with each for this address.
- if mlist.internal_name() == mm_cfg.MAILMAN_SITE_LIST:
- found = 0
- for listname in Utils.list_names():
- xlist = self._open_list(listname)
- if xlist.isMember(addr):
- unlockp = 0
- if not xlist.Locked():
- xlist.Lock()
- unlockp = 1
- try:
- xlist.registerBounce(addr, msg)
- found = 1
- xlist.Save()
- finally:
- if unlockp:
- xlist.Unlock()
- return found
- elif mlist.isMember(addr):
- mlist.registerBounce(addr, msg)
- return 1
- return 0
-
- def __scanbounce(self, mlist, msg):
+ return
+ # Okay, we have some recognized addresses. We now need to register
+ # the bounces for each of these. If the bounce came to the site list,
+ # then we'll register the address on every list in the system, but
+ # note: this could be VERY resource intensive!
if mlist.internal_name() == mm_cfg.MAILMAN_SITE_LIST:
- found = 0
for listname in Utils.list_names():
xlist = self._open_list(listname)
- unlockp = 0
- if not xlist.Locked():
- xlist.Lock()
- unlockp = 1
- try:
- status = BouncerAPI.ScanMessages(xlist, msg)
- if status:
+ if xlist.isMember(addr):
+ unlockp = 0
+ if not xlist.Locked():
+ try:
+ xlist.Lock(timeout=mm_cfg.LIST_LOCK_TIMEOUT)
+ except LockFile.TimeOutError:
+ # Oh well, forget aboutf this list
+ continue
+ unlockp = 1
+ try:
+ xlist.registerBounce(addr, msg)
found = 1
- xlist.Save()
- finally:
- if unlockp:
- xlist.Unlock()
- return found
+ xlist.Save()
+ finally:
+ if unlockp:
+ xlist.Unlock()
else:
- return BouncerAPI.ScanMessages(mlist, msg)
+ try:
+ mlist.Lock(timeout=mm_cfg.LIST_LOCK_TIMEOUT)
+ except LockFile.TimeOutError:
+ # Oh well, forget about this bounce
+ return
+ try:
+ for addr in addrs:
+ mlist.registerBounce(addr, msg)
+ mlist.Save()
+ finally:
+ mlist.Unlock()
+
+
+
+def verp_bounce(mlist, msg):
+ bmailbox, bdomain = Utils.ParseEmail(mlist.GetBouncesEmail())
+ # Sadly not every MTA bounces VERP messages correctly. Fall back to
+ # Delivered-to: 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', '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(mm_cfg.VERP_REGEXP, to)
+ if not mo:
+ continue # no match of regexp
+ try:
+ if bmailbox <> mo.group('bounces'):
+ continue # not a bounce to our list
+ # All is good
+ addr = '%s@%s' % mo.group('mailbox', 'host')
+ except IndexError:
+ syslog('error',
+ "VERP_REGEXP doesn't yield the right match groups: %s",
+ mm_cfg.VERP_REGEXP)
+ return []
+ return [addr]