summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/email/encoders.py20
-rw-r--r--Lib/email/message.py2
-rw-r--r--Lib/test/test_email/test_email.py36
-rw-r--r--Misc/NEWS3
4 files changed, 45 insertions, 16 deletions
diff --git a/Lib/email/encoders.py b/Lib/email/encoders.py
index a0d062a..f9657f0 100644
--- a/Lib/email/encoders.py
+++ b/Lib/email/encoders.py
@@ -28,7 +28,7 @@ def encode_base64(msg):
Also, add an appropriate Content-Transfer-Encoding header.
"""
- orig = msg.get_payload()
+ orig = msg.get_payload(decode=True)
encdata = str(_bencode(orig), 'ascii')
msg.set_payload(encdata)
msg['Content-Transfer-Encoding'] = 'base64'
@@ -40,20 +40,16 @@ def encode_quopri(msg):
Also, add an appropriate Content-Transfer-Encoding header.
"""
- orig = msg.get_payload()
- if isinstance(orig, str):
- # If it is a string, the model data may have binary data encoded in via
- # surrogateescape. Convert back to bytes so we can CTE encode it.
- orig = orig.encode('ascii', 'surrogateescape')
+ orig = msg.get_payload(decode=True)
encdata = _qencode(orig)
- msg.set_payload(encdata.decode('ascii', 'surrogateescape'))
+ msg.set_payload(encdata)
msg['Content-Transfer-Encoding'] = 'quoted-printable'
def encode_7or8bit(msg):
"""Set the Content-Transfer-Encoding header to 7bit or 8bit."""
- orig = msg.get_payload()
+ orig = msg.get_payload(decode=True)
if orig is None:
# There's no payload. For backwards compatibility we use 7bit
msg['Content-Transfer-Encoding'] = '7bit'
@@ -75,16 +71,8 @@ def encode_7or8bit(msg):
msg['Content-Transfer-Encoding'] = '8bit'
else:
msg['Content-Transfer-Encoding'] = '7bit'
- if not isinstance(orig, str):
- msg.set_payload(orig.decode('ascii', 'surrogateescape'))
def encode_noop(msg):
"""Do nothing."""
- # Well, not quite *nothing*: in Python3 we have to turn bytes into a string
- # in our internal surrogateescaped form in order to keep the model
- # consistent.
- orig = msg.get_payload()
- if not isinstance(orig, str):
- msg.set_payload(orig.decode('ascii', 'surrogateescape'))
diff --git a/Lib/email/message.py b/Lib/email/message.py
index b5f7b3a..ebaf1c1 100644
--- a/Lib/email/message.py
+++ b/Lib/email/message.py
@@ -303,6 +303,8 @@ class Message:
Optional charset sets the message's default character set. See
set_charset() for details.
"""
+ if isinstance(payload, bytes):
+ payload = payload.decode('ascii', 'surrogateescape')
self._payload = payload
if charset is not None:
self.set_charset(charset)
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index b2c8b7d..202cee8 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -620,6 +620,42 @@ class TestMessageAPI(TestEmailBase):
"attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt",
msg['Content-Disposition'])
+ def test_binary_quopri_payload(self):
+ for charset in ('latin-1', 'ascii'):
+ msg = Message()
+ msg['content-type'] = 'text/plain; charset=%s' % charset
+ msg['content-transfer-encoding'] = 'quoted-printable'
+ msg.set_payload(b'foo=e6=96=87bar')
+ self.assertEqual(
+ msg.get_payload(decode=True),
+ b'foo\xe6\x96\x87bar',
+ 'get_payload returns wrong result with charset %s.' % charset)
+
+ def test_binary_base64_payload(self):
+ for charset in ('latin-1', 'ascii'):
+ msg = Message()
+ msg['content-type'] = 'text/plain; charset=%s' % charset
+ msg['content-transfer-encoding'] = 'base64'
+ msg.set_payload(b'Zm9v5paHYmFy')
+ self.assertEqual(
+ msg.get_payload(decode=True),
+ b'foo\xe6\x96\x87bar',
+ 'get_payload returns wrong result with charset %s.' % charset)
+
+ def test_binary_uuencode_payload(self):
+ for charset in ('latin-1', 'ascii'):
+ for encoding in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
+ msg = Message()
+ msg['content-type'] = 'text/plain; charset=%s' % charset
+ msg['content-transfer-encoding'] = encoding
+ msg.set_payload(b"begin 666 -\n)9F]OYI:'8F%R\n \nend\n")
+ self.assertEqual(
+ msg.get_payload(decode=True),
+ b'foo\xe6\x96\x87bar',
+ str(('get_payload returns wrong result ',
+ 'with charset {0} and encoding {1}.')).\
+ format(charset, encoding))
+
def test_add_header_with_name_only_param(self):
msg = Message()
msg.add_header('Content-Disposition', 'inline', foo_bar=None)
diff --git a/Misc/NEWS b/Misc/NEWS
index 61f5369..9cba1a4 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -38,6 +38,9 @@ Core and Builtins
Library
-------
+- Issue #18324: set_payload now correctly handles binary input. This also
+ supersedes the previous fixes for #14360, #1717, and #16564.
+
- Issue #18794: Add a fileno() method and a closed attribute to select.devpoll
objects.