[Django] #36478: EmailMessage handles utf-8 encoded text attachments differently in constructor vs property

7 views
Skip to first unread message

Django

unread,
Jun 24, 2025, 9:11:14 PM6/24/25
to django-...@googlegroups.com
#36478: EmailMessage handles utf-8 encoded text attachments differently in
constructor vs property
----------------------------------------+------------------------------
Reporter: Mike Edmunds | Owner: Mike Edmunds
Type: Bug | Status: assigned
Component: Core (Mail) | Version: 5.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 1
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
----------------------------------------+------------------------------
Encoded text attachments set directly in the EmailMessage.attachments
property are not processed the same as the same content passed to in
EmailMessage(attachments=...) or EmailMessage.attach(...).

#27007 added special EmailMessage.attach() handling for text content
encoded as utf-8 bytes. That code is also used for the attachments
constructor argument, but not for attachments set directly:

{{{#!python
# Existing test: passes
def test_attach_text_as_bytes(self):
msg = EmailMessage()
msg.attach("file.txt", b"file content\n")
filename, content, mimetype = self.get_decoded_attachments(msg)[0]
self.assertEqual(filename, "file.txt")
self.assertEqual(content, "file content\n")
self.assertEqual(mimetype, "text/plain")

# New test: passes
def test_attach_text_as_bytes_using_constructor(self):
msg = EmailMessage(
attachments=[EmailAttachment("file.txt", b"file content\n",
"text/plain")]
)
filename, content, mimetype = self.get_decoded_attachments(msg)[0]
self.assertEqual(filename, "file.txt")
self.assertEqual(content, "file content\n")
self.assertEqual(mimetype, "text/plain")

# New test: AttributeError: 'bytes' object has no attribute 'encode'
def test_attach_text_as_bytes_using_property(self):
msg = EmailMessage()
msg.attachments = [EmailAttachment("file.txt", b"file content\n",
"text/plain")]
filename, content, mimetype = self.get_decoded_attachments(msg)[0]
self.assertEqual(filename, "file.txt")
self.assertEqual(content, "file content\n")
self.assertEqual(mimetype, "text/plain")
}}}

The second added test fails with `AttributeError: 'bytes' object has no
attribute 'encode` deep in SafeMIMEText.

The EmailMessage documentation implies that
[https://docs.djangoproject.com/en/5.2/topics/email/#emailmessage-
objects:~:text=The%20EmailMessage%20class%20is%20initialized%20with%20the%20following%20parameters%20(in%20the%20given%20order%2C%20if%20positional%20arguments%20are%20used).%20All%20parameters%20are%20optional%20and%20can%20be%20set%20at%20any%20time%20prior%20to%20calling%20the%20send()%20method.
the second and third tests should be equivalent].

(#27007 also added a fallback to application/octet-stream for non-utf-8
text content, but didn't include a test case for that behavior.)

See also
https://github.com/django/django/pull/18966#discussion_r2154081996
--
Ticket URL: <https://code.djangoproject.com/ticket/36478>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jun 24, 2025, 11:47:50 PM6/24/25
to django-...@googlegroups.com
#36478: EmailMessage handles utf-8 encoded text attachments differently in
constructor vs property
------------------------------+----------------------------------------
Reporter: Mike Edmunds | Owner: Mike Edmunds
Type: Bug | Status: assigned
Component: Core (Mail) | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+----------------------------------------
Description changed by Mike Edmunds:

Old description:
New description:

Encoded text attachments set directly in the EmailMessage.attachments
property are not processed like the same content passed to
EmailMessage(attachments=...) or EmailMessage.attach(...).

#27007 added EmailMessage.attach() handling for text content encoded as
utf-8 bytes. That code is also used for the attachments constructor
argument, but not for attachments set directly on the object property:
--
Ticket URL: <https://code.djangoproject.com/ticket/36478#comment:1>

Django

unread,
Jun 25, 2025, 3:01:49 AM6/25/25
to django-...@googlegroups.com
#36478: EmailMessage handles utf-8 encoded text attachments differently in
constructor vs property
------------------------------+----------------------------------------
Reporter: Mike Edmunds | Owner: Mike Edmunds
Type: Bug | Status: assigned
Component: Core (Mail) | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+----------------------------------------
Changes (by Sarah Boyce):

* stage: Unreviewed => Accepted

--
Ticket URL: <https://code.djangoproject.com/ticket/36478#comment:2>

Django

unread,
Jun 25, 2025, 3:15:24 AM6/25/25
to django-...@googlegroups.com
#36478: EmailMessage handles utf-8 encoded text attachments differently in
constructor vs property
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
| Edmunds
Type: Bug | Status: assigned
Component: Core (Mail) | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/36478#comment:3>

Django

unread,
Jun 26, 2025, 2:54:11 AM6/26/25
to django-...@googlegroups.com
#36478: EmailMessage handles utf-8 encoded text attachments differently in
constructor vs property
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
| Edmunds
Type: Bug | Status: closed
Component: Core (Mail) | Version: 5.2
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce <42296566+sarahboyce@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"23529b662793cdf4725d5f8ff58f0df94b343365" 23529b66]:
{{{#!CommitTicketReference repository=""
revision="23529b662793cdf4725d5f8ff58f0df94b343365"
Fixed #36478 -- Fixed inconsistent mail attachment handling.

Fixed an inconsistency between EmailMessage.attach() and .attachments
when attaching bytes content with a text/* mimetype. The attach()
function decodes UTF-8 bytes if possible and otherwise changes the
mimetype to application/octet-stream to preserve the content's unknown
encoding (refs #27007). Providing equivalent content directly in
EmailMessage.attachments did not apply the same logic, leading
to an "AttributeError: 'bytes' object has no attribute 'encode'"
in SafeMIMEText.set_payload().

Updated EmailMessage._create_mime_attachment() to match attach()'s
handling for text/* mimetypes with bytes content. Updated test cases
to accurately cover behavior on both paths.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36478#comment:4>
Reply all
Reply to author
Forward
0 new messages