> I wish this discussion was on the forum so I could mark Pankaj’s response as spam 😅
And here I was thinking it was another +1 (that also gently poked fun at my own overly-verbose tendencies). <g> Speaking of the forum, I've taken the "combine EmailMessage and EmailMultiAlternatives" idea that was dropped from this proposal, and incorporated it into a separate proposal that's looking for feedback over there: https://forum.djangoproject.com/t/proposal-simplify-sending-testing-html-in-emailmessage/32844. (Apologies for the cross-post; I get the impression some of the people with opinions on django.core.mail are maybe here on django-developers but not the forum. There are also a couple of other interesting email-related threads active over there.) - Mike On Sunday, July 21, 2024 at 3:59:22 AM UTC-7 Adam Johnson wrote: > I wish this discussion was on the forum so I could mark Pankaj’s response > as spam 😅 > > On Sun, 21 Jul 2024, at 08:26, Othniel Davidson wrote: > > Thank you for the update > > On Sat, Jul 20, 2024 at 15:26 Pankaj Kumar <pankaj...@gmail.com> wrote: > > Hi Sir, > I hope this message finds you well. > > I am writing to inform you that we have reviewed and decided to accept the > proposal to upgrade django.core.mail to Python's modern email API. We > believe that this upgrade will bring significant improvements to our > system's performance and maintainability. > > I would also like to extend my sincere apologies for the delay in our > response. I received the proposal seven days ago, and I regret not being > able to get back to you sooner. Thank you for your patience and > understanding in this matter. > > We are looking forward to the successful implementation of this upgrade > and are excited about the enhancements it will bring to our project. Please > let us know the next steps and how we can assist in the process. > > Thank you once again for your proposal and for your continued support. > > Best regards, > > - PANKAJ NEEMA > > > > On Sat, 6 Jul 2024 at 04:00, Mike Edmunds <medm...@gmail.com> wrote: > > On Friday, June 28, 2024 at 1:07:35 PM UTC-7 Florian Apolloner wrote: > > Are all of those documented? If not we can simply remove them > (especially if the deprecation implementation turns out to be a PITA). > > It sort of depends on the definition of "documented." I've dug into > real-world usage; results and proposals below. > > Incidentally, I thought there was (used to be?) a policy that internal > undocumented APIs were fair game for use by third-party libraries, > subclassing, etc., so long as they didn't start with an underscore. (But > "private" underscore APIs could have breaking changes at any time.) Am I > remembering that wrong? Or was internal API stability only guaranteed for > patch-level releases? > > *Should go through deprecation process* (in my opinion, sorted roughly by > real-world usage) > > - *BadHeaderError* is mentioned in the docs > > <https://docs.djangoproject.com/en/5.0/topics/email/#preventing-header-injection> > as > potentially raised during sending > - Exposed in django.core.mail.__all__ > - Real-world use: ~2300+ cases in GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*BadHeaderError%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code>, > > seems to be primarily error handling > > <https://github.com/python/pythondotorg/blob/2a45f8cbb0254f7f0a62e5aba0e6dd2349686559/events/views.py#L145> > - Proposal: deprecate on import. (Modern Python email API raises > ValueError for newlines in headers. In our deprecation, we'll need > `BadHeaderError = ValueError`—rather than subclassing ValueError—to > preserve behavior of existing error handling code.) > - Suggested replacement for docs: change `except BadHeaderError` to > `except ValueError` > - *sanitize_address()* is not documented, but is widely used > - Not exposed in django.core.mail (have to import from > django.core.mail.message) > - Real-world use: ~430 cases in GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*sanitize_address%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code>, > > often in custom EmailBackend implementations > > <https://github.com/Blueshoe/django-exchange/blob/fe49ed8f934d147d0435c9669239684ab0af6eaa/django_exchange/backend.py#L69-L70> > or > for special case handling > > <https://github.com/zulip/zulip/blob/41b431de70e9718ca60ce3307b392eb04c1e86a9/zerver/lib/send_email.py#L113> > that > needs knowledge of how django.core.mail handles addresses. > - Proposal: deprecate. (Have to keep implementation around anyway > as part of other deprecated code.) > - Suggested replacement for docs: none (it's an internal, > undocumented API). Or we could say it depends on the use case: just > skip it > if no longer relevant, use something like Python's modern email Address > object if you need formatting cleanup, or copy sanitize_address() into > your > code and adapt for your needs. (Incidentally, it's already pretty > common to copy > > <https://github.com/search?q=symbol%3Asanitize_address+language%3Apython+NOT+path%3Adjango%2Fcore%2Fmail&type=code> > > and adapt sanitize_address().) > - *SafeMIMEText* and *SafeMIMEMultipart* are mentioned in the docs > > <https://docs.djangoproject.com/en/5.0/topics/email/#the-emailmessage-class:~:text=constructs%20a%20django.core.mail.SafeMIMEText%20object%20(a%20subclass%20of%20Python%E2%80%99s%20MIMEText%20class)%20or%20a%20django.core.mail.SafeMIMEMultipart%20object> > > as the return type of EmailMessage.message(), but not further documented > - Exposed in django.core.mail.__all__ > - Real-world use: ~240 cases in GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*SafeMIME%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code>, > > both for type checking > > <https://github.com/freelawproject/courtlistener/blob/430747e03e085f6d83c02e2a9ce8546b648bbefa/cl/users/email_handlers.py#L221> > > and for constructing text or message attachments > > <https://github.com/openedx/edx-platform/blob/57dd2135a655bc4e6d29e4e90706ac8955f6d9b2/openedx/core/djangoapps/credit/email_utils.py#L100> > - Proposal: deprecate (on import, to catch type checking uses) > - Suggested replacement for docs: > django.mail.EmailMessage.message() will now return an > email.message.EmailMessage; to construct text or message attachments, > switch to modern email.message.EmailMessage > - [Tip for django-stubs: SafeMIMEText, SafeMIMEMultipart, and > email.message.EmailMessage are all subclasses of email.message.Message] > - *forbid_multi_line_headers()* is not documented, but seems to be > an intentional part of the public API for implementing pluggable email > backends > - Exposed in django.core.mail as part of ticket-10355 > <https://code.djangoproject.com/ticket/10355> "add support for > email backends," and added to __all__ by Tim Graham via ticket-21302 > <https://code.djangoproject.com/ticket/21302> > - Real-world use: ~100 cases in GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*forbid_multi_line_headers%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code&p=1>, > > mostly false positives; at least one real use in > openedx/edx-platform > > <https://github.com/openedx/edx-platform/blob/57dd2135a655bc4e6d29e4e90706ac8955f6d9b2/lms/djangoapps/bulk_email/tasks.py#L409> > > to construct a from address > - Proposal: deprecate. (Have to keep implementation around anyway > as part of deprecated SafeMIME*.) > - Suggested replacement for docs: modern Python email already > detects CR/NL in headers; or use `if '\r' in value or '\n' in value` if > your code needs to check it directly > > > *Can remove without deprecation* > > (We'll have to keep these around as part of the implementation of things > that *are* being deprecated, but can move them to a place that would > break imports in existing code.) > > - *MIMEMixin* and *SafeMIMEMessage* are not documented, not exposed in > django.core.mail > - Used to implement SafeMIMEText and SafeMIMEMultipart > - Real-world use: virtually nonexistent - GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*%28MIMEMixin%7CSafeMIMEMessage%29%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code> > - Proposal: remove without deprecation > - *utf8_charset*, *utf8_charset_qp*, > *RFC5322_EMAIL_LINE_LENGTH_LIMIT* are not documented, not exposed in > django.core.mail > - Used to implement MIMEMixin, SafeMIME*; not exposed in > django.core.mail > - Real-world use: virtually nonexistent - GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*%28utf8_charset%7CRFC5322_EMAIL_LINE_LENGTH_LIMIT%29%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code> > > is mainly false positives, one use in third-party library > > <https://github.com/nekonaq/djangoexpack/blob/6ad39bb305cbac7cafbbc323a9db21830f69b811/djangoexpack/mail/__init__.py#L34> > - Proposal: remove without deprecation > - *ADDRESS_HEADERS* is not documented, not exposed in > django.core.mail > - Used to implement forbid_multi_line_headers() > - Real-world use: virtually nonexistent - GitHub code search > > <https://github.com/search?q=%2F%5Efrom%5Cs%2Bdjango%5C.core%5C.mail%28%5C.message%29%3F%5Cs%2Bimport%28.%7C%5Cn%29*ADDRESS_HEADERS%2F+language%3Apython+NOT+path%3Adjango%2Fcore&type=code> > > is mainly false positives, one use in third-party code > > <https://github.com/APSL/django-yubin/blob/2dcb33d08a5c8a0001e1e5a6abd0b8d940afa0b6/django_yubin/models.py#L29> > - Proposal: remove without deprecation > > > [Real-world GitHub code search numbers are clearly not exact. I've tried > to catch wrapped import statements and ignore Django forks and vendored > copies, but it's not perfect. The search expressions find false positives > (overcount) in comments and obsolete branches, as well as forks of popular > libraries. But they miss (undercount) some creative approaches > <https://github.com/Tivix/django-common/blob/407d208121011a8425139e541629554114d96c18/django_common/email_backends.py#L29-L30> > and > any usage outside of a public repo hosted on GitHub.] > > - Mike > > > -- > You received this message because you are subscribed to the Google Groups > "Django developers (Contributions to Django itself)" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to django-develop...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-developers/95e993a0-4b61-47d8-a365-d63676187f43n%40googlegroups.com > > <https://groups.google.com/d/msgid/django-developers/95e993a0-4b61-47d8-a365-d63676187f43n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > > -- > You received this message because you are subscribed to the Google Groups > "Django developers (Contributions to Django itself)" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to django-develop...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-developers/CAPD84HnRTfZ-z1R5%3D0zNeLwdnbaECgRbCHOFV9TiFfK9bC0dQw%40mail.gmail.com > > <https://groups.google.com/d/msgid/django-developers/CAPD84HnRTfZ-z1R5%3D0zNeLwdnbaECgRbCHOFV9TiFfK9bC0dQw%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > > > -- > You received this message because you are subscribed to the Google Groups > "Django developers (Contributions to Django itself)" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to django-develop...@googlegroups.com. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-developers/CAPRrvgxwxop48-ZFZdKvuLxG0CYUbMD4uFCaSWC2P-q2_fxeiQ%40mail.gmail.com > > <https://groups.google.com/d/msgid/django-developers/CAPRrvgxwxop48-ZFZdKvuLxG0CYUbMD4uFCaSWC2P-q2_fxeiQ%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > > > -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/048efbc8-eebf-4353-9924-d81c73798207n%40googlegroups.com.