Opened 7 months ago
Last modified 4 weeks ago
#35581 assigned Cleanup/optimization
Upgrade django.core.mail to use Python's modern email API
Reported by: | Mike Edmunds | Owned by: | Mike Edmunds |
---|---|---|---|
Component: | Core (Mail) | Version: | dev |
Severity: | Normal | Keywords: | email, compat32 |
Cc: | bcail | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
django.core.mail.EmailMessage currently uses Python's "legacy" email API. Updating that code to Python's newer "modern" email API would fix bugs and substantially simplify it.
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:
- Background and rationale for switching to Python's modern email API
- Proposed implementation details (some of these were modified in later discussion—in particular, we don't expect to combine EmailMultiAlternatives into EmailMessage as part of this ticket, and we won't deprecate MIMEBase attachments just yet)
- Deprecation details for the documented BadHeaderError, SafeMIMEText and SafeMIMEMultipart, and the undocumented forbid_multi_line_headers() and sanitize_address()
Change History (19)
comment:1 by , 7 months ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Version: | → dev |
comment:2 by , 5 months ago
Owner: | changed from | to
---|
comment:3 by , 5 months ago
Owner: | changed from | to
---|
@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 this note about the DEFAULT_CHARSET setting also applying to django.core.mail.)
comment:4 by , 5 months ago
Has patch: | set |
---|
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.
comment:5 by , 5 months ago
Patch needs improvement: | set |
---|
comment:6 by , 5 months ago
Patch needs improvement: | unset |
---|
comment:7 by , 3 months ago
Cc: | added |
---|
comment:12 by , 7 weeks ago
Triage Stage: | Accepted → Ready for checkin |
---|
comment:16 by , 7 weeks ago
Triage Stage: | Ready for checkin → Accepted |
---|
comment:17 by , 7 weeks ago
Has patch: | unset |
---|
comment:18 by , 4 weeks ago
Has patch: | set |
---|
I've opened 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.)
comment:19 by , 4 weeks ago
The PR includes a few changes that weren't covered by the original deprecation plan from the django-developers discussion:
- Deprecated MIMEBase attachments: I had 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.
- Dropped undocumented subtype attributes: Removed support for the undocumented
EmailMessage.mixed_subtype
andEmailMultiAlternatives.alternative_subtype
attributes. (But it will raise an error on attempts to use them.)
- 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.)
I will try to solve this.