﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
37162	Docs ContactForm example demonstrates poor practices	Mike Edmunds	Mike Edmunds	"The `ContactForm` used as a running example starting in the [https://docs.djangoproject.com/en/6.1/topics/forms/#more-on-fields More on fields] forms topic demonstrates poor practices for implementing a contact form that sends email:

* It uses the contact's email address (`sender`) as the message's `from_email`. At best, this [https://stackoverflow.com/questions/54549797/smtpdataerror-553-brelaying-disallowed-as-abcemail-com-while-using-contact won't work] (the message will be rejected by the outgoing server or silently ignored as spam at the receiving end). At worst, it creates vulnerabilities.
* It passes through `subject` and `message` without any indication they originated in a web contact form. This can allow high-fidelity phishing attacks against the organization deploying the form (particularly when combined with an arbitrary sender address).

I realize the example needs to be kept simple, but Django's docs probably shouldn't be illustrating insecure approaches.

I'd suggest changing the current:

{{{#!python
from django.core.mail import send_mail

if form.is_valid():
    subject = form.cleaned_data[""subject""]
    message = form.cleaned_data[""message""]
    sender = form.cleaned_data[""sender""]
    cc_myself = form.cleaned_data[""cc_myself""]

    recipients = [""info@example.com""]
    if cc_myself:
        recipients.append(sender)

    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect(""/thanks/"")
}}}

to something like (also renaming the `sender` form field to `email` throughout the page):

{{{#!python
    from django.core.mail import EmailMessage

    if form.is_valid():
        subject = form.cleaned_data[""subject""]
        message = form.cleaned_data[""message""]
        email = form.cleaned_data[""email""]
        cc_myself = form.cleaned_data[""cc_myself""]

        # Send the message, directing replies to the contact's email.
        EmailMessage(
            subject=f""[via contact form] {subject}"",
            body=f""Contact email: {email}\n\n{message}"",
            to=[""info@example.com""],
            cc=[email] if cc_myself else None,
            reply_to=[email],
        ).send()

        return HttpResponseRedirect(""/thanks/"")
}}}

Note that the `cc` handling there (and in the original) is also not ideal. Maybe we could come up with some other reason to include a boolean field in the form? (""Urgent""? ""No reply necessary""?)

Or if something like that seems too complicated, maybe we should consider rewriting the page to use something other than a contact form.

[Noticed this while I was working on #34753. I was considering removing the contact-form-like example from the [https://docs.djangoproject.com/en/6.1/topics/email/#preventing-header-injection Email header injection] section and replacing it with a ref to this actual-contact-form example.]"	Cleanup/optimization	assigned	Documentation	6.0	Normal				Unreviewed	0	0	0	0	0	0
