Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed #35365 -- Add RFC 3824 Auto-Submitted header to emails by default #18099

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -192,6 +192,7 @@ answer newbie questions, and generally made Django that much better:
Can Burak Çilingir <canburak@cs.bilgi.edu.tr>
Can Sarıgöl <ertugrulsarigol@gmail.com>
Carl Meyer <carl@oddbird.net>
Carter Gracin <carter.rgracin@gmail.com>
Carles Pina i Estany <carles@pina.cat>
Carlos Eduardo de Paula <carlosedp@gmail.com>
Carlos Matías de la Torre <cmdelatorre@gmail.com>
Expand Down
2 changes: 2 additions & 0 deletions django/core/mail/__init__.py
Expand Up @@ -13,6 +13,7 @@
BadHeaderError,
EmailMessage,
EmailMultiAlternatives,
NoAutoSubmittedHeaderEmailMessage,
SafeMIMEMultipart,
SafeMIMEText,
forbid_multi_line_headers,
Expand All @@ -26,6 +27,7 @@
"DNS_NAME",
"EmailMessage",
"EmailMultiAlternatives",
"NoAutoSubmittedHeaderEmailMessage",
"SafeMIMEText",
"SafeMIMEMultipart",
"DEFAULT_ATTACHMENT_MIME_TYPE",
Expand Down
20 changes: 20 additions & 0 deletions django/core/mail/message.py
Expand Up @@ -280,9 +280,15 @@ def message(self):
if "message-id" not in header_names:
# Use cached DNS_NAME for performance
msg["Message-ID"] = make_msgid(domain=DNS_NAME)

if "Auto-Submitted" not in self.extra_headers:
# Default to adding the Auto-Submitted: auto-generated header
self.extra_headers["Auto-Submitted"] = "auto-generated"

for name, value in self.extra_headers.items():
if name.lower() != "from": # From is already handled
msg[name] = value

return msg

def recipients(self):
Expand Down Expand Up @@ -432,6 +438,20 @@ def _set_list_header_if_not_empty(self, msg, header, values):
msg[header] = value


class NoAutoSubmittedHeaderEmailMessage(EmailMessage):
"""
A version of EmailMessage that does not have the default
Auto-Submitted: auto-generated header attached to it.
"""

def message(self):
msg = super().message()
if "Auto-Submitted" in msg:
del msg["Auto-Submitted"]

return msg


class EmailMultiAlternatives(EmailMessage):
"""
A version of EmailMessage that makes it easy to send multipart/alternative
Expand Down
12 changes: 11 additions & 1 deletion docs/releases/5.1.txt
Expand Up @@ -193,7 +193,17 @@ Decorators
Email
~~~~~

* ...
* :class:`<django.core.mail.EmailMessage>` now attaches a default header of "Auto-Submitted : auto-generated"
to outgoing emails. You can opt-out of this by using :class:`<django.core.mail.NoAutoSubmittedHeaderEmailMessage>`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The angle brackets are not required and should be removed.

* :class:`<django.core.mail.EmailMessage>` now attaches a default header of "Auto-Submitted: auto-generated"
to outgoing emails. You can opt-out of this by using :class:`<django.core.mail.NoAutoSubmittedHeaderEmailMessage>`
* :class:`~django.core.mail.EmailMessage` now attaches a default header of "Auto-Submitted : auto-generated"
to outgoing emails. You can opt-out of this by using :class:`~django.core.mail.NoAutoSubmittedHeaderEmailMessage`
* :class:`<django.core.mail.EmailMessage>` now attaches a default header of "Auto-Submitted: auto-generated"
to outgoing emails. You can opt-out of this by using :class:`~django.core.mail.NoAutoSubmittedHeaderEmailMessage`
* :class:`~django.core.mail.EmailMessage` now attaches a default header of "Auto-Submitted: auto-generated"
to outgoing emails. You can opt-out of this by using :class:`~django.core.mail.NoAutoSubmittedHeaderEmailMessage`
which does not attach this default header.

Error Reporting
~~~~~~~~~~~~~~~
Expand Down
16 changes: 15 additions & 1 deletion docs/topics/email.txt
Expand Up @@ -288,7 +288,21 @@ All parameters are optional and can be set at any time prior to calling the
* ``headers``: A dictionary of extra headers to put on the message. The
keys are the header name, values are the header values. It's up to the
caller to ensure header names and values are in the correct format for
an email message. The corresponding attribute is ``extra_headers``.
an email message. The corresponding attribute is ``extra_headers``. The
EmailMessage class attaches a default header of ``Auto-Submitted :
auto-generated ``. The sender can opt-out of this default header by using
the ``NoAutoSubmittedHeaderEmailMessage`` subclass.

For example::

from django.core.mail import NoAutoSubmittedHeaderEmailMessage

email = NoAutoSubmittedHeaderEmailMessage(
"Hello",
"Body goes here",
"from@example.com",
["to@example.com"]
)

* ``cc``: A list or tuple of recipient addresses used in the "Cc" header
when sending the email.
Expand Down
13 changes: 13 additions & 0 deletions tests/mail/tests.py
Expand Up @@ -19,6 +19,7 @@
DNS_NAME,
EmailMessage,
EmailMultiAlternatives,
NoAutoSubmittedHeaderEmailMessage,
mail_admins,
mail_managers,
send_mail,
Expand Down Expand Up @@ -449,6 +450,18 @@ def test_reply_to_in_headers_only(self):
).message()
self.assertEqual(message["Reply-To"], "reply_to@example.com")

def test_default_auto_generated_header(self):
message = EmailMessage(
"Subject", "Content", "from@example.com", ["to@example.com"]
).message()
self.assertEqual(message["Auto-Submitted"], "auto-generated")

def test_no_default_auto_generated_header(self):
message = NoAutoSubmittedHeaderEmailMessage(
"Subject", "Content", "from@example.com", ["to@example.com"]
).message()
self.assertNotIn("Auto-Submitted", message)

def test_multiple_message_call(self):
"""
Regression for #13259 - Make sure that headers are not changed when
Expand Down