Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-flufl.bounce for openSUSE:Factory checked in at 2021-11-20 02:39:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-flufl.bounce (Old) and /work/SRC/openSUSE:Factory/.python-flufl.bounce.new.1895 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-flufl.bounce" Sat Nov 20 02:39:07 2021 rev:3 rq:932383 version:4.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-flufl.bounce/python-flufl.bounce.changes 2020-01-24 14:12:17.518432387 +0100 +++ /work/SRC/openSUSE:Factory/.python-flufl.bounce.new.1895/python-flufl.bounce.changes 2021-11-20 02:40:15.376559185 +0100 @@ -1,0 +2,17 @@ +Wed Nov 17 09:55:03 UTC 2021 - Andreas Schneider <a...@cryptomilk.org> + +- Update to version 4.0 + - Added another string to the stop looking strings in the yahoo + detector. + - Detectors are now run in a defined order and stop on the + first detection. + - Fixed microsoft.py which has been broken forever. + - Added recognition for yet another non-complaint Yahoo DSN. + - Added recognition for a non-compliant DSN from an unknown + MTA. + - Added recognition for a non-compliant opensmtpd DSN with + Action: error. + - Fixed simplmatch.py to not return results that don't resemble + email addresses. (LP: #1859011) + +------------------------------------------------------------------- Old: ---- flufl.bounce-3.0.tar.gz New: ---- flufl.bounce-4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-flufl.bounce.spec ++++++ --- /var/tmp/diff_new_pack.lqyE4m/_old 2021-11-20 02:40:15.920557390 +0100 +++ /var/tmp/diff_new_pack.lqyE4m/_new 2021-11-20 02:40:15.924557377 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-flufl.bounce # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,9 +17,9 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} -%define skip_python2 1 +%define pythons python3 Name: python-flufl.bounce -Version: 3.0 +Version: 4.0 Release: 0 Summary: Email bounce detectors License: Apache-2.0 @@ -28,16 +28,17 @@ Source0: https://files.pythonhosted.org/packages/source/f/flufl.bounce/flufl.bounce-%{version}.tar.gz Source1: https://gitlab.com/warsaw/flufl.bounce/raw/master/LICENSE BuildRequires: %{python_module setuptools} -BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-atpublic Requires: python-zope.interface -BuildArch: noarch # SECTION test requirements BuildRequires: %{python_module atpublic} BuildRequires: %{python_module pytest} +BuildRequires: %{python_module six} BuildRequires: %{python_module zope.interface} # /SECTION +BuildRequires: fdupes +BuildArch: noarch %python_subpackages %description ++++++ flufl.bounce-3.0.tar.gz -> flufl.bounce-4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/LICENSE new/flufl.bounce-4.0/LICENSE --- old/flufl.bounce-3.0/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/LICENSE 2020-01-18 03:13:00.000000000 +0100 @@ -0,0 +1,13 @@ +Copyright 2004-2020 Barry Warsaw + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/MANIFEST.in new/flufl.bounce-4.0/MANIFEST.in --- old/flufl.bounce-3.0/MANIFEST.in 2017-02-17 23:54:44.000000000 +0100 +++ new/flufl.bounce-4.0/MANIFEST.in 2020-01-18 03:13:00.000000000 +0100 @@ -1,4 +1,4 @@ -include *.py COPYING.LESSER MANIFEST.in +include *.py LICENSE MANIFEST.in exclude *.egg global-include *.rst *.txt *.ini *.cfg prune build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/PKG-INFO new/flufl.bounce-4.0/PKG-INFO --- old/flufl.bounce-3.0/PKG-INFO 2017-02-17 23:59:25.000000000 +0100 +++ new/flufl.bounce-4.0/PKG-INFO 2021-06-17 03:02:39.739049700 +0200 @@ -1,10 +1,10 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: flufl.bounce -Version: 3.0 +Version: 4.0 Summary: Email bounce detectors. Home-page: https://fluflbounce.readthedocs.io/en/latest/ -Author: Barry Warsaw -Author-email: ba...@python.org +Maintainer: Barry Warsaw +Maintainer-email: ba...@python.org License: ASLv2 Download-URL: https://pypi.python.org/pypi/flufl.bounce Description: UNKNOWN diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/README.rst new/flufl.bounce-4.0/README.rst --- old/flufl.bounce-3.0/README.rst 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/README.rst 2020-01-18 03:13:00.000000000 +0100 @@ -12,11 +12,11 @@ Authors ======= -`flufl.bounce` is Copyright (C) 2004-2017 Barry Warsaw <ba...@python.org> - -Barry Warsaw <ba...@python.org> -Mark Sapiro <m...@msapiro.net> +`flufl.bounce` is Copyright (C) 2004-2020 Barry Warsaw <ba...@python.org> +| Barry Warsaw <ba...@python.org> +| Mark Sapiro <m...@msapiro.net> +| Licensed under the terms of the Apache Software License, version 2. See LICENSE for details. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/NEWS.rst new/flufl.bounce-4.0/flufl/bounce/NEWS.rst --- old/flufl.bounce-3.0/flufl/bounce/NEWS.rst 2017-02-17 23:52:25.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/NEWS.rst 2021-06-17 02:58:36.000000000 +0200 @@ -2,6 +2,28 @@ NEWS for flufl.bounce ===================== +4.0 (2021-06-16) +================ + * Added another string to the ``stop looking`` strings in the yahoo detector. + (Closes #13) + * Detectors are now run in a defined order and stop on the first detection. + (Closes #12) + +3.0.2 (2021-02-09) +================== + * Fixed microsoft.py which has been broken forever. (Closes #10) + * Added recognition for yet another non-complaint Yahoo DSN. + * Added recognition for a non-compliant DSN from an unknown MTA. + * Fixed missing () in the groupwise detector. + +3.0.1 (2020-01-17) +================== + * Added recognition for a non-compliant opensmtpd DSN with Action: error. + * Caught a possible UnicodeEncodeError in simplematch.py. (Closes #8) + * Fixed simplmatch.py to not return results that don't resemble email + addresses. (LP: #1859011) (Closes #9) + + 3.0 (2017-02-17) ================ * Drop Python 2 support. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/README.rst new/flufl.bounce-4.0/flufl/bounce/README.rst --- old/flufl.bounce-3.0/flufl/bounce/README.rst 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/README.rst 2021-02-10 00:04:50.000000000 +0100 @@ -43,7 +43,7 @@ Copyright ========= -Copyright (C) 2004-2017 Barry A. Warsaw +Copyright (C) 2004-2021 Barry A. Warsaw Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/__init__.py new/flufl.bounce-4.0/flufl/bounce/__init__.py --- old/flufl.bounce-3.0/flufl/bounce/__init__.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/__init__.py 2021-06-17 02:58:36.000000000 +0200 @@ -2,7 +2,7 @@ from public import public -__version__ = '3.0' +__version__ = '4.0' public(__version__=__version__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/_detectors/dsn.py new/flufl.bounce-4.0/flufl/bounce/_detectors/dsn.py --- old/flufl.bounce-3.0/flufl/bounce/_detectors/dsn.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/_detectors/dsn.py 2020-01-18 03:13:00.000000000 +0100 @@ -40,7 +40,8 @@ # Some MTAs have been observed that put comments on the action. if action.startswith('delayed'): address_set = delayed_addresses - elif action.startswith('fail'): + # opensmtpd uses non-compliant Action: error + elif action.startswith('fail') or action.startswith('error'): address_set = failed_addresses else: # Some non-permanent failure, so ignore this block. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/_detectors/groupwise.py new/flufl.bounce-4.0/flufl/bounce/_detectors/groupwise.py --- old/flufl.bounce-3.0/flufl/bounce/_detectors/groupwise.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/_detectors/groupwise.py 2021-02-10 00:01:13.000000000 +0100 @@ -21,7 +21,7 @@ def find_textplain(msg): if msg.get_content_type() == 'text/plain': return msg - if msg.is_multipart: + if msg.is_multipart(): for part in msg.get_payload(): if not isinstance(part, Message): continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/_detectors/microsoft.py new/flufl.bounce-4.0/flufl/bounce/_detectors/microsoft.py --- old/flufl.bounce-3.0/flufl/bounce/_detectors/microsoft.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/_detectors/microsoft.py 2020-01-24 22:45:19.000000000 +0100 @@ -3,6 +3,7 @@ import re from enum import Enum +from flufl.bounce._detectors.simplematch import VALID from flufl.bounce.interfaces import ( IBounceDetector, NoFailures, NoTemporaryFailures) from io import BytesIO @@ -44,6 +45,6 @@ if scre.search(line): state = ParseState.tag_seen elif state is ParseState.tag_seen: - if '@' in line: + if VALID.match(line.strip()): addresses.add(line.strip()) return NoTemporaryFailures, set(addresses) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/_detectors/simplematch.py new/flufl.bounce-4.0/flufl/bounce/_detectors/simplematch.py --- old/flufl.bounce-3.0/flufl/bounce/_detectors/simplematch.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/_detectors/simplematch.py 2020-12-18 19:48:44.000000000 +0100 @@ -28,13 +28,20 @@ # # For compatibility with Python 3, the API requires byte addresses. unquoted = re.sub('=[a-fA-F0-9]{2}', _unquote_match, address) - return unquoted.encode('us-ascii').strip() + try: + return unquoted.encode('us-ascii').strip() + except UnicodeEncodeError: + return b'' def _c(pattern): return re.compile(pattern, re.IGNORECASE) +# Pattern to match any valid email address and not much more. +VALID = _c(rb'^[\x21-\x3d\x3f\x41-\x7e]+@[a-z0-9._]+$') + + # This is a list of tuples of the form # # (start cre, end cre, address cre) @@ -46,167 +53,175 @@ # address that bounced. PATTERNS = [ # sdm.de - (_c('here is your list of failed recipients'), - _c('here is your returned mail'), + (_c(r'here is your list of failed recipients'), + _c(r'here is your returned mail'), _c(r'<(?P<addr>[^>]*)>')), # sz-sb.de, corridor.com, nfg.nl - (_c('the following addresses had'), - _c('transcript of session follows'), + (_c(r'the following addresses had'), + _c(r'transcript of session follows'), _c(r'^ *(\(expanded from: )?<?(?P<addr>[^\s@]+@[^\s@>]+?)>?\)?\s*$')), # robanal.demon.co.uk - (_c('this message was created automatically by mail delivery software'), - _c('original message follows'), - _c('rcpt to:\s*<(?P<addr>[^>]*)>')), + (_c(r'this message was created automatically by mail delivery software'), + _c(r'original message follows'), + _c(r'rcpt to:\s*<(?P<addr>[^>]*)>')), # s1.com (InterScan E-Mail VirusWall NT ???) - (_c('message from interscan e-mail viruswall nt'), - _c('end of message'), - _c('rcpt to:\s*<(?P<addr>[^>]*)>')), + (_c(r'message from interscan e-mail viruswall nt'), + _c(r'end of message'), + _c(r'rcpt to:\s*<(?P<addr>[^>]*)>')), # Smail - (_c('failed addresses follow:'), - _c('message text follows:'), + (_c(r'failed addresses follow:'), + _c(r'message text follows:'), _c(r'\s*(?P<addr>\S+@\S+)')), # newmail.ru - (_c('This is the machine generated message from mail service.'), - _c('--- Below the next line is a copy of the message.'), - _c('<(?P<addr>[^>]*)>')), + (_c(r'This is the machine generated message from mail service.'), + _c(r'--- Below the next line is a copy of the message.'), + _c(r'<(?P<addr>[^>]*)>')), # turbosport.com runs something called `MDaemon 3.5.2' ??? - (_c('The following addresses did NOT receive a copy of your message:'), - _c('--- Session Transcript ---'), - _c('[>]\s*(?P<addr>.*)$')), + (_c(r'The following addresses did NOT receive a copy of your message:'), + _c(r'--- Session Transcript ---'), + _c(r'[>]\s*(?P<addr>.*)$')), # usa.net - (_c('Intended recipient:\s*(?P<addr>.*)$'), - _c('--------RETURNED MAIL FOLLOWS--------'), - _c('Intended recipient:\s*(?P<addr>.*)$')), + (_c(r'Intended recipient:\s*(?P<addr>.*)$'), + _c(r'--------RETURNED MAIL FOLLOWS--------'), + _c(r'Intended recipient:\s*(?P<addr>.*)$')), # hotpop.com - (_c('Undeliverable Address:\s*(?P<addr>.*)$'), - _c('Original message attached'), - _c('Undeliverable Address:\s*(?P<addr>.*)$')), + (_c(r'Undeliverable Address:\s*(?P<addr>.*)$'), + _c(r'Original message attached'), + _c(r'Undeliverable Address:\s*(?P<addr>.*)$')), # Another demon.co.uk format - (_c('This message was created automatically by mail delivery'), - _c('^---- START OF RETURNED MESSAGE ----'), - _c("addressed to '(?P<addr>[^']*)'")), + (_c(r'This message was created automatically by mail delivery'), + _c(r'^---- START OF RETURNED MESSAGE ----'), + _c(r"addressed to '(?P<addr>[^']*)'")), # Prodigy.net full mailbox (_c("User's mailbox is full:"), - _c('Unable to deliver mail.'), - _c("User's mailbox is full:\s*<(?P<addr>[^>]*)>")), + _c(r'Unable to deliver mail.'), + _c(r"User's mailbox is full:\s*<(?P<addr>[^>]*)>")), # Microsoft SMTPSVC - (_c('The email below could not be delivered to the following user:'), - _c('Old message:'), - _c('<(?P<addr>[^>]*)>')), + (_c(r'The email below could not be delivered to the following user:'), + _c(r'Old message:'), + _c(r'<(?P<addr>[^>]*)>')), # Yahoo on behalf of other domains like sbcglobal.net - (_c('Unable to deliver message to the following address\(es\)\.'), - _c('--- Original message follows\.'), - _c('<(?P<addr>[^>]*)>:')), + (_c(r'Unable to deliver message to the following address\(es\)\.'), + _c(r'--- Original message follows\.'), + _c(r'<(?P<addr>[^>]*)>:')), # googlemail.com - (_c('Delivery to the following recipient failed'), - _c('----- Original message -----'), - _c('^\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), + (_c(r'Delivery to the following recipient failed'), + _c(r'----- Original message -----'), + _c(r'^\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), # kundenserver.de - (_c('A message that you sent could not be delivered'), - _c('^---'), - _c('<(?P<addr>[^>]*)>')), + (_c(r'A message that you sent could not be delivered'), + _c(r'^---'), + _c(r'<(?P<addr>[^>]*)>')), # another kundenserver.de - (_c('A message that you sent could not be delivered'), - _c('^---'), - _c('^(?P<addr>[^\s@]+@[^\s@:]+):')), + (_c(r'A message that you sent could not be delivered'), + _c(r'^---'), + _c(r'^(?P<addr>[^\s@]+@[^\s@:]+):')), # thehartford.com / songbird - (_c('Del(i|e)very to the following recipients (failed|was aborted)'), + (_c(r'Del(i|e)very to the following recipients (failed|was aborted)'), # this one may or may not have the original message, but there's nothing # unique to stop on, so stop on the first line of at least 3 characters # that doesn't start with 'D' (to not stop immediately) and has no '@'. # Also note that simple_30.txt contains an apparent misspelling in the # MTA's DSN section. - _c('^[^D][^@]{2,}$'), - _c('^[\s*]*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), + _c(r'^[^D][^@]{2,}$'), + _c(r'^[\s*]*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), # and another thehartfod.com/hartfordlife.com - (_c('^Your message\s*$'), - _c('^because:'), - _c('^\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), + (_c(r'^Your message\s*$'), + _c(r'^because:'), + _c(r'^\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), # kviv.be (InterScan NT) - (_c('^Unable to deliver message to'), + (_c(r'^Unable to deliver message to'), _c(r'\*+\s+End of message\s+\*+'), - _c('<(?P<addr>[^>]*)>')), + _c(r'<(?P<addr>[^>]*)>')), # earthlink.net supported domains - (_c('^Sorry, unable to deliver your message to'), - _c('^A copy of the original message'), - _c('\s*(?P<addr>[^\s@]+@[^\s@]+)\s+')), + (_c(r'^Sorry, unable to deliver your message to'), + _c(r'^A copy of the original message'), + _c(r'\s*(?P<addr>[^\s@]+@[^\s@]+)\s+')), # ademe.fr - (_c('^A message could not be delivered to:'), - _c('^Subject:'), - _c('^\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), + (_c(r'^A message could not be delivered to:'), + _c(r'^Subject:'), + _c(r'^\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), # andrew.ac.jp - (_c('^Invalid final delivery userid:'), - _c('^Original message follows.'), - _c('\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), + (_c(r'^Invalid final delivery userid:'), + _c(r'^Original message follows.'), + _c(r'\s*(?P<addr>[^\s@]+@[^\s@]+)\s*$')), # e500_smtp_mail_serv...@lerctr.org - (_c('------ Failed Recipients ------'), - _c('-------- Returned Mail --------'), - _c('<(?P<addr>[^>]*)>')), + (_c(r'------ Failed Recipients ------'), + _c(r'-------- Returned Mail --------'), + _c(r'<(?P<addr>[^>]*)>')), # cynergycom.net - (_c('A message that you sent could not be delivered'), - _c('^---'), - _c('(?P<addr>[^\s@]+@[^\s@)]+)')), + (_c(r'A message that you sent could not be delivered'), + _c(r'^---'), + _c(r'(?P<addr>[^\s@]+@[^\s@)]+)')), # LSMTP for Windows - (_c('^--> Error description:\s*$'), - _c('^Error-End:'), - _c('^Error-for:\s+(?P<addr>[^\s@]+@[^\s@]+)')), + (_c(r'^--> Error description:\s*$'), + _c(r'^Error-End:'), + _c(r'^Error-for:\s+(?P<addr>[^\s@]+@[^\s@]+)')), # Qmail with a tri-language intro beginning in spanish - (_c('Your message could not be delivered'), - _c('^-'), - _c('<(?P<addr>[^>]*)>:')), + (_c(r'Your message could not be delivered'), + _c(r'^-'), + _c(r'<(?P<addr>[^>]*)>:')), # socgen.com - (_c('Your message could not be delivered to'), - _c('^\s*$'), - _c('(?P<addr>[^\s@]+@[^\s@]+)')), + (_c(r'Your message could not be delivered to'), + _c(r'^\s*$'), + _c(r'(?P<addr>[^\s@]+@[^\s@]+)')), # dadoservice.it - (_c('Your message has encountered delivery problems'), - _c('Your message reads'), - _c('addressed to\s*(?P<addr>[^\s@]+@[^\s@)]+)')), + (_c(r'Your message has encountered delivery problems'), + _c(r'Your message reads'), + _c(r'addressed to\s*(?P<addr>[^\s@]+@[^\s@)]+)')), # gomaps.com - (_c('Did not reach the following recipient'), - _c('^\s*$'), - _c('\s(?P<addr>[^\s@]+@[^\s@]+)')), + (_c(r'Did not reach the following recipient'), + _c(r'^\s*$'), + _c(r'\s(?P<addr>[^\s@]+@[^\s@]+)')), # EYOU MTA SYSTEM - (_c('This is the deliver program at'), - _c('^-'), - _c('^(?P<addr>[^\s@]+@[^\s@<>]+)')), + (_c(r'This is the deliver program at'), + _c(r'^-'), + _c(r'^(?P<addr>[^\s@]+@[^\s@<>]+)')), # A non-standard qmail at ieo.it - (_c('this is the email server at'), - _c('^-'), - _c('\s(?P<addr>[^\s@]+@[^\s@]+)[\s,]')), + (_c(r'this is the email server at'), + _c(r'^-'), + _c(r'\s(?P<addr>[^\s@]+@[^\s@]+)[\s,]')), # pla.net.py (MDaemon.PRO ?) - (_c('- no such user here'), - _c('There is no user'), - _c('^(?P<addr>[^\s@]+@[^\s@]+)\s')), + (_c(r'- no such user here'), + _c(r'There is no user'), + _c(r'^(?P<addr>[^\s@]+@[^\s@]+)\s')), # mxlogic.net - (_c('The following address failed:'), - _c('Included is a copy of the message header'), - _c('<(?P<addr>[^>]+)>')), + (_c(r'The following address failed:'), + _c(r'Included is a copy of the message header'), + _c(r'<(?P<addr>[^>]+)>')), # fastdnsservers.com - (_c('The following recipient\(s\) could not be reached'), - _c('\s*Error Type'), - _c('^(?P<addr>[^\s@]+@[^\s@<>]+)')), + (_c(r'The following recipient\(s\) could not be reached'), + _c(r'\s*Error Type'), + _c(r'^(?P<addr>[^\s@]+@[^\s@<>]+)')), # xxx.com (simple_36.txt) - (_c('Could not deliver message to the following recipient'), - _c('\s*-- The header'), - _c('Failed Recipient: (?P<addr>[^\s@]+@[^\s@<>]+)')), + (_c(r'Could not deliver message to the following recipient'), + _c(r'\s*-- The header'), + _c(r'Failed Recipient: (?P<addr>[^\s@]+@[^\s@<>]+)')), # mta1.service.uci.edu - (_c('Message not delivered to the following addresses'), - _c('Error detail'), - _c('\s*(?P<addr>[^\s@]+@[^\s@)]+)')), + (_c(r'Message not delivered to the following addresses'), + _c(r'Error detail'), + _c(r'\s*(?P<addr>[^\s@]+@[^\s@)]+)')), # Dovecot LDA Over quota MDN (bogus - should be DSN). - (_c('^Your message'), - _c('^Reporting'), - _c('Your message to <?(?P<addr>[^\s<@]+@[^\s@>]+)>? was automatically' + (_c(r'^Your message'), + _c(r'^Reporting'), + _c(r'Your message to <?(?P<addr>[^\s<@]+@[^\s@>]+)>? was automatically' ' rejected')), # mail.ru - (_c('A message that you sent was rejected'), - _c('This is a copy of your message'), - _c('\s(?P<addr>[^\s@]+@[^\s@]+)')), + (_c(r'A message that you sent was rejected'), + _c(r'This is a copy of your message'), + _c(r'\s(?P<addr>[^\s@]+@[^\s@]+)')), # MailEnable - (_c('Message could not be delivered to some recipients.'), - _c('Message headers follow'), - _c('Recipient: \[SMTP:(?P<addr>[^\s@]+@[^\s@]+)\]')), + (_c(r'Message could not be delivered to some recipients.'), + _c(r'Message headers follow'), + _c(r'Recipient: \[SMTP:(?P<addr>[^\s@]+@[^\s@]+)\]')), + # This one is from Yahoo but dosen't fit the yahoo recognizer format + (_c(r'wasn\'t able to deliver the following message'), + _c(r'---Below this line is a copy of the message.'), + _c(r'To: (?P<addr>[^\s@]+@[^\s@]+)')), + # From some unknown MTA + (_c(r'This is a delivery failure notification message'), + _c(r'The problem appears to be'), + _c(r'-- (?P<addr>[^\s@]+@[^\s@]+)')), # Next one goes here... ] @@ -221,6 +236,7 @@ def process(self, msg): """See `IBounceDetector`.""" addresses = set() + new_addresses = set() # MAS: This is a mess. The outer loop used to be over the message # so we only looped through the message once. Looping through the # message for each set of patterns is obviously way more work, but @@ -244,4 +260,7 @@ break if len(addresses) > 0: break - return NoTemporaryFailures, addresses + for address in addresses: + if VALID.match(address): + new_addresses.add(address) + return NoTemporaryFailures, new_addresses diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/_detectors/yahoo.py new/flufl.bounce-4.0/flufl/bounce/_detectors/yahoo.py --- old/flufl.bounce-3.0/flufl/bounce/_detectors/yahoo.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/_detectors/yahoo.py 2021-06-11 18:11:43.000000000 +0200 @@ -19,6 +19,7 @@ acre = re.compile(r'<(?P<addr>[^>]*)>:') ecre = (re.compile(r'--- Original message follows'), re.compile(r'--- Below this line is a copy of the message'), + re.compile(r'---------- Forwarded message ----------'), ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/_scan.py new/flufl.bounce-4.0/flufl/bounce/_scan.py --- old/flufl.bounce-3.0/flufl/bounce/_scan.py 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/_scan.py 2021-06-17 02:58:36.000000000 +0200 @@ -1,29 +1,55 @@ -import os import logging -from flufl.bounce.interfaces import IBounceDetector -from importlib import import_module -from pkg_resources import resource_listdir +from flufl.bounce._detectors import ( + aol, + caiwireless, + dsn, + exchange, + exim, + groupwise, + llnl, + microsoft, + netscape, + postfix, + qmail, + simplematch, + simplewarning, + sina, + smtp32, + yahoo, + yale, + ) from public import public log = logging.getLogger('flufl.bounce') -def _find_detectors(package): - missing = object() - for filename in resource_listdir(package, ''): - basename, extension = os.path.splitext(filename) - if extension != '.py': - continue - module_name = '{}.{}'.format(package, basename) - module = import_module(module_name) - for name in getattr(module, '__all__', []): - component = getattr(module, name, missing) - if component is missing: - log.error('skipping missing __all__ entry: {}'.format(name)) - if IBounceDetector.implementedBy(component): - yield component +def _find_detectors(): + """Get all detectors in order of most specific/authoritative to least""" + yield from [ + # RFC compliant DSNs. + dsn.DSN, + # Detectors for specific providers without heuristics. + exim.Exim, + sina.Sina, + # Provider specific heuristic detectors. + yahoo.Yahoo, + yale.Yale, + smtp32.SMTP32, + postfix.Postfix, + qmail.Qmail, + groupwise.GroupWise, + microsoft.Microsoft, + caiwireless.Caiwireless, + exchange.Exchange, + netscape.Netscape, + aol.AOL, + # Generic and other heuristic detectors. + simplematch.SimpleMatch, + simplewarning.SimpleWarning, + llnl.LLNL, + ] @public @@ -36,8 +62,7 @@ :rtype: set of strings """ permanent_failures = set() - package = 'flufl.bounce._detectors' - for detector_class in _find_detectors(package): + for detector_class in _find_detectors(): log.info('Running detector: {}'.format(detector_class)) try: temporary, permanent = detector_class().process(msg) @@ -45,6 +70,8 @@ log.exception('Exception in detector: {}'.format(detector_class)) raise permanent_failures.update(permanent) + if temporary or permanent: + break return permanent_failures @@ -59,10 +86,11 @@ """ temporary_failures = set() permanent_failures = set() - package = 'flufl.bounce._detectors' - for detector_class in _find_detectors(package): + for detector_class in _find_detectors(): log.info('Running detector: {}'.format(detector_class)) temporary, permanent = detector_class().process(msg) temporary_failures.update(temporary) permanent_failures.update(permanent) + if temporary or permanent: + break return temporary_failures, permanent_failures diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/conf.py new/flufl.bounce-4.0/flufl/bounce/conf.py --- old/flufl.bounce-3.0/flufl/bounce/conf.py 2017-02-16 00:04:30.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/conf.py 2021-02-10 00:06:58.000000000 +0100 @@ -39,7 +39,7 @@ # General information about the project. project = 'flufl.bounce' -copyright = '2004-2017, Barry A. Warsaw' +copyright = '2004-2021, Barry A. Warsaw' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/testing/helpers.py new/flufl.bounce-4.0/flufl/bounce/testing/helpers.py --- old/flufl.bounce-3.0/flufl/bounce/testing/helpers.py 2017-02-17 23:42:59.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/testing/helpers.py 2021-06-11 17:33:22.000000000 +0200 @@ -78,7 +78,7 @@ self.assertEqual(got, self.expected) def loadTestsFromTestCase(self, event): - if event.testCase.__name__ is not 'TestDetectors': + if event.testCase.__name__ != 'TestDetectors': return for data in DATA: event.extraTests.append(Detectors.DataTest(data)) @@ -140,8 +140,12 @@ ('simplematch', 'simple_38.txt', [b'us...@example.com']), ('simplematch', 'simple_39.txt', [b'us...@example.ru']), ('simplematch', 'simple_41.txt', [b'us...@example.com']), + ('simplematch', 'simple_42.txt', []), + ('simplematch', 'simple_43.txt', []), + ('simplematch', 'simple_44.txt', [b'u...@example.com']), ('simplematch', 'bounce_02.txt', [b'us...@example.com']), ('simplematch', 'bounce_03.txt', [b'us...@example.uk']), + ('simplematch', 'yahoo_12.txt', [b'u...@yahoo.com']), # SimpleWarning ('simplewarning', 'simple_03.txt', [b'us...@example.za'], True), ('simplewarning', 'simple_21.txt', [b'us...@example.com'], True), @@ -181,9 +185,12 @@ ('dsn', 'dsn_15.txt', [b'us...@example.com']), ('dsn', 'dsn_16.txt', [b'us...@example.com']), ('dsn', 'dsn_17.txt', [b'us...@example.fi'], True), + ('dsn', 'dsn_18.txt', [b'em...@replaced.net']), # Microsoft Exchange ('exchange', 'microsoft_01.txt', [b'us...@example.com']), ('exchange', 'microsoft_02.txt', [b'us...@example.com']), + # Microsoft's `SMTPSVC'? + ('microsoft', 'microsoft_04.txt', [b'us...@example.com']), # SMTP32 ('smtp32', 'smtp32_01.txt', [b'us...@example.ph']), ('smtp32', 'smtp32_02.txt', [b'us...@example.com']), @@ -235,6 +242,7 @@ b'us...@example.com', b'us...@example.com']), ('yahoo', 'yahoo_11.txt', [b'bad_u...@aol.com']), + ('yahoo', 'yahoo_13.txt', [b'bogus-addr...@example.net']), # sina.com appears to use their own weird SINAEMAIL MTA ('sina', 'sina_01.txt', [b'us...@sina.com', b'us...@sina.com']), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/dsn_18.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/dsn_18.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/dsn_18.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/dsn_18.txt 2020-01-18 03:13:00.000000000 +0100 @@ -0,0 +1,52 @@ +Return-Path: <> +X-Original-To: list.name-bounces@domain.replaced +Delivered-To: list.name-bounces@domain.replaced +Received: from mx.domain.replaced (mx.domain.replaced [177.XXX.XXX.XXX]) + by mailhost.domain.replaced (Postfix) with ESMTP id 6D6C71E8A3 + for <list.name-bounces@domain.replaced>; Thu, 22 Nov 2018 17:56:08 -0200 (BRST) +Received: from mx.domain.replaced (mx.domain.replaced [local]) + by mx.domain.replaced (OpenSMTPD) with ESMTPA id cce9bd49 + for <list.name-bounces@domain.replaced>; + Thu, 22 Nov 2018 17:56:08 -0200 (-02) +Subject: Delivery status notification: error +From: Mailer Daemon <MAILER-DAEMON@mx.domain.replaced> +To: list.name-bounces@domain.replaced +Date: Thu, 22 Nov 2018 17:56:08 -0200 (-02) +MIME-Version: 1.0 +Content-Type: multipart/mixed;boundary="9950749020440539406/mx.domain.replaced" +Message-ID: <f778c4a058120b20@mx.domain.replaced> + +This is a MIME-encapsulated message. + +--9950749020440539406/mx.domain.replaced +Content-Description: Notification +Content-Type: text/plain; charset=us-ascii + + Hi! + + This is the MAILER-DAEMON, please DO NOT REPLY to this email. + + An error has occurred while attempting to deliver a message for + the following list of recipients: + +em...@replaced.net: Domain does not exist + + Below is a copy of the original message: + +--9950749020440539406/mx.domain.replaced +Content-Description: Delivery Report +Content-Type: message/delivery-status + +Reporting-MTA: dns; mx.domain.replaced + +Final-Recipient: rfc822; em...@replaced.net +Action: error +Status: 5.0.0 + +--9950749020440539406/mx.domain.replaced +Content-Description: Message headers +Content-Type: text/rfc822-headers + +[ORIGINAL MESSAGE] + +--9950749020440539406/mx.domain.replaced-- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/microsoft_04.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/microsoft_04.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/microsoft_04.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/microsoft_04.txt 2020-01-24 22:45:19.000000000 +0100 @@ -0,0 +1,49 @@ +Return-Path: <MAILER-DAEMON> +From: System Administrator <postmas...@example.com> +To: list-boun...@example.com +Subject: Undeliverable: RE: Waiver draft results explained +Date: Fri, 4 Oct 2002 17:12:35 -0400 +MIME-Version: 1.0 +X-Mailer: Internet Mail Service (5.5.2656.59) +X-MS-Embedded-Report: +Content-Type: multipart/mixed; + boundary="----_=_NextPart_000_01C26BEA.C2970D56" + +This is a contrived message. the microsoft detector was totally untested +and there was no suitable message for it, so this is reverse engineered +from the code. + +------_=_NextPart_000_01C26BEA.C2970D56 +Content-Type: text/plain; + charset="iso-8859-1" + +Your message + + To: xxx + Subject: RE: Waiver draft results explained + Sent: Fri, 4 Oct 2002 17:10:56 -0400 + +did not reach the following recipient(s): + +c=US;a= ;p=IKON;o=Nexus2;dda:SMTP=us...@example.com; on Fri, 4 Oct 2002 +17:12:28 -0400 + The recipient name is not recognized + The MTS-ID of the original message is: c=us;a= +;p=ikon;l=BKB02-IMS-010210042112TX06SNVK + MSEXCH:IMS:IKON:Nexus2:BKB02-IMS-01 0 (000C05A6) Unknown Recipient + + ----- Transcript of session follows ----- + +bogus line + + us...@example.com + + + +------_=_NextPart_000_01C26BEA.C2970D56 +Content-Type: message/rfc822 + +Message removed + +------_=_NextPart_000_01C26BEA.C2970D56-- + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/simple_42.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/simple_42.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/simple_42.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/simple_42.txt 2020-01-18 03:13:00.000000000 +0100 @@ -0,0 +1,54 @@ +From: Mail Delivery System <mailer-dae...@smtp13.example.com> +To: python-dev-bounces+python=david...@python.org +Content-Type: multipart/report; report-type=delivery-status; boundary=1578513971-eximdsn-503222498 +MIME-Version: 1.0 +Subject: Mail delivery failed: returning message to sender +Message-Id: <e1iphal-0002lo...@smtp13.example.com> +Date: Wed, 08 Jan 2020 20:06:11 +0000 + +--1578513971-eximdsn-503222498 +Content-type: text/plain; charset=us-ascii + +This message was created automatically by mail delivery software. + +A message that you sent could not be delivered to one or more of its +recipients. This is a permanent error. The following address(es) failed: + + david...@gmail.com + (generated from python@david...) + host gmail-smtp-in.l.google.com [108.177.119.27] + SMTP error from remote mail server after end of data: + 550-5.7.1 [94.136.40.141 12] Our system has detected that this message is + 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail, + 550-5.7.1 this message has been blocked. Please visit + 550-5.7.1 https://support.google.com/mail/?p=UnsolicitedMessageError + 550 5.7.1 for more information. c11si2772404eds.65 - gsmtp + +--1578513971-eximdsn-503222498 +Content-type: message/delivery-status + +Reporting-MTA: dns; smtp13.mailcore.me + +Action: failed +Final-Recipient: rfc822;david...@gmail.com +Status: 5.0.0 +Remote-MTA: dns; gmail-smtp-in.l.google.com +Diagnostic-Code: smtp; 550-5.7.1 [94.136.40.141 12] Our system has detected that this message is + 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail, + 550-5.7.1 this message has been blocked. Please visit + 550-5.7.1 https://support.google.com/mail/?p=UnsolicitedMessageError + 550 5.7.1 for more information. c11si2772404eds.65 - gsmtp + +--1578513971-eximdsn-503222498 +Content-type: text/rfc822-headers + +Return-path: <python-dev-bounces+python=david...@python.org> +Received: from mail.python.org ([188.166.95.178]) + by smtp13.mailcore.me with esmtp (Exim 4.92.3) + (envelope-from <python-dev-bounces+python=david...@python.org>) + id 1ipHak-0002Kp-UJ + for python@david...; Wed, 08 Jan 2020 20:06:11 +0000 +X-Comment: Remainder removed, not needed for test. + +--1578513971-eximdsn-503222498-- + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/simple_43.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/simple_43.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/simple_43.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/simple_43.txt 2020-01-18 03:13:00.000000000 +0100 @@ -0,0 +1,344 @@ +From prvs=126700a846=ndr@some.domain Mon Dec 30 19:53:03 2019 +Return-Path: <prvs=126700a846=ndr@some.domain> +X-Original-To: test-a-boun...@listserv.our-domain.de +Delivered-To: test-a-boun...@listserv.our-domain.de +Received: from mx05.our-domain.de (mx05.our-domain.de [10.0.0.215]) + by mx09.our-domain.de (Postfix) with ESMTP id F2BEEE9318 + for <test-a-boun...@listserv.our-domain.de>; + Mon, 30 Dec 2019 19:48:01 +0100 (CET) +X-Env-Sender: prvs=126700a846=ndr@some.domain +From: ndr@some.domain +To: test-a-boun...@listserv.our-domain.de +Date: Mon, 30 Dec 2019 18:46:14 +0000 (GMT) +Message-Id: <qfdc648a0d891023ab@some.domain> +Subject: Mail delivery failed: returning message to sender +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="2458848.14.12" + + +--2458848.14.12 +Content-Type: text/plain; charset=US-ASCII + +This message was created automatically by mail delivery software. + +A message that you sent could not be delivered to one or more of its recipients. + +One or more of the recipients are not a valid user of the system. Please check to be sure the email address is correct. + + + +--2458848.14.12 +Content-Type: message/rfc822 + +Received: from smtp.some.domain (smtp.some.domain [10.0.0.1]) + by VMACSEGCCMC02.localdomain (MTA) with ESMTP id 47mmbl5ltRzKm6s + for <some.name.16565@some.domain>; Mon, 30 Dec 2019 18:46:11 +0000 (GMT) +Received: from mx09.our-domain.de (HELO mx09.our-domain.de) (10.0.0.219) + by server-28.someother.domain with ECDHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 30 Dec 2019 18:45:59 -0000 +Received: from mx09.our-domain.de (localhost [127.0.0.1]) + by mx09.our-domain.de (Postfix) with ESMTP id CC58AAC993; + Mon, 30 Dec 2019 19:39:05 +0100 (CET) +X-Original-To: tes...@listserv.our-domain.de +Delivered-To: tes...@listserv.our-domain.de +Received: from mx04.our-domain.de (mx04.our-domain.de [10.0.0.214]) + by mx09.our-domain.de (Postfix) with ESMTP id 6EFD1A9DA7 + for <tes...@listserv.our-domain.de>; + Mon, 30 Dec 2019 19:18:16 +0100 (CET) +To: "(Info) Test A" + <tes...@listserv.our-domain.de> +From: List_Owner <list-ow...@our-domain.de> +Message-ID: <ea184277-2081-cdae-1478-0639bb427...@our-domain.de> +Date: Mon, 30 Dec 2019 19:17:22 +0100 +User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:68.0) Gecko/20100101 + Thunderbird/68.3.0 +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------80AB81809DF608AE8D353110" +X-Mailman-Approved-At: Mon, 30 Dec 2019 19:38:57 +0100 +Subject: [Test-A] Subject +X-BeenThere: tes...@listserv.our-domain.de +X-Mailman-Version: 2.1.15 +Precedence: list +List-Id: Test-A + <test-a.listserv.our-domain.de> +List-Unsubscribe: <https://listserv.our-domain.de/mailman/options/test-a>, + <mailto:test-a-requ...@listserv.our-domain.de?subject=unsubscribe> +List-Archive: <https://listserv.our-domain.de/mailman/private/test-a/> +List-Post: <mailto:tes...@listserv.our-domain.de> +List-Help: <mailto:test-a-requ...@listserv.our-domain.de?subject=help> +List-Subscribe: <https://listserv.our-domain.de/mailman/listinfo/test-a>, + <mailto:test-a-requ...@listserv.our-domain.de?subject=subscribe> +Reply-To: list-ow...@our-domain.de +Errors-To: test-a-boun...@listserv.our-domain.de +Sender: "Test-A" + <test-a-boun...@listserv.our-domain.de> + +This is a multi-part message in MIME format. +--------------80AB81809DF608AE8D353110 +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Transfer-Encoding: 8bit + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim +veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea +commodo consequat. Duis aute irure dolor in reprehenderit in voluptate +velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint +occaecat cupidatat non proident, sunt in culpa qui officia deserunt +mollit anim id est laborum. + + +__________________________________________________________________________________________ +Footer +__________________________________________________________________________________________ +--------------80AB81809DF608AE8D353110 +Content-Type: application/pdf; name=dummy.pdf +Content-Disposition: attachment; size=13264; filename=dummy.pdf +Content-Transfer-Encoding: base64 + +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 +USRuPC6uZTI6hUkHjGBBoU5ADiZ+I8AZj6cuEx8zjpm4eFQITuTkV/uewQl+EA3PcXwkUimfl/nI +xJJC8fwSnKisjfV4PhV9JKegWvwUQR1YRV8Y650p5QAOFx4uP1w3VjhWPlZnFD+08BCQtofEURqp +fEihoCMw4wiAwW6K/XQB9N0fycuXiscE4HB0OwLyN17ow6526L8jA6fPOjagSw1I8cGZgMTwAYoR +xyYdoRmmkM4iJ0OSRSr8P1jbNhMKZW5kc3RyZWFtCmVuZG9iagoKNiAwIG9iagoxMDgyNQplbmRv +YmoKCjcgMCBvYmoKPDwvVHlwZS9Gb250RGVzY3JpcHRvci9Gb250TmFtZS9CQUFBQUErQXJpYWwt +Qm9sZE1UCi9GbGFncyA0Ci9Gb250QkJveFstNjI3IC0zNzYgMjAwMCAxMDExXS9JdGFsaWNBbmds +ZSAwCi9Bc2NlbnQgOTA1Ci9EZXNjZW50IDIxMQovQ2FwSGVpZ2h0IDEwMTAKL1N0ZW1WIDgwCi9G +b250RmlsZTIgNSAwIFI+PgplbmRvYmoKCjggMCBvYmoKPDwvTGVuZ3RoIDI3Mi9GaWx0ZXIvRmxh +dGVEZWNvZGU+PgpzdHJlYW0KeJxdkc9uhCAQxu88BcftYQNadbuJMdm62cRD/6S2D6AwWpKKBPHg +2xcG2yY9QH7DzDf5ZmB1c220cuzVzqIFRwelpYVlXq0A2sOoNElSKpVwe4S3mDpDmNe22+JgavQw +lyVhbz63OLvRw0XOPdwR9mIlWKVHevioWx+3qzFfMIF2lJOqohIG3+epM8/dBAxVx0b6tHLb0Uv+ +Ct43AzTFOIlWxCxhMZ0A2+kRSMl5RcvbrSKg5b9cskv6QXx21pcmvpTzLKs8p8inPPA9cnENnMX3 +c+AcOeWBC+Qc+RT7FIEfohb5HBm1l8h14MfIOZrc3QS7YZ8/a6BitdavAJeOs4eplYbffzGzCSo8 +3zuVhO0KZW5kc3RyZWFtCmVuZG9iagoKOSAwIG9iago8PC9UeXBlL0ZvbnQvU3VidHlwZS9UcnVl +VHlwZS9CYXNlRm9udC9CQUFBQUErQXJpYWwtQm9sZE1UCi9GaXJzdENoYXIgMAovTGFzdENoYXIg +MTEKL1dpZHRoc1s3NTAgNzIyIDYxMCA4ODkgNTU2IDI3NyA2NjYgNjEwIDMzMyAyNzcgMjc3IDU1 +NiBdCi9Gb250RGVzY3JpcHRvciA3IDAgUgovVG9Vbmljb2RlIDggMCBSCj4+CmVuZG9iagoKMTAg +MCBvYmoKPDwKL0YxIDkgMCBSCj4+CmVuZG9iagoKMTEgMCBvYmoKPDwvRm9udCAxMCAwIFIKL1By +b2NTZXRbL1BERi9UZXh0XT4+CmVuZG9iagoKMSAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDQg +MCBSL1Jlc291cmNlcyAxMSAwIFIvTWVkaWFCb3hbMCAwIDU5NSA4NDJdL0dyb3VwPDwvUy9UcmFu +c3BhcmVuY3kvQ1MvRGV2aWNlUkdCL0kgdHJ1ZT4+L0NvbnRlbnRzIDIgMCBSPj4KZW5kb2JqCgox +MiAwIG9iago8PC9Db3VudCAxL0ZpcnN0IDEzIDAgUi9MYXN0IDEzIDAgUgo+PgplbmRvYmoKCjEz +IDAgb2JqCjw8L1RpdGxlPEZFRkYwMDQ0MDA3NTAwNkQwMDZEMDA3OTAwMjAwMDUwMDA0NDAwNDYw +MDIwMDA2NjAwNjkwMDZDMDA2NT4KL0Rlc3RbMSAwIFIvWFlaIDU2LjcgNzczLjMgMF0vUGFyZW50 +IDEyIDAgUj4+CmVuZG9iagoKNCAwIG9iago8PC9UeXBlL1BhZ2VzCi9SZXNvdXJjZXMgMTEgMCBS +Ci9NZWRpYUJveFsgMCAwIDU5NSA4NDIgXQovS2lkc1sgMSAwIFIgXQovQ291bnQgMT4+CmVuZG9i +agoKMTQgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL1BhZ2VzIDQgMCBSCi9PdXRsaW5lcyAxMiAwIFIK +Pj4KZW5kb2JqCgoxNSAwIG9iago8PC9BdXRob3I8RkVGRjAwNDUwMDc2MDA2MTAwNkUwMDY3MDA2 +NTAwNkMwMDZGMDA3MzAwMjAwMDU2MDA2QzAwNjEwMDYzMDA2ODAwNkYwMDY3MDA2OTAwNjEwMDZF +MDA2RTAwNjkwMDczPgovQ3JlYXRvcjxGRUZGMDA1NzAwNzIwMDY5MDA3NDAwNjUwMDcyPgovUHJv +ZHVjZXI8RkVGRjAwNEYwMDcwMDA2NTAwNkUwMDRGMDA2NjAwNjYwMDY5MDA2MzAwNjUwMDJFMDA2 +RjAwNzIwMDY3MDAyMDAwMzIwMDJFMDAzMT4KL0NyZWF0aW9uRGF0ZShEOjIwMDcwMjIzMTc1NjM3 +KzAyJzAwJyk+PgplbmRvYmoKCnhyZWYKMCAxNgowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMTE5 +OTcgMDAwMDAgbiAKMDAwMDAwMDAxOSAwMDAwMCBuIAowMDAwMDAwMjI0IDAwMDAwIG4gCjAwMDAw +MTIzMzAgMDAwMDAgbiAKMDAwMDAwMDI0NCAwMDAwMCBuIAowMDAwMDExMTU0IDAwMDAwIG4gCjAw +MDAwMTExNzYgMDAwMDAgbiAKMDAwMDAxMTM2OCAwMDAwMCBuIAowMDAwMDExNzA5IDAwMDAwIG4g +CjAwMDAwMTE5MTAgMDAwMDAgbiAKMDAwMDAxMTk0MyAwMDAwMCBuIAowMDAwMDEyMTQwIDAwMDAw +IG4gCjAwMDAwMTIxOTYgMDAwMDAgbiAKMDAwMDAxMjQyOSAwMDAwMCBuIAowMDAwMDEyNDk0IDAw +MDAwIG4gCnRyYWlsZXIKPDwvU2l6ZSAxNi9Sb290IDE0IDAgUgovSW5mbyAxNSAwIFIKL0lEIFsg +PEY3RDc3QjNEMjJCOUY5MjgyOUQ0OUZGNUQ3OEI4RjI4Pgo8RjdENzdCM0QyMkI5RjkyODI5RDQ5 +RkY1RDc4QjhGMjg+IF0KPj4Kc3RhcnR4cmVmCjEyNzg3CiUlRU9GCg== +--------------80AB81809DF608AE8D353110 +Content-Type: text/plain; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline + +_______________________________________________ +Test-A mailing list +tes...@listserv.our-domain.de +subscribe or unsubscribe newsletter +https://listserv.our-domain.de/mailman/listinfo/test-a + +--------------80AB81809DF608AE8D353110-- + +--2458848.14.12-- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/simple_44.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/simple_44.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/simple_44.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/simple_44.txt 2020-12-18 19:27:23.000000000 +0100 @@ -0,0 +1,28 @@ +Subject: [Postmaster] Email Delivery Failure +Message-Id: <111195647-1608276241...@example.com> +Date: Fri, 18 Dec 2020 09:24:01 +0200 +From: "Mail Delivery System" <mailer-dae...@example.com> +To: "dns-operations" <dns-operations-boun...@example.net> +X-Mimecast-Originator: <> +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +X-MIME-Autoconverted: from quoted-printable to 8bit by example.net id 0BI7O1sk026573 + +This is a delivery failure notification message indicating that +an email dns-operations-boun...@example.net addressed to email address : +-- u...@example.com + +With subject Re: [dns-operations] Monitoring for impending expiration of domains? sent on the Mon, 14 Dec 2020 11:30:37 +0100 (CET) +could not be delivered. The problem appears to be : +-- Recipient server unavailable or busy + +Additional information follows : +-- 4.4.4 Temporary server error. Please try again later ATTR5 [VE1EUR02FT049.eop-EUR02.prod.protection.outlook.com] + +This condition occurred after 30 attempt(s) to deliver over +a period of 92 hour(s) and 52 minute(s). + +If you sent the email to multiple recipients, you will receive one +of these messages for each one which failed delivery, otherwise +they have been sent. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/yahoo_12.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/yahoo_12.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/yahoo_12.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/yahoo_12.txt 2020-04-24 23:52:51.000000000 +0200 @@ -0,0 +1,18 @@ +From: mailer-dae...@yahoo.com +To: list-boun...@lists.example.org +Message-ID: <1724157855.37526491587724620658.javamail.ya...@mpq204.consmr.mail.bf2.yahoo.com> +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: 7bit +Message-ID-Hash: NMFBS7K2KRA44XW6KCW6CW6NNKCXESHM +X-Message-ID-Hash: NMFBS7K2KRA44XW6KCW6CW6NNKCXESHM +X-MailFrom: mailer-dae...@yahoo.com + +I'm afraid I wasn't able to deliver the following message. +This is a permanent error; I've given up. Sorry it didn't work out. + +Subject: [List] Re: Name for MP3 Folder +To: u...@yahoo.com + +---Below this line is a copy of the message. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/data/yahoo_13.txt new/flufl.bounce-4.0/flufl/bounce/tests/data/yahoo_13.txt --- old/flufl.bounce-3.0/flufl/bounce/tests/data/yahoo_13.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/data/yahoo_13.txt 2021-06-11 17:55:07.000000000 +0200 @@ -0,0 +1,51 @@ +Return-Path: <> +Received: from sonic.gate.mail.ne1.yahoo.com by sonic303.consmr.mail.ne1.yahoo.com with HTTP; Fri, 11 Jun 2021 13:59:55 +0000 +Date: Fri, 11 Jun 2021 13:59:55 +0000 +From: mailer-dae...@yahoo.com +To: user_n...@yahoo.com +Message-ID: + <278929949.490718.1623419995...@sonic303.consmr.mail.ne1.yahoo.com> +Subject: Failure Notice +Content-Type: multipart/report; report-type=delivery-status; + boundary="-=Part.77cde.7cbe8eccd6310fd8.179fb5f46a7.49c125a19f0a1035=-" +Content-Length: 5236 + +---=Part.77cde.7cbe8eccd6310fd8.179fb5f46a7.49c125a19f0a1035=- +Content-Type: text/plain; charset=UTF-8 + +Sorry, we were unable to deliver your message to the following address. + +<bogus-addr...@example.net>: +550: 5.1.1 <bogus-addr...@example.net>: Recipient address rejected: User unknown in local recipient table + +---------- Forwarded message ---------- + +---=Part.77cde.7cbe8eccd6310fd8.179fb5f46a7.49c125a19f0a1035=- +Content-Type: message/rfc822 + +X-Sonic-MF: <user_n...@yahoo.com> +Received: from sonic.gate.mail.ne1.yahoo.com by sonic303.consmr.mail.ne1.yahoo.com with HTTP; Fri, 11 Jun 2021 13:59:55 +0000 +Received: by kubenode558.mail-prod1.omega.gq1.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 007ece6be172ed81332d038abbd95120; + Fri, 11 Jun 2021 13:57:53 +0000 (UTC) +To: bogus-addr...@example.net +From: Some User <user_n...@yahoo.com> +Subject: bounce me +Message-ID: <130907fb-848c-d154-8e59-ed1e08319...@yahoo.com> +Date: Fri, 11 Jun 2021 06:57:50 -0700 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) + Gecko/20100101 Thunderbird/78.11.0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Language: en-US +Content-Transfer-Encoding: 7bit +References: <130907fb-848c-d154-8e59-ed1e08319fcf....@yahoo.com> +X-Mailer: WebService/1.1.18368 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo +Content-Length: 163 + +this should bounce. + +This is somewhat bogus and contrived to test the separator. +-- +<user_n...@yahoo.com>: My sig + +---=Part.77cde.7cbe8eccd6310fd8.179fb5f46a7.49c125a19f0a1035=--- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl/bounce/tests/test_detectors.py new/flufl.bounce-4.0/flufl/bounce/tests/test_detectors.py --- old/flufl.bounce-3.0/flufl/bounce/tests/test_detectors.py 2017-02-17 23:42:59.000000000 +0100 +++ new/flufl.bounce-4.0/flufl/bounce/tests/test_detectors.py 2021-06-17 02:58:36.000000000 +0200 @@ -7,7 +7,7 @@ from flufl.bounce._detectors.caiwireless import Caiwireless from flufl.bounce._detectors.microsoft import Microsoft from flufl.bounce._detectors.smtp32 import SMTP32 -from flufl.bounce._scan import scan_message +from flufl.bounce._scan import all_failures, scan_message from pkg_resources import resource_stream @@ -61,6 +61,36 @@ self.assertEqual(scan_message(msg), set([b'bbb...@example.com'])) +class TestScanAllDetectors(unittest.TestCase): + # Ensure that _scan runs detectors. + def test_llnl(self): + with closing(resource_stream('flufl.bounce.tests.data', + 'llnl_01.txt')) as fp: + msg = parse(fp) + self.assertEqual(scan_message(msg), set([b'us...@example.gov'])) + temporary, permanent = all_failures(msg) + self.assertEqual(temporary, set()) + self.assertEqual(permanent, set([b'us...@example.gov'])) + + def test_unrecognized(self): + with closing(resource_stream('flufl.bounce.tests.data', + 'dumbass_01.txt')) as fp: + msg = parse(fp) + self.assertEqual(scan_message(msg), set()) + temporary, permanent = all_failures(msg) + self.assertEqual(temporary, set()) + self.assertEqual(permanent, set()) + + def test_warning(self): + with closing(resource_stream('flufl.bounce.tests.data', + 'simple_03.txt')) as fp: + msg = parse(fp) + self.assertEqual(scan_message(msg), set()) + temporary, permanent = all_failures(msg) + self.assertEqual(temporary, set([b'us...@example.za'])) + self.assertEqual(permanent, set()) + + class TestDetectors(unittest.TestCase): # This is a pure placeholder for the nose2 plugin in # flufl.bounce.testing.helpers.Detectors. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl.bounce.egg-info/PKG-INFO new/flufl.bounce-4.0/flufl.bounce.egg-info/PKG-INFO --- old/flufl.bounce-3.0/flufl.bounce.egg-info/PKG-INFO 2017-02-17 23:59:25.000000000 +0100 +++ new/flufl.bounce-4.0/flufl.bounce.egg-info/PKG-INFO 2021-06-17 03:02:38.000000000 +0200 @@ -1,10 +1,10 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: flufl.bounce -Version: 3.0 +Version: 4.0 Summary: Email bounce detectors. Home-page: https://fluflbounce.readthedocs.io/en/latest/ -Author: Barry Warsaw -Author-email: ba...@python.org +Maintainer: Barry Warsaw +Maintainer-email: ba...@python.org License: ASLv2 Download-URL: https://pypi.python.org/pypi/flufl.bounce Description: UNKNOWN diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/flufl.bounce.egg-info/SOURCES.txt new/flufl.bounce-4.0/flufl.bounce.egg-info/SOURCES.txt --- old/flufl.bounce-3.0/flufl.bounce.egg-info/SOURCES.txt 2017-02-17 23:59:25.000000000 +0100 +++ new/flufl.bounce-4.0/flufl.bounce.egg-info/SOURCES.txt 2021-06-17 03:02:39.000000000 +0200 @@ -1,3 +1,4 @@ +LICENSE MANIFEST.in README.rst coverage.ini @@ -66,6 +67,7 @@ flufl/bounce/tests/data/dsn_15.txt flufl/bounce/tests/data/dsn_16.txt flufl/bounce/tests/data/dsn_17.txt +flufl/bounce/tests/data/dsn_18.txt flufl/bounce/tests/data/dumbass_01.txt flufl/bounce/tests/data/exim_01.txt flufl/bounce/tests/data/groupwise_01.txt @@ -76,6 +78,7 @@ flufl/bounce/tests/data/microsoft_01.txt flufl/bounce/tests/data/microsoft_02.txt flufl/bounce/tests/data/microsoft_03.txt +flufl/bounce/tests/data/microsoft_04.txt flufl/bounce/tests/data/netscape_01.txt flufl/bounce/tests/data/newmailru_01.txt flufl/bounce/tests/data/postfix_01.txt @@ -133,6 +136,9 @@ flufl/bounce/tests/data/simple_39.txt flufl/bounce/tests/data/simple_40.txt flufl/bounce/tests/data/simple_41.txt +flufl/bounce/tests/data/simple_42.txt +flufl/bounce/tests/data/simple_43.txt +flufl/bounce/tests/data/simple_44.txt flufl/bounce/tests/data/sina_01.txt flufl/bounce/tests/data/smtp32_01.txt flufl/bounce/tests/data/smtp32_02.txt @@ -152,4 +158,6 @@ flufl/bounce/tests/data/yahoo_09.txt flufl/bounce/tests/data/yahoo_10.txt flufl/bounce/tests/data/yahoo_11.txt +flufl/bounce/tests/data/yahoo_12.txt +flufl/bounce/tests/data/yahoo_13.txt flufl/bounce/tests/data/yale_01.txt \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/setup.cfg new/flufl.bounce-4.0/setup.cfg --- old/flufl.bounce-3.0/setup.cfg 2017-02-17 23:59:25.000000000 +0100 +++ new/flufl.bounce-4.0/setup.cfg 2021-06-17 03:02:39.739791900 +0200 @@ -5,7 +5,6 @@ upload_dir = build/sphinx/html [egg_info] -tag_svn_revision = 0 -tag_date = 0 tag_build = +tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/flufl.bounce-3.0/tox.ini new/flufl.bounce-4.0/tox.ini --- old/flufl.bounce-3.0/tox.ini 2017-02-17 23:13:22.000000000 +0100 +++ new/flufl.bounce-4.0/tox.ini 2020-11-15 00:43:32.000000000 +0100 @@ -1,5 +1,5 @@ [tox] -envlist = {py34,py35,py36}-{cov,nocov,diffcov},qa,docs +envlist = {py35,py36,py37,py38,py39}-{cov,nocov,diffcov},qa,docs recreate = True skip_missing_interpreters = True