Skip to content
Prev Previous commit
Next Next commit
gh-150771: Use output charset in set_text_content for shift_jis/euc-jp
Encode the payload with the charset output mapping (iso-2022-jp) when
set_content is called with shift_jis or euc-jp, instead of patching
serialization in body_encode and set_payload. Reverts those changes.
  • Loading branch information
bhuvi27 committed Jun 14, 2026
commit f6c53cb11c9617db20f6bd2f235b7b9fc1b79fa8
10 changes: 1 addition & 9 deletions Lib/email/charset.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import email.quoprimime

from email import errors
from email import utils
from email.encoders import encode_7or8bit


Expand Down Expand Up @@ -439,12 +438,5 @@ def body_encode(self, string):
return email.quoprimime.body_encode(string)
else:
if isinstance(string, str):
if utils._has_surrogates(string):
string = string.encode('ascii', 'surrogateescape')
if self.input_charset != self.output_charset:
string = (string.decode(self.input_codec)
.encode(self.output_codec))
string = string.decode('ascii', 'surrogateescape')
else:
string = string.encode(self.output_charset).decode('ascii')
string = string.encode(self.output_charset).decode('ascii')
return string
3 changes: 2 additions & 1 deletion Lib/email/contentmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ def set_text_content(msg, string, subtype="plain", charset='utf-8', cte=None,
params=None, headers=None):
_prepare_set(msg, 'text', subtype, headers)

charset = email.charset.Charset(charset).input_charset
cs = email.charset.Charset(charset)
charset = cs.output_charset
cte, payload = _encode_text(string, charset, cte, msg.policy)
msg.set_payload(payload)
msg.set_param('charset', charset, replace=True)
Expand Down
4 changes: 1 addition & 3 deletions Lib/email/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,7 @@ def set_payload(self, payload, charset=None):
return
if not isinstance(charset, Charset):
charset = Charset(charset)
if not utils._has_surrogates(payload):
payload = payload.encode(charset.output_charset,
'surrogateescape')
payload = payload.encode(charset.output_charset, 'surrogateescape')
if hasattr(payload, 'decode'):
self._payload = payload.decode('ascii', 'surrogateescape')
else:
Expand Down
12 changes: 4 additions & 8 deletions Lib/test/test_email/test_contentmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,9 @@ def test_set_text_charset_shift_jis(self):
m = self._make_message()
content = "\u65e5\u672c\u8a9e\n"
raw_data_manager.set_content(m, content, charset='shift_jis')
self.assertEqual(m['Content-Type'], 'text/plain; charset="shift_jis"')
self.assertEqual(m['Content-Transfer-Encoding'], '8bit')
self.assertEqual(m.get_payload(decode=True), content.encode('shift_jis'))
self.assertEqual(m['Content-Type'], 'text/plain; charset="iso-2022-jp"')
self.assertEqual(m.get_payload(decode=True), content.encode('iso-2022-jp'))
self.assertEqual(m.get_content(), content)
# Serialization converts the payload to iso-2022-jp for output.
self.assertEqual(str(m), textwrap.dedent("""\
Comment thread
bhuvi27 marked this conversation as resolved.
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit
Expand All @@ -382,11 +380,9 @@ def test_set_text_charset_euc_jp(self):
m = self._make_message()
content = "\u65e5\u672c\u8a9e\n"
raw_data_manager.set_content(m, content, charset='euc-jp')
self.assertEqual(m['Content-Type'], 'text/plain; charset="euc-jp"')
self.assertEqual(m['Content-Transfer-Encoding'], '8bit')
self.assertEqual(m.get_payload(decode=True), content.encode('euc-jp'))
self.assertEqual(m['Content-Type'], 'text/plain; charset="iso-2022-jp"')
self.assertEqual(m.get_payload(decode=True), content.encode('iso-2022-jp'))
self.assertEqual(m.get_content(), content)
# Serialization converts the payload to iso-2022-jp for output.
self.assertEqual(str(m), textwrap.dedent("""\
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Fix serialization of :mod:`email` messages using ``shift_jis`` or ``euc-jp``
charsets. Converting surrogate-escaped payloads to the required
``iso-2022-jp`` output charset no longer raises :exc:`UnicodeEncodeError`.
Fix :mod:`email` messages created with ``shift_jis`` or ``euc-jp`` charsets.
:func:`email.contentmanager.set_text_content` now stores the payload using
the output charset (``iso-2022-jp``) so :func:`str` on the message no longer
raises :exc:`UnicodeEncodeError`.