浏览代码

Fixed #36119 -- Fixed UnicodeEncodeError when attaching a file with 8bit Content-Transfer-Encoding.

greg 1 月之前
父节点
当前提交
89e28e13ec
共有 2 个文件被更改,包括 28 次插入4 次删除
  1. 4 4
      django/core/mail/message.py
  2. 24 0
      tests/mail/tests.py

+ 4 - 4
django/core/mail/message.py

@@ -2,7 +2,7 @@ import mimetypes
 from collections import namedtuple
 from email import charset as Charset
 from email import encoders as Encoders
-from email import generator, message_from_string
+from email import generator, message_from_bytes
 from email.errors import HeaderParseError
 from email.header import Header
 from email.headerregistry import Address, parser
@@ -17,7 +17,7 @@ from pathlib import Path
 
 from django.conf import settings
 from django.core.mail.utils import DNS_NAME
-from django.utils.encoding import force_str, punycode
+from django.utils.encoding import force_bytes, force_str, punycode
 
 # Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from
 # some spam filters.
@@ -152,7 +152,7 @@ class MIMEMixin:
 
 class SafeMIMEMessage(MIMEMixin, MIMEMessage):
     def __setitem__(self, name, val):
-        # message/rfc822 attachments must be ASCII
+        # Per RFC 2046 Section 5.2.1, message/rfc822 attachment headers must be ASCII.
         name, val = forbid_multi_line_headers(name, val, "ascii")
         MIMEMessage.__setitem__(self, name, val)
 
@@ -399,7 +399,7 @@ class EmailMessage:
             elif not isinstance(content, Message):
                 # For compatibility with existing code, parse the message
                 # into an email.Message object if it is not one already.
-                content = message_from_string(force_str(content))
+                content = message_from_bytes(force_bytes(content))
 
             attachment = SafeMIMEMessage(content, subtype)
         else:

+ 24 - 0
tests/mail/tests.py

@@ -913,6 +913,30 @@ class MailTests(MailTestsMixin, SimpleTestCase):
         self.assertEqual(content, b"\xff")
         self.assertEqual(mimetype, "application/octet-stream")
 
+    def test_attach_8bit_rfc822_message_non_ascii(self):
+        """
+        Attaching a message that uses 8bit content transfer encoding for
+        non-ASCII characters should not raise a UnicodeEncodeError (#36119).
+        """
+        attachment = dedent(
+            """\
+            Subject: A message using 8bit CTE
+            Content-Type: text/plain; charset=utf-8
+            Content-Transfer-Encoding: 8bit
+
+            ¡8-bit content!
+            """
+        ).encode()
+        email = EmailMessage()
+        email.attach("attachment.eml", attachment, "message/rfc822")
+        attachments = self.get_raw_attachments(email)
+        self.assertEqual(len(attachments), 1)
+        self.assertEqual(attachments[0].get_content_type(), "message/rfc822")
+        attached_message = attachments[0].get_content()
+        self.assertEqual(attached_message.get_content().rstrip(), "¡8-bit content!")
+        self.assertEqual(attached_message["Content-Transfer-Encoding"], "8bit")
+        self.assertEqual(attached_message.get_content_type(), "text/plain")
+
     def test_attach_mime_image(self):
         """
         EmailMessage.attach() docs: "You can pass it