From a72eaf5c9ac4e34c5feec0dbadadb7fa578b5886 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 4 Feb 2025 15:39:01 +0100 Subject: [PATCH 1/3] Closes SMTP connection on 421 during data Fixes a minor issue in smtlib.SMTP.sendmail that leads to SMTP client connections not being closed when a server responds with 421 during a DATA command. The existing 421 handling covers almost all cases, but as the DATA command method already handles some error response codes, the 421 is masked for sendmail. --- Lib/smtplib.py | 9 ++++++++- Lib/test/test_smtplib.py | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 84d6d858e7dec1..d86af9a6a79fbd 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -886,7 +886,14 @@ def sendmail(self, from_addr, to_addrs, msg, mail_options=(), # the server refused all our recipients self._rset() raise SMTPRecipientsRefused(senderrs) - (code, resp) = self.data(msg) + try: + (code, resp) = self.data(msg) + except SMTPDataError as ex: + if ex.smtp_code == 421: + self.close() + else: + self._rset() + raise if code != 250: if code == 421: self.close() diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 4c9fc14bd43f54..0450f945135243 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -1259,6 +1259,10 @@ def test__rest_from_mail_cmd(self): smtp.sendmail('John', 'Sally', 'test message') self.assertIsNone(smtp.sock) + # The following 421 response tests for sendmail ensure that sendmail handles + # 421 respones correctly by closing the connection. sendmail has to take + # care of this, as it wraps a mail transaction for users. + # 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', @@ -1297,6 +1301,16 @@ def found_terminator(self): self.assertIsNone(smtp.sock) self.assertEqual(self.serv._SMTPchannel.rcpt_count, 0) + def test_421_during_data_cmd(self): + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', + timeout=support.LOOPBACK_TIMEOUT) + smtp.noop() + self.serv._SMTPchannel.data_response = '421 closing' + with self.assertRaises(smtplib.SMTPDataError): + smtp.sendmail('John@foo.org', ['Sally@foo.org'], 'test message') + self.assertIsNone(smtp.sock) + self.assertEqual(self.serv._SMTPchannel.rcpt_count, 0) + def test_smtputf8_NotSupportedError_if_no_server_support(self): smtp = smtplib.SMTP( HOST, self.port, local_hostname='localhost', From 046dfbf924fd37cb9a1c90a8e55cd2b064c4d8da Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 22 Apr 2025 14:53:49 +0200 Subject: [PATCH 2/3] Fixes trailing whitespaces in smtplib and test file --- Lib/smtplib.py | 2 +- Lib/test/test_smtplib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index d86af9a6a79fbd..e79d2e752cf9f3 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -891,7 +891,7 @@ def sendmail(self, from_addr, to_addrs, msg, mail_options=(), except SMTPDataError as ex: if ex.smtp_code == 421: self.close() - else: + else: self._rset() raise if code != 250: diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 0450f945135243..6a5d9046684859 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -1260,7 +1260,7 @@ def test__rest_from_mail_cmd(self): self.assertIsNone(smtp.sock) # The following 421 response tests for sendmail ensure that sendmail handles - # 421 respones correctly by closing the connection. sendmail has to take + # 421 respones correctly by closing the connection. sendmail has to take # care of this, as it wraps a mail transaction for users. # Issue 5713: make sure close, not rset, is called if we get a 421 error From b4ac209ae405f28ca27f3c70ca60c5aeec48939e Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 20 May 2025 15:45:26 +0200 Subject: [PATCH 3/3] Adds NEWS entry for smtplib improved 421 handling --- .../Library/2025-05-20-15-39-55.gh-issue-132796.UJXDBR.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-05-20-15-39-55.gh-issue-132796.UJXDBR.rst diff --git a/Misc/NEWS.d/next/Library/2025-05-20-15-39-55.gh-issue-132796.UJXDBR.rst b/Misc/NEWS.d/next/Library/2025-05-20-15-39-55.gh-issue-132796.UJXDBR.rst new file mode 100644 index 00000000000000..fadf346490a85b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-20-15-39-55.gh-issue-132796.UJXDBR.rst @@ -0,0 +1,3 @@ +Improve handling of 421 SMTP responses in :meth:`smtplib.SMTP.sendmail` by +covering a previously missing case in which 421 occurs while sending a DATA +command.