diff options
| author | Barry Warsaw | 2009-10-31 15:14:37 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2009-10-31 15:14:37 -0400 |
| commit | 6ec26d074d923fa83b65b96c4904459d777781f9 (patch) | |
| tree | 50258e956bc1a7f4eaaa989a34180ebecd3a0de1 /src | |
| parent | cac646019303ffe85cfac4c00eca7d44f634a03d (diff) | |
| download | mailman-6ec26d074d923fa83b65b96c4904459d777781f9.tar.gz mailman-6ec26d074d923fa83b65b96c4904459d777781f9.tar.zst mailman-6ec26d074d923fa83b65b96c4904459d777781f9.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/mta/bulk.py | 6 | ||||
| -rw-r--r-- | src/mailman/mta/docs/bulk.txt | 34 | ||||
| -rw-r--r-- | src/mailman/testing/mta.py | 52 |
3 files changed, 74 insertions, 18 deletions
diff --git a/src/mailman/mta/bulk.py b/src/mailman/mta/bulk.py index 21bbd1713..be740c9cd 100644 --- a/src/mailman/mta/bulk.py +++ b/src/mailman/mta/bulk.py @@ -147,4 +147,10 @@ class BulkDelivery: except smtplib.SMTPRecipientsRefused as error: log.error('%s recipients refused: %s', message_id, error) refused = error.recipients + except smtplib.SMTPResponseException as error: + log.error('%s response exception: %s', message_id, error) + refused = dict( + # recipient -> (code, error) + (recipient, (error.smtp_code, error.smtp_error)) + for recipient in recipients) return refused diff --git a/src/mailman/mta/docs/bulk.txt b/src/mailman/mta/docs/bulk.txt index fabc265b6..bcce7e4c7 100644 --- a/src/mailman/mta/docs/bulk.txt +++ b/src/mailman/mta/docs/bulk.txt @@ -338,14 +338,14 @@ local mail server which manages queuing and final delivery. However, even this local mail server can produce delivery failures visible to Mailman in certain situations. -For example, something could be seriously wrong with the mail server and it -could refuse delivery to all recipients. +For example, there could be a problem delivering to any of the specified +recipients. # Tell the mail server to fail on the next 3 RCPT TO commands, one for # each recipient in the following message. - >>> smtpd.err_queue.put('rcpt') - >>> smtpd.err_queue.put('rcpt') - >>> smtpd.err_queue.put('rcpt') + >>> smtpd.err_queue.put(('rcpt', 500)) + >>> smtpd.err_queue.put(('rcpt', 500)) + >>> smtpd.err_queue.put(('rcpt', 500)) >>> recipients = set([ ... 'aperson@example.org', @@ -373,3 +373,27 @@ could refuse delivery to all recipients. >>> messages = list(smtpd.messages) >>> len(messages) 0 + +Or there could be some other problem causing an SMTP response failure. + + # Tell the mail server to register a temporary failure on the next MAIL + # FROM command. + >>> smtpd.err_queue.put(('mail', 450)) + + >>> failures = bulk.deliver(mlist, msg, msgdata) + >>> for address in sorted(failures): + ... print address, failures[address][0], failures[address][1] + aperson@example.org 450 Error: SMTPResponseException + bperson@example.org 450 Error: SMTPResponseException + cperson@example.org 450 Error: SMTPResponseException + + # Tell the mail server to register a permanent failure on the next MAIL + # FROM command. + >>> smtpd.err_queue.put(('mail', 500)) + + >>> failures = bulk.deliver(mlist, msg, msgdata) + >>> for address in sorted(failures): + ... print address, failures[address][0], failures[address][1] + aperson@example.org 500 Error: SMTPResponseException + bperson@example.org 500 Error: SMTPResponseException + cperson@example.org 500 Error: SMTPResponseException diff --git a/src/mailman/testing/mta.py b/src/mailman/testing/mta.py index 81852a24b..d16b9f955 100644 --- a/src/mailman/testing/mta.py +++ b/src/mailman/testing/mta.py @@ -66,13 +66,25 @@ class StatisticsChannel(Channel): def smtp_RCPT(self, arg): """For testing, sometimes cause a non-25x response.""" - if self._server.next_error == 'rcpt': + code = self._server.next_error('rcpt') + if code is None: + # Everything's cool. + Channel.smtp_RCPT(self, arg) + else: # The test suite wants this to fail. The message corresponds to # the exception we expect smtplib.SMTP to raise. - self.push(b'500 Error: SMTPRecipientsRefused') - else: + self.push(b'%d Error: SMTPRecipientsRefused' % code) + + def smtp_MAIL(self, arg): + """For testing, sometimes cause a non-25x response.""" + code = self._server.next_error('mail') + if code is None: # Everything's cool. - Channel.smtp_RCPT(self, arg) + Channel.smtp_MAIL(self, arg) + else: + # The test suite wants this to fail. The message corresponds to + # the exception we expect smtplib.SMTP to raise. + self.push(b'%d Error: SMTPResponseException' % code) @@ -95,18 +107,32 @@ class ConnectionCountingServer(QueueServer): # controller upon request. self._oob_queue = oob_queue self._err_queue = err_queue + self._last_error = None - @property - def next_error(self): - """Return the next error, or None if nothing's on the stack. + def next_error(self, command): + """Return the next error for the SMTP command, if there is one. - :return: The next SMTP command that should error. - :rtype: string (lower cased) or None + :param command: The SMTP command for which an error might be + expected. If the next error matches the given command, the + expected error code is returned. + :type command: string, lower-cased + :return: An SMTP error code + :rtype: integer """ - try: - return self._err_queue.get_nowait() - except Empty: - return None + # If the last error we pulled from the queue didn't match, then we're + # caching it, and it might match this expected error. If there is no + # last error in the cache, get one from the queue now. + if self._last_error is None: + try: + self._last_error = self._err_queue.get_nowait() + except Empty: + # No error is expected + return None + if self._last_error[0] == command: + code = self._last_error[1] + self._last_error = None + return code + return None def handle_accept(self): """See `lazr.smtp.server.Server`.""" |
