From 1c87341f648a9f5e4162695937241f954392cae6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 7 Jun 2026 12:27:17 +0000 Subject: [PATCH] Fix email header folding exceeding max_line_length on continuation lines When an encoded word starts a continuation line, _fold_as_ew() emits the line's leading whitespace as its own encoded word but kept using the remaining_space/text_space computed before that word was added. The following encoded word was therefore sized against a stale budget, so the folded line could exceed max_line_length. Recompute the available space after appending the whitespace encoded word, and start a new line when nothing else fits. https://claude.ai/code/session_019aJ7pxZ6gNWzXmYT5obbvN --- Lib/email/_header_value_parser.py | 7 +++++++ Lib/test/test_email/test__header_value_parser.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 91243378dc0441..6d432990aeb5f2 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -3001,6 +3001,13 @@ def _fold_as_ew(to_encode, lines, maxlen, last_ew, ew_combine_allowed, charset, encoded_word = _ew.encode(leading_whitespace, charset=encode_as) lines[-1] += encoded_word leading_whitespace = '' + # The leading whitespace was encoded as its own encoded word and + # appended to the line, so recompute the space left on the line. + remaining_space = maxlen - len(lines[-1]) + text_space = remaining_space - chrome_len + if text_space <= 0: + lines.append(' ') + continue to_encode_word = to_encode[:text_space] encoded_word = _ew.encode(to_encode_word, charset=encode_as) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index 179e236ecdfd7f..545bb269f07beb 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -3123,6 +3123,21 @@ def test_unknown_after_unknown(self): "=?unknown-8bit?q?=A4?="), prefix + "=?unknown-8bit?q?=C2?=\n =?unknown-8bit?q?=A4?=\n") + def test_long_ew_after_encoded_continuation_whitespace(self): + # When an encoded word begins a continuation line, the line's leading + # whitespace is emitted as its own encoded word. The space it consumes + # must be subtracted from the budget, otherwise the following encoded + # word overflows max_line_length. + policy = self.policy.clone(max_line_length=40) + self._test(parser.get_unstructured( + 'a b c d ä d .,ä, dc cbaö,ä.,baaöa üa.,ü,c,äöäa,bööüc üü'), + 'a b c d =?utf-8?b?w6QgZCAuLMOkLA==?= dc\n' + ' =?utf-8?q?_?==?utf-8?b?Y2Jhw7Ysw6Qu?=\n' + ' =?utf-8?b?LGJhYcO2YSDDvGEuLMO8LGMs?=\n' + ' =?utf-8?b?w6TDtsOkYSxiw7bDtsO8YyA=?=\n' + ' =?utf-8?q?=C3=BC=C3=BC?=\n', + policy=policy) + # XXX Need test of an encoded word so long that it needs to be wrapped def test_simple_address(self):