Build a Django Contact Form with Email Backend

April 17, 2020, 12:29 p.m.

Django · 5 min read

Build a Django Contact Form with Email Backend

Last Modified: Sept. 8, 2020, 4:03 p.m.

Many websites list their contact email address in the footer where it is up to the user to send an email.  While this is by no means a bad way for users to contact staff, it requires more work and effort on the user's side than what's necessary. 

So let's help the user easily send a contact email with an in-site contact form that instantly sends an email to the website staff upon submission.  While this may seem daunting at first, Django actually handles most of the heavy lifting. 

We will cover (1) how to create the Django contact form fields, (2) how to add the form to the HTML template, and (3) how to add a Django email backend.

 

Create a Django contact form in forms.py

env > mysite > main > forms.py

from django import forms

# Create your forms here.

class ContactForm(forms.Form):
	first_name = forms.CharField(max_length = 50)
	last_name = forms.CharField(max_length = 50)
	email_address = forms.EmailField(max_length = 150)
	message = forms.CharField(widget = forms.Textarea, max_length = 2000)

To make the contact form we need to edit forms.py. The form will be called ContactForm and require basic contact information prior to submission. Django does not come with forms.py created, so if you do not have a forms.py file, create one in the mysite > main folder.

Add first_name and last_name as Django CharFields. These are character fields that allow a maximum of 50 characters each. Then add a new field called email_address as an EmailField, a specific field that checks for an @ address in the field input before form submission. Finally add the message field as a CharField with a widget specifying the form will display as a Textarea, a form field that accepts paragraph styled text.

Save the changes to this file.

 

Update the function in views.py

env > mysite > main > views.py

from django.shortcuts import render, redirect
from .forms import ContactForm
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse


# Create your views here.
def contact(request):
	if request.method == 'POST':
		form = ContactForm(request.POST)
		if form.is_valid():
			subject = "Website Inquiry" 
		    body = {
			'first_name': form.cleaned_data['first_name'], 
			'last_name': form.cleaned_data['last_name'], 
			'email': form.cleaned_data['email_address'], 
			'message':form.cleaned_data['message'], 
			}
			message = "\n".join(body.values())

			try:
				send_mail(subject, message, 'admin@example.com', ['admin@example.com']) 
			except BadHeaderError:
				return HttpResponse('Invalid header found.')
			return redirect ("main:homepage")
      
	form = ContactForm()
	return render(request, "main/contact.html", {'form':form})

Open views.py and import the ContactForm from forms.py along with send_mail, BadHeaderError, HttpResponse, and redirect from Django. Then add an if statement that if the user requests to post the form, check to see if the form is valid. If the form is valid, then declare the subject and body of the email.

The subject will be "Website Inquiry" while the body will be all of the cleaned form fields. Django has built-in form validation that cleans the data for you, all you need to do is call the form.cleaned_data['form_field']. To format the actual email message, join all of the body's values together.

With this completed, the function will try to send the email with the subject, message, from email, and email declared. Django requires the format  send_mail to be ('subject', 'message', 'from_email', ['to_email']).

The from and to email addresses are both set to admin@example.com so the email will appear in the terminal for testing purposes. 

Now, to prevent attackers from inserting extra email headers, we need to return a bad header error. If a bad header is added, let's return a HttpResponse that the header is invalid. Else, if the form is submitted correctly, the user will be redirected to the homepage. 

Finally, if the user simply requests to see the page, the empty form displays in the contact.html template.

 

Add a contact URL path

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"

urlpatterns = [
    path("contact", views.contact, name="contact"),
    
]

Now let's add the contact page URL to our app's urls.py. If you are using an existing template with a URL path already listed, skip this step. 

 

Add the form to contact.html

env > mysite > main > templates > main > contact.html

	<!--Contact form-->
	<div style="margin:80px">
		<h1>Contact</h1>
		<h4>Contact us directly if you have any questions</h4>
		<p>
			Please write your name, email address and a message below if you have any questions.
			One of our staff members will be happy to contact you directly and answer your questions as soon as possible. 
		</p>
		<form method="post">
        {% csrf_token %}
            {{form.as_p}}
            <button type="submit">Submit</button>
        </form>
    </div>

Open contact.html, or the template file of your choice, and add a form HTML element below the text.  Add method="POST" to the element so the form is posted upon submission. Within the form element, nest the {% csrf_token %} to prevent form submission forgery. This is a very important line of code that allows your Django project to securely send information.

Next, call the ContactForm fields after the CSRF token using the template context; use as_p to wrap the fields in <p> tags. You can also choose to call fields individually using the format {{form.name_of_field}}.

Lastly, add a submit button right before the closing tag of the form element. 

If you are using the CSS framework Bootstrap, learn how to render your Django form with Bootstrap.

 

Add the Django email backend to the settings

env > mysite > main > settings.py

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

For developer mode, send the email to the CLI and not to an email inbox.

In settings.py add the following line of code at the bottom of the page. This line sets the Django email backend as the Command Prompt/Terminal for testing purposes but will eventually be changed to an actual email sending service for production. 

 

Send a test email to the CLI

macOS Terminal/Windows Command Prompt

__________________________________________________________________________________________
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Website Inquiry
From: admin@example.com
To: admin@example.com
Date: Wed, 05 Feb 2020 00:04:43 -0000
Message-ID: [123456789@DESKTOP]

John
Smith
john@gmail.com
Hello, I have a question...

__________________________________________________________________________________________

Now you can submit your contact form in the browser by going to http://127.0.0.1:8000/contact. Upon submission, you will be instantly redirected to the homepage.

But how do you know it worked correctly?

Go to your Command Prompt/Terminal and there should be an output similar to the one above given that we set the Django email backend to output in the console rather than actually sending an email.

When you are ready for production, learn how to configure your Django contact form for production using the AWS SES Email Backend.

 

Django 'django.core.mail.backends.console.EmailBackend' not working

If the Django email backend in the settings is not working, first check to make sure there are no spelling errors. 

Next, check to make sure you placed the EMAIL_BACKEND in quotation marks.

If those are not the cause of the error, go to the views.py file and make sure send_email and BadHeaderError is imported from django.core.mail and HttpResponse is imported from django.http.

 

You must also include try and except in the views function or the function will not work properly and the email will not send.


0
Subscribe now

Subscribe to stay current on our latest articles and promos





Post a Comment
Join the community

0 Comments