diff options
| author | diaxoaine <42137630+diaxoaine@users.noreply.github.com> | 2026-06-11 09:58:41 +0700 |
|---|---|---|
| committer | nessita <124304+nessita@users.noreply.github.com> | 2026-06-16 19:56:20 -0300 |
| commit | 09434486302078c3649e034dfa74cf3f102db20b (patch) | |
| tree | e9dd12e8dd1d1e591c516e4f26e3eaa0bd630cd8 | |
| parent | b5b53afa29c53a79ae92ed5298144db0cab0ea3b (diff) | |
Fixed #37152 -- Raised ValueError when Bcc is used in EmailMessage headers.
Bcc addresses are sent via the SMTP envelope and must never appear in
the message itself. A "Bcc" key in `extra_headers` was not excluded like
From/To/Cc/Reply-To, so it leaked into the generated message as a
visible header.
Thanks Mike Edmunds for reviews.
| -rw-r--r-- | django/core/mail/message.py | 8 | ||||
| -rw-r--r-- | docs/releases/6.1.txt | 4 | ||||
| -rw-r--r-- | docs/topics/email.txt | 2 | ||||
| -rw-r--r-- | tests/mail/tests.py | 12 |
4 files changed, 24 insertions, 2 deletions
diff --git a/django/core/mail/message.py b/django/core/mail/message.py index 549b8050fe..2b396d870b 100644 --- a/django/core/mail/message.py +++ b/django/core/mail/message.py @@ -360,8 +360,14 @@ class EmailMessage: # Use cached DNS_NAME for performance msg["Message-ID"] = make_msgid(domain=DNS_NAME) for name, value in self.extra_headers.items(): + header = name.lower() + if header == "bcc": + raise ValueError( + 'Bcc is not a valid email header. Use the "bcc" ' + "argument to specify blind carbon copy recipients." + ) # Avoid headers handled above. - if name.lower() not in {"from", "to", "cc", "reply-to"}: + if header not in {"from", "to", "cc", "reply-to"}: msg[name] = force_str(value, strings_only=True) self._idna_encode_address_header_domains(msg) return msg diff --git a/docs/releases/6.1.txt b/docs/releases/6.1.txt index adb66a013d..03a9b8cdfd 100644 --- a/docs/releases/6.1.txt +++ b/docs/releases/6.1.txt @@ -470,6 +470,10 @@ Email ``EmailMessage``. (This behavior was never documented. The ``send()`` method will still *use* a ``connection`` that is set on the message before sending.) +* :meth:`.EmailMessage.message` now raises a ``ValueError`` if ``Bcc`` is + included in the ``headers`` argument or ``extra_headers`` attribute. Use the + ``bcc`` argument instead. + Models ------ diff --git a/docs/topics/email.txt b/docs/topics/email.txt index d52ffd12ed..c9e3cfd1ce 100644 --- a/docs/topics/email.txt +++ b/docs/topics/email.txt @@ -505,7 +505,7 @@ email backend API :ref:`provides an alternative * ``cc``: A list or tuple of recipient addresses used in the "Cc" header when sending the email. - * ``bcc``: A list or tuple of addresses used in the "Bcc" header when + * ``bcc``: A list or tuple of addresses used for blind carbon copies when sending the email. * ``reply_to``: A list or tuple of recipient addresses used in the diff --git a/tests/mail/tests.py b/tests/mail/tests.py index 7963b81892..01a37284c1 100644 --- a/tests/mail/tests.py +++ b/tests/mail/tests.py @@ -397,6 +397,18 @@ class EmailMessageTests(MailTestsMixin, SimpleTestCase): self.assertNotIn("bcc@example.com", message.as_string()) self.assertEqual(email.recipients(), ["to@example.com", "bcc@example.com"]) + def test_bcc_in_headers_raises_error(self): + email = EmailMessage( + to=["to@example.com"], + headers={"Bcc": "bcc@example.com"}, + ) + msg = ( + 'Bcc is not a valid email header. Use the "bcc" argument to ' + "specify blind carbon copy recipients." + ) + with self.assertRaisesMessage(ValueError, msg): + email.message() + def test_reply_to(self): with self.subTest("Single Reply-To"): email = EmailMessage( |
