From 1679e1a30e73a52c551533dfcc0a845764bf2b4e Mon Sep 17 00:00:00 2001 From: Mazin Sharaf Date: Mon, 17 Aug 2026 19:11:21 +1000 Subject: [PATCH 1/7] Improve error handling in SMTP email logging Refactor email message handling in SMTP logging to ensure proper cleanup and error handling. --- Lib/logging/handlers.py | 67 +++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index fb6b5f3b411b227..c751f99682b8823 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1121,36 +1121,43 @@ def emit(self, record): if not port: port = smtplib.SMTP_PORT smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout) - msg = EmailMessage() - msg['From'] = self.fromaddr - msg['To'] = ','.join(self.toaddrs) - msg['Subject'] = self.getSubject(record) - msg['Date'] = email.utils.localtime() - msg.set_content(self.format(record)) - if self.username: - if self.secure is not None: - import ssl - - try: - keyfile = self.secure[0] - except IndexError: - keyfile = None - - try: - certfile = self.secure[1] - except IndexError: - certfile = None - - context = ssl._create_stdlib_context( - certfile=certfile, keyfile=keyfile - ) - smtp.ehlo() - smtp.starttls(context=context) - smtp.ehlo() - smtp.login(self.username, self.password) - smtp.send_message(msg) - smtp.quit() - except Exception: + try: + msg = EmailMessage() + msg['From'] = self.fromaddr + msg['To'] = ','.join(self.toaddrs) + msg['Subject'] = self.getSubject(record) + msg['Date'] = email.utils.localtime() + msg.set_content(self.format(record)) + if self.username: + if self.secure is not None: + import ssl + + try: + keyfile = self.secure[0] + except IndexError: + keyfile = None + + try: + certfile = self.secure[1] + except IndexError: + certfile = None + + context = ssl._create_stdlib_context( + certfile=certfile, keyfile=keyfile + ) + smtp.ehlo() + smtp.starttls(context=context) + smtp.ehlo() + smtp.login(self.username, self.password) + smtp.send_message(msg) + smtp.quit() + except Exception: + try: + smtp.close() + except Exception: + pass + raise + except Exception: self.handleError(record) class NTEventLogHandler(logging.Handler): From b349e4efb28ab016d639fe2f93dd799f25110937 Mon Sep 17 00:00:00 2001 From: Mazin Sharaf Date: Mon, 17 Aug 2026 19:38:34 +1000 Subject: [PATCH 2/7] Fix indentation in exception handling block --- Lib/logging/handlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index c751f99682b8823..cf57b93fb96dd04 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1157,7 +1157,7 @@ def emit(self, record): except Exception: pass raise - except Exception: + except Exception: self.handleError(record) class NTEventLogHandler(logging.Handler): From 16da0d36c62369d05f75028625f3f1c18206e4d7 Mon Sep 17 00:00:00 2001 From: Mazin Sharaf Date: Mon, 17 Aug 2026 19:43:04 +1000 Subject: [PATCH 3/7] Refactor email message creation in handlers.py --- Lib/logging/handlers.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index cf57b93fb96dd04..9056f82ec4d9c7f 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1121,13 +1121,13 @@ def emit(self, record): if not port: port = smtplib.SMTP_PORT smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout) + msg = EmailMessage() + msg['From'] = self.fromaddr + msg['To'] = ','.join(self.toaddrs) + msg['Subject'] = self.getSubject(record) + msg['Date'] = email.utils.localtime() + msg.set_content(self.format(record)) try: - msg = EmailMessage() - msg['From'] = self.fromaddr - msg['To'] = ','.join(self.toaddrs) - msg['Subject'] = self.getSubject(record) - msg['Date'] = email.utils.localtime() - msg.set_content(self.format(record)) if self.username: if self.secure is not None: import ssl From 500c4460bdf81a4bcd20d627f5c475d610908ff9 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 10:12:29 +0000 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst diff --git a/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst b/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst new file mode 100644 index 000000000000000..161caadeb57dd55 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst @@ -0,0 +1 @@ +Fix SMTPHandler to close the SMTP connection when sending an email fails. From 86b1b79c873d18cbb3f822ad5ea48286f602b890 Mon Sep 17 00:00:00 2001 From: Mazin Sharaf Date: Mon, 17 Aug 2026 20:18:09 +1000 Subject: [PATCH 5/7] Clean up blank lines in SSL context code Removed unnecessary blank lines in the SSL context setup. --- Lib/logging/handlers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 9056f82ec4d9c7f..acb31f38251f74e 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1131,17 +1131,17 @@ def emit(self, record): if self.username: if self.secure is not None: import ssl - + try: keyfile = self.secure[0] except IndexError: keyfile = None - + try: certfile = self.secure[1] except IndexError: certfile = None - + context = ssl._create_stdlib_context( certfile=certfile, keyfile=keyfile ) From d27b51f1707f9333364ba1867b44f8a612c49447 Mon Sep 17 00:00:00 2001 From: Mazin Sharaf Date: Mon, 17 Aug 2026 20:28:52 +1000 Subject: [PATCH 6/7] Implement test for SMTPHandler on send failure Add test for connection closure on SMTP send failure. --- Lib/test/test_logging.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 7cd0df3ea0b62d2..2e3f8bdcad78a1e 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1171,6 +1171,25 @@ def test_basic(self): self.assertEndsWith(data, '\n\nHello \u2713') h.close() + def test_connection_closed_on_send_failure(self): + handler = logging.handlers.SMTPHandler( + ("localhost", 25), + "me@example.com", + "you@example.com", + "subject", + timeout=self.TIMEOUT, + ) + record = logging.makeLogRecord({"msg": "hello"}) + + smtp = unittest.mock.Mock() + smtp.send_message.side_effect = OSError("send failed") + + with unittest.mock.patch("smtplib.SMTP", return_value=smtp): + with support.captured_stderr(): + handler.emit(record) + + smtp.close.assert_called_once() + def process_message(self, *args): self.messages.append(args) self.handled.set() From 5bb481fee40ed03b8af6309d4b3514012d136076 Mon Sep 17 00:00:00 2001 From: Mazin Sharaf Date: Mon, 17 Aug 2026 21:02:24 +1000 Subject: [PATCH 7/7] Update Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst b/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst index 161caadeb57dd55..73e89f2638d2d77 100644 --- a/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst +++ b/Misc/NEWS.d/next/Library/2026-08-17-10-12-27.gh-issue-155946.NCtsd4.rst @@ -1 +1,2 @@ -Fix SMTPHandler to close the SMTP connection when sending an email fails. +:mod:`logging`: ensure that :class:`logging.handlesr.SMTPHandler` +correctly releases resources on SMTP connection failures.