From 0596263c3136bc26cffa670e5322bd0aa56c4d34 Mon Sep 17 00:00:00 2001 From: nessita <124304+nessita@users.noreply.github.com> Date: Thu, 24 Apr 2025 10:11:16 -0300 Subject: [PATCH] Fixed #36309 -- Made email alternatives and attachments pickleable. Regression in aba0e541caaa086f183197eaaca0ac20a730bbe4 and in d5bebc1c26d4c0ec9eaa057aefc5b38649c0ba3b. Thanks Florent Messa for the report, and Jake Howard and Claude Paroz for the review. --- django/core/mail/message.py | 4 ++-- docs/releases/5.2.1.txt | 3 +++ tests/mail/tests.py | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/django/core/mail/message.py b/django/core/mail/message.py index adcd9fc504..421e353bfa 100644 --- a/django/core/mail/message.py +++ b/django/core/mail/message.py @@ -191,8 +191,8 @@ class SafeMIMEMultipart(MIMEMixin, MIMEMultipart): MIMEMultipart.__setitem__(self, name, val) -EmailAlternative = namedtuple("Alternative", ["content", "mimetype"]) -EmailAttachment = namedtuple("Attachment", ["filename", "content", "mimetype"]) +EmailAlternative = namedtuple("EmailAlternative", ["content", "mimetype"]) +EmailAttachment = namedtuple("EmailAttachment", ["filename", "content", "mimetype"]) class EmailMessage: diff --git a/docs/releases/5.2.1.txt b/docs/releases/5.2.1.txt index 82df478d96..a79d61c60a 100644 --- a/docs/releases/5.2.1.txt +++ b/docs/releases/5.2.1.txt @@ -48,3 +48,6 @@ Bugfixes * Fixed a regression in Django 5.2, introduced when fixing :cve:`2025-26699`, where the :tfilter:`wordwrap` template filter did not preserve empty lines between paragraphs after wrapping text (:ticket:`36341`). + +* Fixed a regression in Django 5.2 that caused a crash when serializing email + alternatives or attachments due to named tuple mismatches (:ticket:`36309`). diff --git a/tests/mail/tests.py b/tests/mail/tests.py index 3fb1a47bc7..301e589409 100644 --- a/tests/mail/tests.py +++ b/tests/mail/tests.py @@ -1,5 +1,6 @@ import mimetypes import os +import pickle import shutil import socket import sys @@ -654,6 +655,23 @@ class MailTests(MailTestsMixin, SimpleTestCase): self.assertIn(html_content, msg.message().as_string()) + def test_alternatives_and_attachment_serializable(self): + html_content = "
This is html
" + mime_type = "text/html" + + msg = EmailMultiAlternatives(alternatives=[(html_content, mime_type)]) + msg.attach("test.txt", "This is plain text.", "plain/text") + + # Alternatives and attachments can be serialized. + restored = pickle.loads(pickle.dumps(msg)) + + self.assertEqual(restored.subject, msg.subject) + self.assertEqual(restored.body, msg.body) + self.assertEqual(restored.from_email, msg.from_email) + self.assertEqual(restored.to, msg.to) + self.assertEqual(restored.alternatives, msg.alternatives) + self.assertEqual(restored.attachments, msg.attachments) + def test_none_body(self): msg = EmailMessage("subject", None, "from@example.com", ["to@example.com"]) self.assertEqual(msg.body, "")