From ebde4e897750963b82bcae785949ac11b3877640 Mon Sep 17 00:00:00 2001 From: "R. David Murray" Date: Mon, 19 May 2025 15:03:07 -0400 Subject: [PATCH 1/4] Fix additional refolding-encoding edge case. In this case, the higher level syntactic unit fit on the remainder of the line in un-encoded format, so the encoding check never happened. To fix this, we look inside the current unit to see if has anything that was originally encoded. --- Lib/email/_header_value_parser.py | 13 ++++++++++++- Lib/test/test_email/test__header_value_parser.py | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 9a51b9437333db8..67b885115a37170 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -162,6 +162,14 @@ def comments(self): comments.extend(token.comments) return comments + def has_token_type(self, *token_types): + if self.token_type in token_types: + return True + for t in self: + if t.has_token_type(*token_types): + return True + return False + def fold(self, *, policy): return _refold_parse_tree(self, policy=policy) @@ -922,6 +930,9 @@ def pop_trailing_ws(self): def comments(self): return [] + def has_token_type(self, *token_types): + return self.token_type in token_types + def __getnewargs__(self): return(str(self), self.token_type) @@ -2813,7 +2824,7 @@ def _refold_parse_tree(parse_tree, *, policy): continue tstr = str(part) if not want_encoding: - if part.token_type in ('ptext', 'vtext'): + if part.token_type == 'ptext' or part.has_token_type('vtext'): # Encode if tstr contains special characters. want_encoding = not SPECIALSNL.isdisjoint(tstr) else: diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index ac12c3b2306f7d7..a2e77d2e8176eb4 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -3096,6 +3096,11 @@ def test_address_list_with_specials_in_encoded_word(self): 'A =?utf-8?q?v=C3=A9ry?= long name\n' ' containing =?utf-8?q?a=2C?= comma\n' ' \n'), + ('=?utf-8?Q?a=2C=20123456789012345678901234567890123456?=' + ' ', + '=?utf-8?q?a=2C?=\n' + ' 123456789012345678901234567890123456\n' + ' \n'), ] for (to, folded) in cases: with self.subTest(to=to): From d97bd404acfa9655320a0f304a47ea0fd2b48f57 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Thu, 8 Oct 2026 16:15:16 -0400 Subject: [PATCH 2/4] Better name for new function. --- Lib/email/_header_value_parser.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 50d043b0bf70729..f396f4f9b32a9a8 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -166,11 +166,11 @@ def comments(self): comments.extend(token.comments) return comments - def has_token_type(self, *token_types): + def contains_token_type(self, *token_types): if self.token_type in token_types: return True for t in self: - if t.has_token_type(*token_types): + if t.contains_token_type(*token_types): return True return False @@ -941,7 +941,7 @@ def pop_trailing_ws(self): def comments(self): return [] - def has_token_type(self, *token_types): + def contains_token_type(self, *token_types): return self.token_type in token_types def __getnewargs__(self): @@ -2927,7 +2927,7 @@ def _refold_with_ew(parse_tree, lines, maxlen, encoding, *, policy): continue tstr = str(part) if not want_encoding: - if part.token_type == 'ptext' or part.has_token_type('vtext'): + if part.token_type == 'ptext' or part.contains_token_type('vtext'): # Encode if tstr contains special characters. want_encoding = not SPECIALSNL.isdisjoint(tstr) else: From 8b106ae42630e0ec33de36fdbb4f7fcda22227bd Mon Sep 17 00:00:00 2001 From: R David Murray Date: Thu, 8 Oct 2026 16:18:58 -0400 Subject: [PATCH 3/4] Add news item. --- .../next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst diff --git a/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst b/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst new file mode 100644 index 000000000000000..461d1066318bd2e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst @@ -0,0 +1,3 @@ +Fixed error in :lib:`email` new policies where header folding failed to +detect the need to re-quote text obtained from encoded words in certain +cases. From 44115bf51cc14b345c260e642e5de304d8202db1 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Thu, 8 Oct 2026 16:29:38 -0400 Subject: [PATCH 4/4] Fix markup. --- .../next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst b/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst index 461d1066318bd2e..a2df7654b31444b 100644 --- a/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst +++ b/Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst @@ -1,3 +1,3 @@ -Fixed error in :lib:`email` new policies where header folding failed to +Fixed error in :mod:`email` new policies where header folding failed to detect the need to re-quote text obtained from encoded words in certain cases.