Commit 4d8eee97 authored by R David Murray's avatar R David Murray

Merge #17498: Defer SMTPServerDisconnected errors until the next command.

parents 7dc5f0af afb151a5
......@@ -478,6 +478,18 @@ class SMTP:
"""SMTP 'rset' command -- resets session."""
return self.docmd("rset")
def _rset(self):
"""Internal 'rset' command which ignores any SMTPServerDisconnected error.
Used internally in the library, since the server disconnected error
should appear to the application when the *next* command is issued, if
we are doing an internal "safety" reset.
"""
try:
self.rset()
except SMTPServerDisconnected:
pass
def noop(self):
"""SMTP 'noop' command -- doesn't do anything :>"""
return self.docmd("noop")
......@@ -762,7 +774,7 @@ class SMTP:
if code == 421:
self.close()
else:
self.rset()
self._rset()
raise SMTPSenderRefused(code, resp, from_addr)
senderrs = {}
if isinstance(to_addrs, str):
......@@ -776,14 +788,14 @@ class SMTP:
raise SMTPRecipientsRefused(senderrs)
if len(senderrs) == len(to_addrs):
# the server refused all our recipients
self.rset()
self._rset()
raise SMTPRecipientsRefused(senderrs)
(code, resp) = self.data(msg)
if code != 250:
if code == 421:
self.close()
else:
self.rset()
self._rset()
raise SMTPDataError(code, resp)
#if we got here then somebody got our mail
return senderrs
......
......@@ -619,6 +619,7 @@ class SimSMTPChannel(smtpd.SMTPChannel):
data_response = None
rcpt_count = 0
rset_count = 0
disconnect = 0
def __init__(self, extra_features, *args, **kw):
self._extrafeatures = ''.join(
......@@ -684,6 +685,8 @@ class SimSMTPChannel(smtpd.SMTPChannel):
super().smtp_MAIL(arg)
else:
self.push(self.mail_response)
if self.disconnect:
self.close_when_done()
def smtp_RCPT(self, arg):
if self.rcpt_response is None:
......@@ -875,6 +878,16 @@ class SMTPSimTests(unittest.TestCase):
#TODO: add tests for correct AUTH method fallback now that the
#test infrastructure can support it.
# Issue 17498: make sure _rset does not raise SMTPServerDisconnected exception
def test__rest_from_mail_cmd(self):
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
smtp.noop()
self.serv._SMTPchannel.mail_response = '451 Requested action aborted'
self.serv._SMTPchannel.disconnect = True
with self.assertRaises(smtplib.SMTPSenderRefused):
smtp.sendmail('John', 'Sally', 'test message')
self.assertIsNone(smtp.sock)
# Issue 5713: make sure close, not rset, is called if we get a 421 error
def test_421_from_mail_cmd(self):
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
......
......@@ -46,6 +46,11 @@ Core and Builtins
Library
-------
- Issue #17498: Some SMTP servers disconnect after certain errors, violating
strict RFC conformance. Instead of losing the error code when we issue the
subsequent RSET, smtplib now returns the error code and defers raising the
SMTPServerDisconnected error until the next command is issued.
- Issue #17826: setting an iterable side_effect on a mock function created by
create_autospec now works. Patch by Kushal Das.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment