mirror of
https://github.com/python/cpython.git
synced 2025-12-09 18:48:05 +00:00
bpo-40597: email: Use CTE if lines are longer than max_line_length consistently (gh-20038)
raw_data_manager (default for EmailPolicy, EmailMessage) does correct wrapping of 'text' parts as long as the message contains characters outside of 7bit US-ASCII set: base64 or qp Content-Transfer-Encoding is applied if the lines would be too long without it. It did not, however, do this for ascii-only text, which could result in lines that were longer than policy.max_line_length or even the rfc 998 maximum. This changeset fixes the heuristic so that if lines are longer than policy.max_line_length, it will always apply a content-transfer-encoding so that the lines are wrapped correctly.
This commit is contained in:
parent
3d17c045b4
commit
6f2f475d5a
3 changed files with 23 additions and 7 deletions
|
|
@ -146,13 +146,13 @@ def _encode_text(string, charset, cte, policy):
|
||||||
def normal_body(lines): return b'\n'.join(lines) + b'\n'
|
def normal_body(lines): return b'\n'.join(lines) + b'\n'
|
||||||
if cte==None:
|
if cte==None:
|
||||||
# Use heuristics to decide on the "best" encoding.
|
# Use heuristics to decide on the "best" encoding.
|
||||||
try:
|
if max(len(x) for x in lines) <= policy.max_line_length:
|
||||||
return '7bit', normal_body(lines).decode('ascii')
|
try:
|
||||||
except UnicodeDecodeError:
|
return '7bit', normal_body(lines).decode('ascii')
|
||||||
pass
|
except UnicodeDecodeError:
|
||||||
if (policy.cte_type == '8bit' and
|
pass
|
||||||
max(len(x) for x in lines) <= policy.max_line_length):
|
if policy.cte_type == '8bit':
|
||||||
return '8bit', normal_body(lines).decode('ascii', 'surrogateescape')
|
return '8bit', normal_body(lines).decode('ascii', 'surrogateescape')
|
||||||
sniff = embedded_body(lines[:10])
|
sniff = embedded_body(lines[:10])
|
||||||
sniff_qp = quoprimime.body_encode(sniff.decode('latin-1'),
|
sniff_qp = quoprimime.body_encode(sniff.decode('latin-1'),
|
||||||
policy.max_line_length)
|
policy.max_line_length)
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,21 @@ class TestRawDataManager(TestEmailBase):
|
||||||
self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)
|
self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)
|
||||||
self.assertEqual(m.get_content(), content)
|
self.assertEqual(m.get_content(), content)
|
||||||
|
|
||||||
|
def test_set_text_plain_long_line_heuristics(self):
|
||||||
|
m = self._make_message()
|
||||||
|
content = ("Simple but long message that is over 78 characters"
|
||||||
|
" long to force transfer encoding.\n")
|
||||||
|
raw_data_manager.set_content(m, content)
|
||||||
|
self.assertEqual(str(m), textwrap.dedent("""\
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
|
Simple but long message that is over 78 characters long to =
|
||||||
|
force transfer encoding.
|
||||||
|
"""))
|
||||||
|
self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)
|
||||||
|
self.assertEqual(m.get_content(), content)
|
||||||
|
|
||||||
def test_set_text_short_line_minimal_non_ascii_heuristics(self):
|
def test_set_text_short_line_minimal_non_ascii_heuristics(self):
|
||||||
m = self._make_message()
|
m = self._make_message()
|
||||||
content = "et là il est monté sur moi et il commence à m'éto.\n"
|
content = "et là il est monté sur moi et il commence à m'éto.\n"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
If text content lines are longer than policy.max_line_length, always use a content-encoding to make sure they are wrapped.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue