[Django] #35581: Upgrade django.core.mail to use Python's modern email API

52 views
Skip to first unread message

Django

unread,
Jul 6, 2024, 3:17:22 PM7/6/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike | Owner: Mike Edmunds
Edmunds |
Type: | Status: assigned
Cleanup/optimization |
Component: Core | Version:
(Mail) |
Severity: Normal | Keywords: email, compat32
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
django.core.mail.EmailMessage currently uses
[https://docs.python.org/3/library/email.html#:~:text=email%3A%20Examples-,Legacy%20API%3A,-email.message.Message
Python's "legacy" email API]. Updating that code to Python's newer
[https://docs.python.org/3/library/email.html#:~:text=modern%20(unicode%20friendly)%20API%20of%20the%20email%20package
"modern" email API] would fix bugs and substantially simplify it.

[https://groups.google.com/g/django-developers/c/2zf9GQtjdIk django-
developers discussion]

The update should be mostly transparent for users of Django's documented
mail APIs, but will rework the internals of django.core.mail.message in
ways that may require changes to some third-party email backends and other
code that borrows undocumented (but popular) functions from that module.
In addition, parts of Django's mail test suite will need reworking to
avoid dependence on legacy implementation specifics.

Some relevant posts from django-developers:
* [https://groups.google.com/g/django-
developers/c/2zf9GQtjdIk/m/GWjimue9FAAJ Background and rationale] for
switching to Python's modern email API
* [https://groups.google.com/g/django-
developers/c/2zf9GQtjdIk/m/RcvARzp9BAAJ Proposed implementation details]
(some of these were modified in later discussion—in particular, we
[https://groups.google.com/g/django-
developers/c/2zf9GQtjdIk/m/4S7UekG4BAAJ don't expect to combine
EmailMultiAlternatives into EmailMessage] as part of this ticket, and we
[https://groups.google.com/g/django-
developers/c/2zf9GQtjdIk/m/LcBfqfizAAAJ won't deprecate MIMEBase
attachments] just yet)
* [https://groups.google.com/g/django-
developers/c/2zf9GQtjdIk/m/mKqz2OKtAAAJ Deprecation details] for the
documented BadHeaderError, SafeMIMEText and SafeMIMEMultipart, and the
undocumented forbid_multi_line_headers() and sanitize_address()
--
Ticket URL: <https://code.djangoproject.com/ticket/35581>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jul 6, 2024, 9:13:47 PM7/6/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* stage: Unreviewed => Accepted
* version: => dev

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:1>

Django

unread,
Aug 11, 2024, 12:57:59 PM8/11/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner:
Type: | YashRaj1506
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by YashRaj1506):

* owner: Mike Edmunds => YashRaj1506

Comment:

I will try to solve this.
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:2>

Django

unread,
Aug 11, 2024, 3:22:10 PM8/11/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* owner: YashRaj1506 => Mike Edmunds

Comment:

@YashRaj1506 I have a bunch of work underway on this and will open a PR
soon. Don't want you to needlessly duplicate effort. Code review on the PR
would be very welcome once it's ready.

Part of the delay is I've run into a handful of open issues in Python's
modern email API that may require further discussion:

- Modern set_content() forces a trailing newline on text content
(https://github.com/python/cpython/issues/121515). I think this is
probably fine, but it touches a lot of tests.
- Security issues in modern header serialization
(https://github.com/python/cpython/issues/80222,
https://github.com/python/cpython/issues/121284). I think these would
block this change.

Also trying to decide how best to handle Django's `EmailMessage.encoding`.
It's not documented, but a bunch of tests cover setting it and checking
the results. (The only relevant docs are
[https://docs.djangoproject.com/en/5.1/topics/email/#:~:text=The%20character%20set%20of%20email%20sent%20with%20django.core.mail%20will%20be%20set%20to%20the%20value%20of%20your%20DEFAULT_CHARSET%20setting.
this note] about the DEFAULT_CHARSET setting also applying to
django.core.mail.)
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:3>

Django

unread,
Aug 20, 2024, 8:53:44 PM8/20/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* has_patch: 0 => 1

Comment:

I've opened two sequential PRs, as suggested in the django-developers
discussion. Both are ready for review:

- https://github.com/django/django/pull/18502 improves the test suite for
django.core.mail while staying on the existing (legacy) API.
- https://github.com/medmunds/django/pull/2 implements the changeover to
the modern email API.

(The second PR is in my own Django fork so that it can be based on the
first PR without overlap. I'll reopen it upstream once the first PR is
closed. But reviews are welcome now if you don't mind working in my fork;
just note any discussion history there won't transfer to the eventual
upstream PR.)

Some additional notes are in the PR comments.
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:4>

Django

unread,
Aug 21, 2024, 3:46:29 PM8/21/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:5>

Django

unread,
Aug 24, 2024, 7:12:38 PM8/24/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* needs_better_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:6>

Django

unread,
Oct 11, 2024, 9:55:01 AM10/11/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by bcail):

* cc: bcail (added)

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:7>

Django

unread,
Oct 29, 2024, 6:13:37 AM10/29/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"4d76adfacde5594c5735a5e76b3d5478cb4ba8de" 4d76adfa]:
{{{#!CommitTicketReference repository=""
revision="4d76adfacde5594c5735a5e76b3d5478cb4ba8de"
Refs #35581 -- Verified attachments in the generated message in mail
tests.

This also removed send() calls, as this doesn't check the serialized
content, and
the backend tests cover sending.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:9>

Django

unread,
Oct 29, 2024, 6:13:37 AM10/29/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"889be2f45520ff7ee9296d89b30f33c1464112e3" 889be2f]:
{{{#!CommitTicketReference repository=""
revision="889be2f45520ff7ee9296d89b30f33c1464112e3"
Refs #35581 -- Clarified some test names and comments in mail tests.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:8>

Django

unread,
Oct 29, 2024, 6:14:39 AM10/29/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"cf4d902eb5c55b0b5966f8c920ba1009fae0d774" cf4d902]:
{{{#!CommitTicketReference repository=""
revision="cf4d902eb5c55b0b5966f8c920ba1009fae0d774"
Refs #35581 -- Reduced boilerplate in mail tests.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:11>

Django

unread,
Oct 29, 2024, 6:16:36 AM10/29/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"00861c4ca7ff51b24ee650e283a0c693573983cf" 00861c4c]:
{{{#!CommitTicketReference repository=""
revision="00861c4ca7ff51b24ee650e283a0c693573983cf"
Refs #35581 -- Identified mail tests that check for Python 2 behavior.

This also removed a duplicate CTE case (that used to be distinct in Python
2).
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:10>

Django

unread,
Dec 2, 2024, 9:19:23 AM12/2/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | 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/35581#comment:12>

Django

unread,
Dec 3, 2024, 5:17:24 AM12/3/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"5d7001b578272cd698cd6bfe64f980f00615ce62" 5d7001b]:
{{{#!CommitTicketReference repository=""
revision="5d7001b578272cd698cd6bfe64f980f00615ce62"
Refs #35581 -- Used modern email parser and helpers in mail tests.

- Used modern email API (policy.default) for tests that reparse
generated messages, and switched to modern accessors where helpful.
- Split get_raw_attachments() helper out of get_decoded_attachments(),
and used modern iter_attachments() to avoid finding nested attachments
in attached message/* emails.
- Stopped using legacy parseaddr.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:14>

Django

unread,
Dec 3, 2024, 5:17:25 AM12/3/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"ea34de3bd76fa87e84ae968f09105118ed360afb" ea34de3b]:
{{{#!CommitTicketReference repository=""
revision="ea34de3bd76fa87e84ae968f09105118ed360afb"
Refs #35581 -- Added tests for email parameters, attachments, MIME
structure, bcc header, encoding and sending.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:15>

Django

unread,
Dec 3, 2024, 5:17:26 AM12/3/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"bddd35cb1a45593935d28dcb08dd69e0bf7c0d2c" bddd35c]:
{{{#!CommitTicketReference repository=""
revision="bddd35cb1a45593935d28dcb08dd69e0bf7c0d2c"
Refs #35581 -- Improved reporting for failing tests in mail tests.

- Converted HeadersCheckMixin to MailTestsMixin for all shared helpers:
- Hoisted assertStartsWith() from BaseEmailBackendTests.
- Added matching assertEndsWith().
- Hoisted get_decoded_attachments() from MailTests.
- Improved failure reporting in assertMessageHasHeaders().
- Used unittest subTest() to improve handling of compound test cases.
- Replaced `assertTrue(test on string)` with custom assertions,
so that failure reporting is more informative than `True != False`.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:13>

Django

unread,
Dec 3, 2024, 5:17:58 AM12/3/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | 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: Ready for checkin => Accepted

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:16>

Django

unread,
Dec 3, 2024, 5:18:10 AM12/3/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* has_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:17>

Django

unread,
Dec 23, 2024, 7:34:14 PM12/23/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* has_patch: 0 => 1

Comment:

I've opened [https://github.com/django/django/pull/18966 PR 18966] that
implements the change to Python's modern email APIs.

Unfortunately, it's blocked by a couple of (public) Python security
issues. Absent some sort of holiday miracle, I think it's unlikely those
will be fixed before the Django 5.2 feature freeze. So realistically, this
is probably targeting 6.0. (Or later.)
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:18>

Django

unread,
Dec 23, 2024, 7:44:03 PM12/23/24
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mike Edmunds):

The PR includes a few changes that weren't covered by the original
[https://groups.google.com/g/django-developers/c/2zf9GQtjdIk deprecation
plan] from the django-developers discussion:

1. **Deprecated MIMEBase attachments:** I had [https://groups.google.com/g
/django-developers/c/2zf9GQtjdIk/m/LcBfqfizAAAJ originally proposed]
continuing support for legacy MIMEBase attachments without deprecation.
But it turns out the modern API's email.message.MIMEPart is a good
replacement, so the PR puts MIMEBase on the usual deprecation path. I've
also added a docs example of using MIMEPart for inline images.

2. **Dropped undocumented subtype attributes:** Removed support for the
undocumented `EmailMessage.mixed_subtype` and
`EmailMultiAlternatives.alternative_subtype` attributes. (But it will
raise an error on attempts to use them.)

3. **Dropped undocumented encoding=Charset():** The legacy code allows
setting the undocumented `EmailMessage.encoding` property to a legacy
email.charset.Charset object. There's no way to make that work with the
modern APIs, so I've dropped it. (You can still set encoding to a string
charset name, and that works properly.)
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:19>

Django

unread,
Apr 9, 2025, 3:46:20 AMApr 9
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"a627829e7b28bcb82129ab9fc3fa9c03d130f636" a627829]:
{{{#!CommitTicketReference repository=""
revision="a627829e7b28bcb82129ab9fc3fa9c03d130f636"
Refs #35581 -- Updated mail tests to include trailing newlines.

Python's modern email API will force a trailing newline onto all text/*
bodies and attachments. Updated mail tests to include (and check for)
the newline while still using the legacy email API.

See https://github.com/python/cpython/issues/121515 which reasons that,
apart from artificial test cases, most text content already ends in a
newline. If it doesn't, adding one won't change the meaning.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:20>

Django

unread,
Jun 18, 2025, 5:12:31 AMJun 18
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:21>

Django

unread,
Jun 19, 2025, 12:20:26 AMJun 19
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* needs_better_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:22>

Django

unread,
Jul 16, 2025, 9:33:25 AMJul 16
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"40d6eb2c0104f2119d5260b77402737cebf3f85c" 40d6eb2c]:
{{{#!CommitTicketReference repository=""
revision="40d6eb2c0104f2119d5260b77402737cebf3f85c"
Refs #35581 -- Added workaround for Python bug in mail tests.

See python/cpython#128110.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:24>

Django

unread,
Jul 16, 2025, 9:33:25 AMJul 16
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"5ca470a52e99b84446c838416fbdac921bfb8146" 5ca470a]:
{{{#!CommitTicketReference repository=""
revision="5ca470a52e99b84446c838416fbdac921bfb8146"
Refs #35581 -- Reduced implementation dependencies in mail tests.

Updated mail tests in preparation for migrating from Python's legacy
to modern email API. The updated tests will pass with either Python API,
and focus on desired outcomes (e.g., that a message with non-ASCII
content parses accurately at the receiving end) rather than specific
implementation details (e.g., where rfc2047 encoded-words are split).

In a few cases that are still implementation dependent, added comments
identifying behavior specific to the legacy email API and expected to
change under the modern one.

Added comments identifying tests that cover internal functions planned
for deprecation, and (where meaningful) added similar tests to verify
the equivalent behavior in non-deprecated features.

Removed obsolete tests left over from Python 2.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:23>

Django

unread,
Jul 17, 2025, 6:00:29 AMJul 17
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:25>

Django

unread,
Jul 19, 2025, 8:42:34 PMJul 19
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):

* needs_better_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:26>

Django

unread,
Jul 23, 2025, 8:59:36 AMJul 23
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | 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/35581#comment:27>

Django

unread,
Jul 25, 2025, 7:50:13 AMJul 25
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution:
Keywords: email, compat32 | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"20c62199ffe0de1410083657a6d5bac799592210" 20c62199]:
{{{#!CommitTicketReference repository=""
revision="20c62199ffe0de1410083657a6d5bac799592210"
Refs #35581 -- Added missing test for lazy email headers.

EmailMessage is intended to support lazy strings in any header field
(via coercion to `str` in forbid_multi_line_headers() called from
SafeMIMEMessage/Text/Multipart.__setitem__).
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:28>

Django

unread,
Jul 25, 2025, 7:50:14 AMJul 25
to django-...@googlegroups.com
#35581: Upgrade django.core.mail to use Python's modern email API
-------------------------------------+-------------------------------------
Reporter: Mike Edmunds | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: closed
Component: Core (Mail) | Version: dev
Severity: Normal | Resolution: fixed
Keywords: email, compat32 | 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:"9ab1991689000821a4d86b8617e1c1455a327482" 9ab19916]:
{{{#!CommitTicketReference repository=""
revision="9ab1991689000821a4d86b8617e1c1455a327482"
Fixed #35581 -- Updated django.core.mail to Python's modern email API.

- Changed EmailMessage.message() to construct a "modern email API"
email.message.EmailMessage and added policy keyword arg.
- Added support for modern MIMEPart objects in EmailMessage.attach()
(and EmailMessage constructor, EmailMessage.attachments list).
- Updated SMTP EmailBackend to use modern email.policy.SMTP.

Deprecated:
- Attaching MIMEBase objects (replace with MIMEPart)
- BadHeaderError (modern email uses ValueError)
- SafeMIMEText, SafeMIMEMultipart (unnecessary for modern email)
- django.core.mail.forbid_multi_line_headers()
(undocumented, but exposed via `__all__` and in wide use)
- django.core.mail.message.sanitize_address()
(undocumented, but in wide use)

Removed without deprecation (all undocumented):
- EmailMessage.mixed_subtype
- EmailMultiAlternatives.alternative_subtype
- Support for setting (undocumented) EmailMessage.encoding property
to a legacy email.charset.Charset object

Related changes:
- Dropped tests for incorrect RFC 2047 encoding of non-ASCII email
address localparts. This is specifically prohibited by RFC 2047, and
not supported by any known MTA or email client. (Python still
mis-applies encoded-word to non-ASCII localparts, but it is a bug that
may be fixed in the future.)
- Added tests that try to discourage using Python's legacy email APIs
in future updates to django.core.mail.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35581#comment:29>
Reply all
Reply to author
Forward
0 new messages