Skip to content

Commit eeb0efc

Browse files
msapiromcepl
authored andcommitted
fix email.generator.py to not replace a non-existent header
This PR replaces pythonGH-1977. The reason for the replacement is two-fold. The fix itself is different is that if the CTE header doesn't exist in the original message, it is inserted. This is important because the new CTE could be quoted-printable whereas the original is implicit 8bit. Also the tests are different. The test_nonascii_as_string_without_cte test in pythongh-1977 doesn't actually test the issue in that it passes without the fix. The test_nonascii_as_string_without_content_type_and_cte test is improved here, and even though it doesn't fail without the fix, it is included for completeness. Fixed KeyError exception when flattening an email to a string attempts to replace a non-existent Content-Transfer-Encoding header. Code is originally from gh#python/cpython@371146a, it was released upstream in 3.8.7 Co-authored-by: Mark Sapiro <[email protected]> Date: Mon, 19 Oct 2020 16:11:37 -0700 Fixes: bsc#1208443 Patch: bpo27321-email-no-replace-header.patch
1 parent b2eb877 commit eeb0efc

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

Lib/email/generator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,11 @@ def _write(self, msg):
186186
# If we munged the cte, copy the message again and re-fix the CTE.
187187
if munge_cte:
188188
msg = deepcopy(msg)
189-
msg.replace_header('content-transfer-encoding', munge_cte[0])
189+
# Preserve the header order if the CTE header already exists.
190+
if msg.get('content-transfer-encoding') is None:
191+
msg['Content-Transfer-Encoding'] = munge_cte[0]
192+
else:
193+
msg.replace_header('content-transfer-encoding', munge_cte[0])
190194
msg.replace_header('content-type', munge_cte[1])
191195
# Write the headers. First we see if the message object wants to
192196
# handle that itself. If not, we'll do it generically.

Lib/test/test_email/test_email.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,41 @@ def test_as_string_policy(self):
314314
g.flatten(msg)
315315
self.assertEqual(fullrepr, s.getvalue())
316316

317+
def test_nonascii_as_string_without_cte(self):
318+
m = textwrap.dedent("""\
319+
MIME-Version: 1.0
320+
Content-type: text/plain; charset="iso-8859-1"
321+
322+
Test if non-ascii messages with no Content-Transfer-Encoding set
323+
can be as_string'd:
324+
Föö bär
325+
""")
326+
source = m.encode('iso-8859-1')
327+
expected = textwrap.dedent("""\
328+
MIME-Version: 1.0
329+
Content-type: text/plain; charset="iso-8859-1"
330+
Content-Transfer-Encoding: quoted-printable
331+
332+
Test if non-ascii messages with no Content-Transfer-Encoding set
333+
can be as_string'd:
334+
F=F6=F6 b=E4r
335+
""")
336+
msg = email.message_from_bytes(source)
337+
self.assertEqual(msg.as_string(), expected)
338+
339+
def test_nonascii_as_string_without_content_type_and_cte(self):
340+
m = textwrap.dedent("""\
341+
MIME-Version: 1.0
342+
343+
Test if non-ascii messages with no Content-Type nor
344+
Content-Transfer-Encoding set can be as_string'd:
345+
Föö bär
346+
""")
347+
source = m.encode('iso-8859-1')
348+
expected = source.decode('ascii', 'replace')
349+
msg = email.message_from_bytes(source)
350+
self.assertEqual(msg.as_string(), expected)
351+
317352
def test_as_bytes(self):
318353
msg = self._msgobj('msg_01.txt')
319354
with openfile('msg_01.txt') as fp:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed KeyError exception when flattening an email to a string attempts to
2+
replace a non-existent Content-Transfer-Encoding header.

0 commit comments

Comments
 (0)