@@ -495,7 +495,8 @@ email backend API :ref:`provides an alternative
495495 * ``body``: The body text. This should be a plain text message.
496496
497497 * ``from_email``: The sender's address. Both ``fred@example.com`` and
498- ``"Fred" <fred@example.com>`` forms are legal. If omitted, the
498+ ``"Fred" <fred@example.com>`` forms are supported (see
499+ :ref:`formatting-addresses`). If omitted, the
499500 :setting:`DEFAULT_FROM_EMAIL` setting is used.
500501
501502 * ``to``: A list or tuple of recipient addresses.
@@ -792,47 +793,112 @@ example::
792793 msg.content_subtype = "html" # Main content is now text/html
793794 msg.send()
794795
795- Preventing header injection
796- ---------------------------
796+ Safely sending email
797+ --------------------
798+
799+ Any public website that can send email will eventually be targeted by attempts
800+ to abuse it for spam, phishing, or other malicious content. While a complete
801+ discussion of vulnerabilities in sending email is beyond the scope of Django's
802+ documentation, there are many references available on the web. Two good
803+ starting points are:
804+
805+ * Princeton University's guidance on `preventing email abuse in web forms`_.
806+ Although this is an internal reference for users of Princeton's Drupal Site
807+ Builder, nearly all of its advice applies equally to sites built with Django
808+ (or any web framework).
809+
810+ * OWASP's `Email Validation and Verification in Identity Systems Cheat Sheet`_.
811+ This primarily covers using email in authentication contexts. While many of
812+ its recommendations are handled by :mod:`django.contrib.auth` and other
813+ Django features, items like rate limiting and securing email change workflows
814+ are the developer's responsibility.
815+
816+ Thinking through how email might be abused (and taking steps to mitigate it) is
817+ especially important if your site can send to unverified addresses. Features
818+ like newsletter sign-up, contact forms that cc or auto-reply to the sender, and
819+ "share this page" can be attractive targets.
820+
821+ .. _preventing email abuse in web forms:
822+ https://sitebuilder.princeton.edu/site-administration/spam
823+ .. _Email Validation and Verification in Identity Systems Cheat Sheet:
824+ https://cheatsheetseries.owasp.org/cheatsheets/Email_Validation_and_Verification_Cheat_Sheet.html
825+
826+ .. _formatting-addresses:
827+
828+ Formatting email addresses
829+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
830+
831+ Email addresses allow a "friendly" display name alongside the ``user@domain``
832+ address. For example, you could include your company name in the
833+ :setting:`DEFAULT_FROM_EMAIL` setting::
834+
835+ DEFAULT_FROM_EMAIL = '"Example, Inc." <contact@example.com>'
836+
837+ The double quotes around ``"Example, Inc."`` are needed so the comma isn't read
838+ as separating two different addresses. A fixed address, written out by hand as
839+ in the example above, is safe, but composing one from variable parts
840+ (especially untrusted input) needs more care.
797841
798- `Header injection`_ is a security exploit in which an attacker inserts extra
799- email headers to control the "To:" and "From:" in email messages that your
800- scripts generate.
842+ .. warning::
801843
802- The Django email functions outlined above all protect against header injection
803- by forbidding newlines in header values. If any ``subject``, ``from_email`` or
804- ``recipient_list`` contains a newline (in either Unix, Windows or Mac style),
805- the email function (e.g. :func:`send_mail`) will raise :exc:`ValueError` and,
806- hence, will not send the email. It's your responsibility to validate all data
807- before passing it to the email functions.
844+ Never use string formatting to build an email address from variable parts.
845+ For example, ``f'"{name}" <{email}>'`` is **unsafe**.
808846
809- If a ``message`` contains headers at the start of the string, the headers will
810- be printed as the first bit of the email message.
847+ Email address headers have complex syntax rules (much like HTML or SQL), so
848+ constructing them by combining strings creates an injection vulnerability. Even
849+ if you've :class:`validated <.EmailValidator>` the format of ``email``, an
850+ attacker could exploit the ``name`` portion to inject additional addresses.
811851
812- Here's an example view that takes a ``subject``, ``message`` and ``from_email``
813- from the request's POST data, sends that to ``admin@example.com`` and redirects
814- to "/contact/thanks/" when it's done::
852+ To avoid this, always use a well-tested library specifically meant to format
853+ email addresses, like Python's :class:`email.headerregistry.Address` class (the
854+ replacement for the legacy :func:`~email.utils.formataddr` function, which does
855+ not support internationalized domain names).
856+
857+ For example, to include a user's full name when sending them email (where
858+ ``user`` is an instance of the default :class:`.User` model)::
815859
816860 from django.core.mail import send_mail
817- from django.http import HttpResponse, HttpResponseRedirect
818-
819-
820- def send_email(request):
821- subject = request.POST.get("subject", "")
822- message = request.POST.get("message", "")
823- from_email = request.POST.get("from_email", "")
824- if subject and message and from_email:
825- try:
826- send_mail(subject, message, from_email, ["admin@example.com"])
827- except ValueError:
828- return HttpResponse("Invalid header found.")
829- return HttpResponseRedirect("/contact/thanks/")
830- else:
831- # In reality we'd use a form class
832- # to get proper validation errors.
833- return HttpResponse("Make sure all fields are entered and valid.")
834-
835- .. _Header injection: http://www.nyphp.org/phundamentals/8_Preventing-Email-Header-Injection.html
861+ from email.headerregistry import Address
862+
863+
864+ def send_mail_to_user(user, subject, body, from_email=None):
865+ # Safely create an email address with the user's name.
866+ # (addr_spec is the technical term for the user@domain address.)
867+ address = Address(
868+ display_name=user.get_full_name(),
869+ addr_spec=user.email,
870+ )
871+ send_mail(subject, body, from_email, [address])
872+
873+ Django's built-in email backends support using
874+ :class:`~email.headerregistry.Address` objects directly in any address field,
875+ as shown here. So do many custom and third-party email backends. But if this
876+ causes a ``TypeError`` or other problem with a particular backend, use
877+ ``str(address)`` to convert the object to a safe, properly formatted string.
878+
879+ Preventing header injection
880+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
881+
882+ `Email header injection`_ is a security exploit in which an attacker
883+ manipulates email headers to change the intended sender or recipients, subject,
884+ or potentially even the entire visible message body.
885+
886+ One type of header injection exploits address header syntax. You are
887+ responsible for preventing this when constructing email addresses from
888+ user-supplied input, as described in :ref:`formatting-addresses` above.
889+
890+ Another (perhaps better understood) attack, CRLF injection, uses carriage
891+ return and line feed characters to insert additional headers into the email.
892+ Django prevents this by raising a :exc:`ValueError` if those characters appear
893+ in any header field when trying to send the message.
894+
895+ Django's CRLF protection relies on using Python's modern
896+ :class:`~email.policy.EmailPolicy` in Django's :meth:`EmailMessage.message`.
897+ Custom email backends that don't call that function, or that call it with the
898+ legacy :data:`~email.policy.compat32` policy, are responsible for implementing
899+ their own CRLF injection prevention.
900+
901+ .. _Email header injection: https://en.wikipedia.org/wiki/Email_injection
836902
837903.. _topics-sending-multiple-emails:
838904
0 commit comments