summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2009-10-31 15:14:37 -0400
committerBarry Warsaw2009-10-31 15:14:37 -0400
commit6ec26d074d923fa83b65b96c4904459d777781f9 (patch)
tree50258e956bc1a7f4eaaa989a34180ebecd3a0de1 /src
parentcac646019303ffe85cfac4c00eca7d44f634a03d (diff)
downloadmailman-6ec26d074d923fa83b65b96c4904459d777781f9.tar.gz
mailman-6ec26d074d923fa83b65b96c4904459d777781f9.tar.zst
mailman-6ec26d074d923fa83b65b96c4904459d777781f9.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/mta/bulk.py6
-rw-r--r--src/mailman/mta/docs/bulk.txt34
-rw-r--r--src/mailman/testing/mta.py52
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`."""