From ab83ccd6aa8a760cab4a8fdff41db1dfae52aee0 Mon Sep 17 00:00:00 2001 From: "R. David Murray" Date: Fri, 9 Oct 2026 08:54:09 -0400 Subject: [PATCH] gh-87720 Fix additional header refolding-quoting edge case (GH-134271) In this case, the higher level syntactic unit fit on the remainder of the line in un-encoded format, and that higher level unit was not a ptext or vtext, so the encoding check failed. To fix this, we look inside the current unit to see if has anything that was originally encoded. (cherry picked from commit 5a22a62b96a68c2dd31784c5e3427ad7b365388a) Co-authored-by: R. David Murray --- Lib/email/_header_value_parser.py | 13 ++++++++++++- Lib/test/test_email/test__header_value_parser.py | 5 +++++ .../2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-08-16-18-43.gh-issue-87720.Elqdl9.rst diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index c02175e24e0e08e..00274ba7661aaba 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -169,6 +169,14 @@ def comments(self): comments.extend(token.comments) return comments + def contains_token_type(self, *token_types): + if self.token_type in token_types: + return True + for t in self: + if t.contains_token_type(*token_types): + return True + return False + def fold(self, *, policy): return _refold_parse_tree(self, policy=policy) @@ -935,6 +943,9 @@ def pop_trailing_ws(self): def comments(self): return [] + def contains_token_type(self, *token_types): + return self.token_type in token_types + def __getnewargs__(self): return(str(self), self.token_type) @@ -2863,7 +2874,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.contains_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 8c9601288da8f8b..2d46d5832f420f6 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -3347,6 +3347,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): 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..a2df7654b31444b --- /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 :mod:`email` new policies where header folding failed to +detect the need to re-quote text obtained from encoded words in certain +cases.