[Python-checkins] cpython (merge 3.4 -> default): Merge #17498: Defer SMTPServerDisconnected errors until the next command.

r.david.murray python-checkins at python.org
Tue Apr 15 00:22:54 CEST 2014


http://hg.python.org/cpython/rev/842014ab1c06
changeset:   90303:842014ab1c06
parent:      90300:528234542ff0
parent:      90302:3c441e9ccf87
user:        R David Murray <rdmurray at bitdance.com>
date:        Mon Apr 14 18:22:00 2014 -0400
summary:
  Merge #17498: Defer SMTPServerDisconnected errors until the next command.

files:
  Lib/smtplib.py           |  18 +++++++++++++++---
  Lib/test/test_smtplib.py |  13 +++++++++++++
  Misc/NEWS                |   5 +++++
  3 files changed, 33 insertions(+), 3 deletions(-)


diff --git a/Lib/smtplib.py b/Lib/smtplib.py
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -478,6 +478,18 @@
         """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 @@
             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 @@
                 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
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py
--- a/Lib/test/test_smtplib.py
+++ b/Lib/test/test_smtplib.py
@@ -619,6 +619,7 @@
     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 @@
             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 @@
     #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)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -46,6 +46,11 @@
 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.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list