From 6cfbdc6cfbbdbec9ba4119c3152a78e404072118 Mon Sep 17 00:00:00 2001 From: lafe3402 Date: Sat, 13 Jan 2018 18:13:07 -0500 Subject: [PATCH 01/11] bpo-28879: add Date header to send_message as per RFC5322 --- Doc/library/smtplib.rst | 17 +++-- Lib/smtplib.py | 4 ++ Lib/test/test_smtplib.py | 66 ++++++++++--------- .../2018-01-13-15-52-00.bpo-28879.aW2gj0.rst | 2 + 4 files changed, 52 insertions(+), 37 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index b3cc60357f554a..509eedbab72e8c 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -522,12 +522,17 @@ An :class:`SMTP` instance has the following methods: specified in :rfc:`5322`\: *from_addr* is set to the :mailheader:`Sender` field if it is present, and otherwise to the :mailheader:`From` field. *to_addrs* combines the values (if any) of the :mailheader:`To`, - :mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If exactly one - set of :mailheader:`Resent-*` headers appear in the message, the regular - headers are ignored and the :mailheader:`Resent-*` headers are used instead. - If the message contains more than one set of :mailheader:`Resent-*` headers, - a :exc:`ValueError` is raised, since there is no way to unambiguously detect - the most recent set of :mailheader:`Resent-` headers. + :mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If there's no + :mailheader:`Date` header inside the message, ``send_message`` will add one to the data. + If exactly one set of :mailheader:`Resent-*` headers appear in the message, + the regular headers are ignored and the :mailheader:`Resent-*` headers are + used instead. If the message contains more than one set of + :mailheader:`Resent-*` headers, a :exc:`ValueError` is raised, since there + is no way to unambiguously detect the most recent set of + :mailheader:`Resent-` headers. + + .. versionchanged:: 3.2 + Support to add :mailheader:`Date` header to the message if one does not exist. ``send_message`` serializes *msg* using :class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and diff --git a/Lib/smtplib.py b/Lib/smtplib.py index e2dbbbcf2e6d16..5e2d3f4b02ca1f 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -932,6 +932,10 @@ def send_message(self, msg, from_addr=None, to_addrs=None, header_prefix = 'Resent-' else: raise ValueError("message has more than one 'Resent-' header block") + + # RFC 5322 section 3.6, 4th Paragraph + if msg.get('Date', None) is None: + msg['Date'] = email.utils.formatdate() if from_addr is None: # Prefer the sender field per RFC 2822:3.6.2. from_addr = (msg[header_prefix + 'Sender'] diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 7816ed34886e95..31af316c88cfe1 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -23,7 +23,7 @@ from test.support import hashlib_helper from test.support import socket_helper from test.support import threading_helper -from unittest.mock import Mock +from unittest.mock import Mock, patch HOST = socket_helper.HOST @@ -1342,36 +1342,40 @@ def test_send_unicode_with_SMTPUTF8_via_low_level_API(self): self.assertEqual(self.serv.last_rcpt_options, []) def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): - msg = EmailMessage() - msg['From'] = "Páolo " - msg['To'] = 'Dinsdale' - msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' - # XXX I don't know why I need two \n's here, but this is an existing - # bug (if it is one) and not a problem with the new functionality. - msg.set_content("oh là là, know what I mean, know what I mean?\n\n") - # XXX smtpd converts received /r/n to /n, so we can't easily test that - # we are successfully sending /r/n :(. - expected = textwrap.dedent("""\ - From: Páolo - To: Dinsdale - Subject: Nudge nudge, wink, wink \u1F609 - Content-Type: text/plain; charset="utf-8" - Content-Transfer-Encoding: 8bit - MIME-Version: 1.0 - - oh là là, know what I mean, know what I mean? - """) - smtp = smtplib.SMTP( - HOST, self.port, local_hostname='localhost', - timeout=support.LOOPBACK_TIMEOUT) - self.addCleanup(smtp.close) - self.assertEqual(smtp.send_message(msg), {}) - self.assertEqual(self.serv.last_mailfrom, 'főo@bar.com') - self.assertEqual(self.serv.last_rcpttos, ['Dinsdale']) - self.assertEqual(self.serv.last_message.decode(), expected) - self.assertIn('BODY=8BITMIME', self.serv.last_mail_options) - self.assertIn('SMTPUTF8', self.serv.last_mail_options) - self.assertEqual(self.serv.last_rcpt_options, []) + expected_date = "Thu, 19 Mar 2020 00:59:43 -0000" + with patch("email.utils.formatdate") as date_mock: + date_mock.return_value = expected_date + msg = EmailMessage() + msg['From'] = "Páolo " + msg['To'] = 'Dinsdale' + msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' + # XXX I don't know why I need two \n's here, but this is an existing + # bug (if it is one) and not a problem with the new functionality. + msg.set_content("oh là là, know what I mean, know what I mean?\n\n") + # XXX smtpd converts received /r/n to /n, so we can't easily test that + # we are successfully sending /r/n :(. + expected = textwrap.dedent("""\ + From: Páolo + To: Dinsdale + Subject: Nudge nudge, wink, wink \u1F609 + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: 8bit + MIME-Version: 1.0 + Date: {} + + oh là là, know what I mean, know what I mean? + """.format(expected_date)) + smtp = smtplib.SMTP( + HOST, self.port, local_hostname='localhost', + timeout=support.LOOPBACK_TIMEOUT) + self.addCleanup(smtp.close) + self.assertEqual(smtp.send_message(msg), {}) + self.assertEqual(self.serv.last_mailfrom, 'főo@bar.com') + self.assertEqual(self.serv.last_rcpttos, ['Dinsdale']) + self.assertEqual(self.serv.last_message.decode(), expected) + self.assertIn('BODY=8BITMIME', self.serv.last_mail_options) + self.assertIn('SMTPUTF8', self.serv.last_mail_options) + self.assertEqual(self.serv.last_rcpt_options, []) EXPECTED_RESPONSE = encode_base64(b'\0psu\0doesnotexist', eol='') diff --git a/Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst b/Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst new file mode 100644 index 00000000000000..3cd194ba82f5f4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst @@ -0,0 +1,2 @@ +Fix ``smtplib.send_message`` to add a ``Date`` header if it is missing as per +RFC5322. \ No newline at end of file From 5ffc0989ac66902bb1332a023b7ed2fb9bcc5520 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 09:39:17 +0200 Subject: [PATCH 02/11] add patch --- Lib/test/test_smtplib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index d2218d30bd4d76..5b664d093ab8eb 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -23,7 +23,7 @@ from test.support import threading_helper from test.support import asyncore from test.support import smtpd -from unittest.mock import Mock +from unittest.mock import Mock, patch support.requires_working_socket(module=True) From 4c2353c3ed38e77a5029a96f5b316993e5906430 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 09:51:52 +0200 Subject: [PATCH 03/11] update blurb --- ...79.aW2gj0.rst => 2025-07-20-09-51-25.bpo-28879.SLDgcy.rst} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename Misc/NEWS.d/next/Library/{2018-01-13-15-52-00.bpo-28879.aW2gj0.rst => 2025-07-20-09-51-25.bpo-28879.SLDgcy.rst} (73%) diff --git a/Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst b/Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst similarity index 73% rename from Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst rename to Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst index 3cd194ba82f5f4..c69820f4e53648 100644 --- a/Misc/NEWS.d/next/Library/2018-01-13-15-52-00.bpo-28879.aW2gj0.rst +++ b/Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst @@ -1,2 +1,2 @@ -Fix ``smtplib.send_message`` to add a ``Date`` header if it is missing as per -RFC5322. \ No newline at end of file +Fix ``smtplib.send_message`` to add a ``Date`` header if it is missing as +per RFC5322. From a4bc9c7c5a1d35043795719278dcafb79eeeb888 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 13:06:21 +0200 Subject: [PATCH 04/11] update rst --- Doc/library/smtplib.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index 8762d2710253b3..6cd9db3a86e0c8 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -519,7 +519,7 @@ An :class:`SMTP` instance has the following methods: is no way to unambiguously detect the most recent set of :mailheader:`Resent-` headers. - .. versionchanged:: 3.2 + .. versionchanged:: 3.14 Support to add :mailheader:`Date` header to the message if one does not exist. ``send_message`` serializes *msg* using From f960ab26effb4efb73af011b3208fdf0aa7f5903 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 13:06:29 +0200 Subject: [PATCH 05/11] update rst --- Doc/library/smtplib.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index 6cd9db3a86e0c8..6553487f27fdd3 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -519,7 +519,7 @@ An :class:`SMTP` instance has the following methods: is no way to unambiguously detect the most recent set of :mailheader:`Resent-` headers. - .. versionchanged:: 3.14 + .. versionchanged:: 3.15 Support to add :mailheader:`Date` header to the message if one does not exist. ``send_message`` serializes *msg* using From 0e6ec22932e46209a6e6c6d63a76696dd419ebb0 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 13:55:16 +0200 Subject: [PATCH 06/11] update tests to not patch date --- Lib/smtplib.py | 3 +- Lib/test/test_smtplib.py | 79 ++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 53da9bd5378321..ddbc34458383cf 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -938,7 +938,8 @@ def send_message(self, msg, from_addr=None, to_addrs=None, # RFC 5322 section 3.6, 4th Paragraph if msg.get('Date', None) is None: - msg['Date'] = email.utils.formatdate() + # localtime: RFC 5322 section 3.3 4th Paragraph + msg['Date'] = email.utils.formatdate(localtime=True) if from_addr is None: # Prefer the sender field per RFC 2822:3.6.2. from_addr = (msg[header_prefix + 'Sender'] diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 5b664d093ab8eb..4f43baf52a1680 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -23,7 +23,7 @@ from test.support import threading_helper from test.support import asyncore from test.support import smtpd -from unittest.mock import Mock, patch +from unittest.mock import Mock support.requires_working_socket(module=True) @@ -1393,6 +1393,11 @@ class SMTPUTF8SimTests(unittest.TestCase): maxDiff = None + def _is_local(self, date: str) -> bool: + dt = email.utils.parsedate_to_datetime(date) + local_offset = dt.now().astimezone().utcoffset() + return dt.utcoffset() == local_offset + def setUp(self): self.thread_key = threading_helper.threading_setup() self.real_getfqdn = socket.getfqdn @@ -1468,40 +1473,44 @@ def test_send_unicode_with_SMTPUTF8_via_low_level_API(self): self.assertEqual(self.serv.last_rcpt_options, []) def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): - expected_date = "Thu, 19 Mar 2020 00:59:43 -0000" - with patch("email.utils.formatdate") as date_mock: - date_mock.return_value = expected_date - msg = EmailMessage() - msg['From'] = "Páolo " - msg['To'] = 'Dinsdale' - msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' - # XXX I don't know why I need two \n's here, but this is an existing - # bug (if it is one) and not a problem with the new functionality. - msg.set_content("oh là là, know what I mean, know what I mean?\n\n") - # XXX smtpd converts received /r/n to /n, so we can't easily test that - # we are successfully sending /r/n :(. - expected = textwrap.dedent("""\ - From: Páolo - To: Dinsdale - Subject: Nudge nudge, wink, wink \u1F609 - Content-Type: text/plain; charset="utf-8" - Content-Transfer-Encoding: 8bit - MIME-Version: 1.0 - Date: {} - - oh là là, know what I mean, know what I mean? - """.format(expected_date)) - smtp = smtplib.SMTP( - HOST, self.port, local_hostname='localhost', - timeout=support.LOOPBACK_TIMEOUT) - self.addCleanup(smtp.close) - self.assertEqual(smtp.send_message(msg), {}) - self.assertEqual(self.serv.last_mailfrom, 'főo@bar.com') - self.assertEqual(self.serv.last_rcpttos, ['Dinsdale']) - self.assertEqual(self.serv.last_message.decode(), expected) - self.assertIn('BODY=8BITMIME', self.serv.last_mail_options) - self.assertIn('SMTPUTF8', self.serv.last_mail_options) - self.assertEqual(self.serv.last_rcpt_options, []) + msg = EmailMessage() + msg['From'] = "Páolo " + msg['To'] = 'Dinsdale' + msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' + # XXX I don't know why I need two \n's here, but this is an existing + # bug (if it is one) and not a problem with the new functionality. + msg.set_content("oh là là, know what I mean, know what I mean?\n\n") + # XXX smtpd converts received /r/n to /n, so we can't easily test that + # we are successfully sending /r/n :(. + smtp = smtplib.SMTP( + HOST, self.port, local_hostname='localhost', + timeout=support.LOOPBACK_TIMEOUT) + self.addCleanup(smtp.close) + self.assertEqual(smtp.send_message(msg), {}) + self.assertEqual(self.serv.last_mailfrom, 'főo@bar.com') + self.assertEqual(self.serv.last_rcpttos, ['Dinsdale']) + + last_message = self.serv.last_message.decode() + date = email.message_from_string(last_message)['Date'] + # asserts RFC 5322 section 3.3 4th Paragraph + self.assertTrue(self._is_local(date)) + + expected = textwrap.dedent("""\ + From: Páolo + To: Dinsdale + Subject: Nudge nudge, wink, wink \u1F609 + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: 8bit + MIME-Version: 1.0 + Date: {} + + oh là là, know what I mean, know what I mean? + """.format(date)) + + self.assertEqual(last_message, expected) + self.assertIn('BODY=8BITMIME', self.serv.last_mail_options) + self.assertIn('SMTPUTF8', self.serv.last_mail_options) + self.assertEqual(self.serv.last_rcpt_options, []) EXPECTED_RESPONSE = encode_base64(b'\0psu\0doesnotexist', eol='') From be69865fc6411a469c4b78540e72132d87f8be88 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 14:02:29 +0200 Subject: [PATCH 07/11] reorder assertions for readability --- Lib/test/test_smtplib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 4f43baf52a1680..6e2af1f23707fd 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -1487,8 +1487,6 @@ def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): timeout=support.LOOPBACK_TIMEOUT) self.addCleanup(smtp.close) self.assertEqual(smtp.send_message(msg), {}) - self.assertEqual(self.serv.last_mailfrom, 'főo@bar.com') - self.assertEqual(self.serv.last_rcpttos, ['Dinsdale']) last_message = self.serv.last_message.decode() date = email.message_from_string(last_message)['Date'] @@ -1507,6 +1505,8 @@ def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): oh là là, know what I mean, know what I mean? """.format(date)) + self.assertEqual(self.serv.last_mailfrom, 'főo@bar.com') + self.assertEqual(self.serv.last_rcpttos, ['Dinsdale']) self.assertEqual(last_message, expected) self.assertIn('BODY=8BITMIME', self.serv.last_mail_options) self.assertIn('SMTPUTF8', self.serv.last_mail_options) From 3a8abdd26ee3f1d8e41c7e61576270d8dd6b8980 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 14:24:16 +0200 Subject: [PATCH 08/11] . --- Lib/smtplib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index ddbc34458383cf..99aad1d549bd30 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -938,7 +938,7 @@ def send_message(self, msg, from_addr=None, to_addrs=None, # RFC 5322 section 3.6, 4th Paragraph if msg.get('Date', None) is None: - # localtime: RFC 5322 section 3.3 4th Paragraph + # localtime: RFC 5322 section 3.3, 4th Paragraph msg['Date'] = email.utils.formatdate(localtime=True) if from_addr is None: # Prefer the sender field per RFC 2822:3.6.2. From 00c870a3285a4b441fefad3b0307fcf515a11395 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 16:39:34 +0200 Subject: [PATCH 09/11] use support.run_with_tz --- Doc/library/smtplib.rst | 2 +- Lib/test/test_smtplib.py | 12 ++++++------ .../Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index 6553487f27fdd3..344514a8d434cf 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -519,7 +519,7 @@ An :class:`SMTP` instance has the following methods: is no way to unambiguously detect the most recent set of :mailheader:`Resent-` headers. - .. versionchanged:: 3.15 + .. versionchanged:: next Support to add :mailheader:`Date` header to the message if one does not exist. ``send_message`` serializes *msg* using diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 6e2af1f23707fd..3f96d3927e7892 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -26,6 +26,7 @@ from unittest.mock import Mock + support.requires_working_socket(module=True) HOST = socket_helper.HOST @@ -1393,11 +1394,6 @@ class SMTPUTF8SimTests(unittest.TestCase): maxDiff = None - def _is_local(self, date: str) -> bool: - dt = email.utils.parsedate_to_datetime(date) - local_offset = dt.now().astimezone().utcoffset() - return dt.utcoffset() == local_offset - def setUp(self): self.thread_key = threading_helper.threading_setup() self.real_getfqdn = socket.getfqdn @@ -1472,6 +1468,7 @@ def test_send_unicode_with_SMTPUTF8_via_low_level_API(self): self.assertIn('SMTPUTF8', self.serv.last_mail_options) self.assertEqual(self.serv.last_rcpt_options, []) + @support.run_with_tz('UTC-2') def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): msg = EmailMessage() msg['From'] = "Páolo " @@ -1491,7 +1488,10 @@ def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): last_message = self.serv.last_message.decode() date = email.message_from_string(last_message)['Date'] # asserts RFC 5322 section 3.3 4th Paragraph - self.assertTrue(self._is_local(date)) + self.assertEqual( + email.utils.parsedate_to_datetime(date).tzname(), + "UTC+02:00" + ) expected = textwrap.dedent("""\ From: Páolo diff --git a/Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst b/Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst index c69820f4e53648..f3fd71b58d89e1 100644 --- a/Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst +++ b/Misc/NEWS.d/next/Library/2025-07-20-09-51-25.bpo-28879.SLDgcy.rst @@ -1,2 +1,2 @@ Fix ``smtplib.send_message`` to add a ``Date`` header if it is missing as -per RFC5322. +per :rfc:`5322`. From 6a5188e56a18778c0214c27a06f37379c6b6b43d Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 16:43:52 +0200 Subject: [PATCH 10/11] remove empty line --- Lib/test/test_smtplib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 3f96d3927e7892..9d30fc4c209fcb 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -26,7 +26,6 @@ from unittest.mock import Mock - support.requires_working_socket(module=True) HOST = socket_helper.HOST From bcfe9d2c718055a875b1d5fbfb0ad12a673b8c46 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 16:48:35 +0200 Subject: [PATCH 11/11] use 02 syntax --- Lib/test/test_smtplib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 9d30fc4c209fcb..d364851ef8e7d8 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -1467,7 +1467,7 @@ def test_send_unicode_with_SMTPUTF8_via_low_level_API(self): self.assertIn('SMTPUTF8', self.serv.last_mail_options) self.assertEqual(self.serv.last_rcpt_options, []) - @support.run_with_tz('UTC-2') + @support.run_with_tz('UTC-02') def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): msg = EmailMessage() msg['From'] = "Páolo "