Django Contact Form

On July 26, 2024
13min read
Denys Kontorskyy Technical Content Writer @Mailtrap
Veljko Ristić Content Manager @ Mailtrap

Python web framework Django is great for rapid and secure web development, providing an easy way to create and customize a contact form.

Whether you’re a beginner or a Jedi developer who needs a refresher, this tutorial provides all the steps to building a robust contact form that can be featured on your homepage. And I’ll cover:

How to create a Django contact form

Make sure that Django is installed on your machine. From the command prompt, run this command:

pip install django

If you have a particular version that you need, and not the latest one that is installed by default, run this command and indicate the version number:

pip install django==4.2

Next, you’ll need to set up an actual project before beginning with the contact form. 

Do this by running the command django-admin startproject <projectname>, where <projectname> is the name you want to give to your Django project. 

In this example, I’ll name it myproject

django-admin startproject myproject

The command creates a new directory called myproject that contains the main settings and configuration files.

myproject/
    manage.py
    myproject/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

***The manage.py file is a command-line utility that helps to interact with the project.

Now it’s time to build a basic contact form.

Start by creating a new forms.py file in the myproject folder.

To access various form-related functionalities, such as validation and rendering, create a form class that inherits Django’s built-in Form class. 

This is where you can define the form fields you want to collect from the user. Here’s the full code that will go in the file:

from django import forms


class ContactForm(forms.Form):
    name = forms.CharField(required=True)
    email = forms.EmailField(required=True)
    message = forms.CharField(widget=forms.Textarea)

This is just a basic example, but you can add additional fields and built-in validations to ensure that the user inputs the correct data:

from django import forms
from django.core.validators import EmailValidator


class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.CharField(validators=[EmailValidator()])
    phone = forms.CharField(max_length=15)
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)

Once the contact form class is created, create a new views.py file, and in it, add a view function that’ll render the contact form template and handle the submission:

from django.shortcuts import render, redirect
from myproject.forms import ContactForm
from django.http import HttpResponse


def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # Process the form data
            pass
            return redirect('success')
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})


def success(request):
  return HttpResponse('Success!')

Here, I defined a view function called contact that takes a web request and returns a rendered contact form template.

The view function is responsible for:

  • Processing the form data submitted by the user
  • Checking if the request is a POST request 
  • Creating an instance of the ContactForm class to validate the submitted data via is_valid() method

In this example, we simply ‘pass’, but you can also:

  1. Send form data via email. We’ll cover this in more detail with code examples in the next step below. 
  1. Save form data to a database:
import csv
from django.shortcuts import redirect

name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']

file = open('responses.csv', 'a')
writer = csv.writer(file)
writer.writerow([name,email,message])
file.close()

return redirect('success')

Note that this approach saves the form data to a CSV file instead of a database. To save form data to a database, you’ll need to define a model to store the data. 

For more information on defining models in Django, check out the Django tutorial on setting up models. But, I’ll also show you another method to collect data in the section below (hit the link to jump to that). 

To use the view function I created, I’ll map a URL to the view function to create a webpage or endpoint accessible via the URL.

This is done using the path() function that defines a URL pattern that points to the contact() function. Note that this code should go to the file called myproject/urls.py

from django.urls import path
from myproject.views import contact, success

urlpatterns = [
    path('contact/', contact, name='contact'),
    path('success/', success, name='success')
]

At this point, I’m moving on to write the HTML for the contact form from scratch or use a ready-made template file. There are several sources for HTML templates, and the one you choose depends on the specific design and functionality you need.

Some of the sources can either be:

Here are some simple steps you can take to set up a template that works with our guide:

  • Add this to TEMPLATES setting in settings.py:
'DIRS': [
          os.path.join(BASE_DIR, "templates")
      ],
  • Create templates/contact.html in our project with the following contents:
<form action="/contact/" method="post">
  {% csrf_token %}
  {% for field in form %}
      <div class="fieldWrapper">
          {{ field.errors }}
          {{ field.label_tag }} {{ field }}
      </div>
  {% endfor %}
  <input type="submit" value="Submit">
</form>
  • Create templates/success.html in our project with the following contents:
<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Success Page</title>

    <style>

        body {

            font-family: Arial, sans-serif;

            display: flex;

            justify-content: center;

            align-items: center;

            height: 100vh;

            margin: 0;

            background-color: #f4f4f4;

        }

        .success-message {

            text-align: center;

            padding: 20px;

            border: 2px solid #4caf50;

            border-radius: 5px;

            background-color: #dff0d8;

            color: #3c763d;

        }

    </style>

</head>

<body>

    <div class="success-message">

        <h1>Success!</h1>

        <p>Your operation was completed successfully.</p>

    </div>

</body>

</html>
  • As a last touch, add a success page to which the user is redirected to after hitting the submit button:
from django.shortcuts import render, redirect
from myproject.forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # Process the form data
            return redirect('success')
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})

def success(request):
    return render(request, 'success.html')

To run all of the example codes from this tutorial, and to check the result, execute the following command in your terminal:

python3 manage.py runserver

After that, open your web browser and enter this URL http://127.0.0.1:8000/contact/ to access the contact form page. Here’s an example of what you should see: 

How to add reCaptcha

To make sure humans fill out the form, I’ll show you how to add reCaptcha to the form above. This includes registering for the service, updating all dependencies, and testing the setup. 

Step 1: Register for reCAPTCHA

  • Go to the Google reCAPTCHA website.
  • Sign in with your Google account.
  • Register a new site by entering your label and selecting reCAPTCHA v2 with the “I’m not a robot” checkbox.
  • Add your domain to the list of domains authorized to use your reCAPTCHA keys.
  • Upon registration, you’ll receive two key pieces of data: a Site key and a Secret key. Keep these handy as you’ll need them in the next steps.

Step 2: Update Django settings

Add the reCAPTCHA keys to your Django settings:

# settings.py

RECAPTCHA_PUBLIC_KEY = 'your_site_key'
RECAPTCHA_PRIVATE_KEY = 'your_secret_key'

Step 3: Install Django reCAPTCHA

Install the django-recaptcha library, which provides Django integrations for reCAPTCHA:

pip install django-recaptcha

Add it to the installed apps under the Django settings:

# settings.py

INSTALLED_APPS = [
    ...
    'django_recaptcha',
]

Step 4: Update the form

Modify the ContactForm to include the reCAPTCHA field:

# forms.py
from django import forms
from django_recaptcha.fields import ReCaptchaField
from django_recaptcha.widgets import ReCaptchaV2Checkbox

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.CharField(max_length=100)
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)
    captcha = ReCaptchaField(widget=ReCaptchaV2Checkbox())

Step 5: Update the Template

Modify the contact.html template to ensure the form template includes the reCAPTCHA widget.

<form action="/contact/" method="post">
    {% csrf_token %}
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }} {{ field }}
        </div>
    {% endfor %}
    <input type="submit" value="Submit">
</form>

Note: Django reCAPTCHA automatically includes the necessary JavaScript and widget code, so there’s no need for additional script tags.

Step 6: Update the view

Ensure your view handles the reCAPTCHA validation:

# views.py
from django.shortcuts import render, redirect
from .forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # Process the form data
            return redirect('success')
    else:
        form = ContactForm()

    return render(request, 'contact.html', {'form': form})

Step 7: Testing

Run your Django development server and navigate to the contact form page. You should see the reCAPTCHA checkbox below your form fields. Test it by filling out your form and verifying that the reCAPTCHA validates inputs as expected.

How to collect data from a Django contact form

First, check if the contact form in forms.py is set up to collect all the data you need. Here’s a quick review of the form I previously made:

# forms.py
from django import forms
from django.core.validators import EmailValidator

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField(validators=[EmailValidator()])
    phone = forms.CharField(max_length=15, required=False)  # Optional field
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)

Next, in the views.py, I’ll add a function to handle the POST request when the form is submitted. This function will validate the form data that then can be processed (e.g., by sending an email or saving it).

# views.py
from django.shortcuts import render, redirect
from forms import ContactForm
from django.core.mail import send_mail
from django.conf import settings

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            phone = form.cleaned_data['phone']
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']

            # Send an email
            send_mail(
                f'From {name}, Subject: {subject}',
                f'Message: {message}\nContact Phone: {phone}',
                email,  # From email
                [settings.ADMIN_EMAIL],  # To email
                fail_silently=False,
            )

            return redirect('success')
    else:
        form = ContactForm()

    return render(request, 'contact.html', {'form': form})

Quick breakdown:

  • form.cleaned_data is used to access validated data from your form.
  • send_mail is a Django utility to send emails. Note: you need to set up your email backend settings in settings.py to use this feature.

Now, to send emails, you need to configure the email backend in your Django project settings. 

Important Note: The code here is just an exemplary setting, I’ll show you the proper sending method with Mailtrap Email API/SMTP in the following sections. Hit the links to jump to these methods.  

# settings.py

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'live.smtp.mailtrap.io'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@yourserver.com'
EMAIL_HOST_PASSWORD = 'your-email-password'
ADMIN_EMAIL = 'admin@yourdomain.com'

With that, I’ll move on to create a success page. You need to have a success page to redirect to after the form is processed, here’s the code:

# views.py

def success(request):
    return render(request, 'success.html', {'message': 'Thank you for contacting us!'})

Then, I’ll create a simple success.html template:

<!-- templates/success.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Success</title>
</head>
<body>
    <p>{{ message }}</p>
</body>
</html>

Lastly, you should test out the form. Do the following:

  • Fill out the form on your website and submit it.
  • Check if the email is received.
  • Verify that the data is correctly collected and displayed.

How to validate and verify data from a contact form

Django provides a robust system for form validation that you can utilize to enforce various constraints and checks. Below, I’ll guide you through enhancing your existing form validation, including server-side and custom validation techniques.

The framework comes with a set of built-in validators that you can use directly in your form fields to enforce specific data rules such as: 

  • Length constraints 
  • Email format 
  • Regex patterns 
  • etc.

Here’s how you can enhance the ContactForm in your forms.py to include more detailed built-in validators:

# forms.py
from django import forms
from django.core.validators import EmailValidator, RegexValidator, MinLengthValidator

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100, validators=[MinLengthValidator(2)])
    email = forms.EmailField(validators=[EmailValidator(message="Enter a valid email address.")])
    phone = forms.CharField(max_length=15, validators=[
        RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
    ], required=False)  # Optional field
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea, validators=[MinLengthValidator(10)])

For more complex validation scenarios that go beyond what is provided by Django’s built-in validators, you can define custom validation methods within your form class. These methods should start with clean_ followed by the field name.

For instance, let’s add a custom validation to ensure that the message does not contain any unwanted characters or words:

The clean_message method is automatically called by Django’s form validation system when you call the is_valid method on a form instance. You generally don’t need to call it explicitly.

# forms.py
def clean_message(self):
    data = self.cleaned_data['message']
    unwanted_words = ['spam', 'money', 'subscribe']
    if any(word in data.lower() for word in unwanted_words):
        raise forms.ValidationError("Please do not include spam words in your message.")
    return data

Also, sometimes there’s a need to validate fields in combination (e.g., checking that one field’s value is greater than another). Django allows you to override the clean() method of the form class for such purposes:

# forms.py
def clean(self):
    cleaned_data = super().clean()
    subject = cleaned_data.get('subject')
    message = cleaned_data.get('message')
    if 'help' in subject.lower() and 'urgent' not in message.lower():
        raise forms.ValidationError("Urgent help requests should include 'urgent' in the message.")

Lastly, it’s important to update the view to make sure it handles these validations correctly and provides feedback to the user when errors occur. Check the snippet below:

# views.py
from django.shortcuts import render, redirect
from forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # process the form data
            return redirect('success')
        else:
            # Return to the form page with validation errors
            return render(request, 'contact.html', {'form': form})
    else:
        form = ContactForm()

    return render(request, 'contact.html', {'form': form})

And yes, don’t forget to test the form with validators before you deploy it to production. It’s best to try to fail the validation and then check the error messages to see if you need to adjust the HTML code. 

Send an email from a Django contact form using SMTP

There are a few actions that you can set the form to do once it’s submitted. In most cases, you’ll want it to send an email with the form’s information. 

As shown earlier, you’ll need to list the SMTP server configuration and your credentials in the settings.py file.

In the following code example, I’ll use Mailtrap Email API/SMTP – the SMTP method. And later I’ll show you how to do the same with Mailtrap API. 

Note: This can also be done with Gmail or any other SMTP server of an email service provider.

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'live.smtp.mailtrap.io'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'example_username'
EMAIL_HOST_PASSWORD = 'example_password'
EMAIL_USE_TLS = True

Once you’ve configured your email settings, use Django’s built-in email sending functionality to send an email in your view function.

Here’s a full code of how to modify the contact() view function we created earlier to send an email:

from django.shortcuts import render, redirect
from django.core.mail import EmailMessage
from myproject.forms import ContactForm
from django.conf import settings

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            message = form.cleaned_data['message']


          EmailMessage(
              'Contact Form Submission from {}'.format(name),
              message,
              'form-response@example.com', # Send from (your website)
              ['JohnDoe@gmail.com'], # Send to (your admin email)
              [],
              reply_to=[email] # Email from the form to get back to
          ).send()

            return redirect('success')
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})

Send an email from a Django contact form using API

Mailtrap API/SMTP has an official Python client, so start by installing that. 

pip install mailtrap

Proceed to create a mail object, making sure you have the proper:

  • Sender 
  • Receiver 
  • Subject
  • Text

I’m stressing this because the code below is for exemplary purposes. And one more thing – when using Mailtrap your sender address needs to match the domain you added and verified on the platform. 

import mailtrap as mt

# create mail object
mail = mt.Mail(
    sender=mt.Address(email="mailtrap@example.com", name="Mailtrap Test"),
    to=[mt.Address(email="your@email.com")],
    subject="You are awesome!",
    text="Congrats for sending test email with Mailtrap!",
)

Then, you need a short snippet that creates the client and sends the email, here it is: 

client = mt.MailtrapClient(token="your-api-key")
client.send(mail)

Tip: You can find your Mailtrap API key under Settings > API Tokens

That’s pretty much it, you can now send a simple email. But if you need a more complex message with attachments, multiple recipients, and categories, here’s the giga snippet. 

Create a sendmail.py file in the same root directory of your project. And write the following code snippet there.

import base64
from pathlib import Path

import mailtrap as mt

welcome_image = Path(__file__).parent.joinpath("welcome.png").read_bytes()

mail = mt.Mail(
    sender=mt.Address(email="mailtrap@example.com", name="Mailtrap Test"),
    to=[mt.Address(email="your@email.com", name="Your name")],
    cc=[mt.Address(email="cc@email.com", name="Copy to")],
    bcc=[mt.Address(email="bcc@email.com", name="Hidden Recipient")],
    subject="You are awesome!",
    text="Congrats for sending test email with Mailtrap!",
    html="""
    <!doctype html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      </head>
      <body style="font-family: sans-serif;">
        <div style="display: block; margin: auto; max-width: 600px;" class="main">
          <h1 style="font-size: 18px; font-weight: bold; margin-top: 20px">
            Congrats for sending test email with Mailtrap!
          </h1>
          <p>Inspect it using the tabs you see above and learn how this email can be improved.</p>
          <img alt="Inspect with Tabs" src="cid:welcome.png" style="width: 100%;">
          <p>Now send your email using our fake SMTP server and integration of your choice!</p>
          <p>Good luck! Hope it works.</p>
        </div>
        <!-- Example of invalid for email html/css, will be detected by Mailtrap: -->
        <style>
          .main { background-color: white; }
          a:hover { border-left-width: 1em; min-height: 2em; }
        </style>
      </body>
    </html>
    """,
    category="Test",
    attachments=[
        mt.Attachment(
            content=base64.b64encode(welcome_image),
            filename="welcome.png",
            disposition=mt.Disposition.INLINE,
            mimetype="image/png",
            content_id="welcome.png",
        )
    ],
    headers={"X-MT-Header": "Custom header"},
    custom_variables={"year": 2023},
)

def sendEmail():
    client = mt.MailtrapClient(token="your-api-key")
    client.send(mail)

In order to call this sendEmail function you would need to import this function within your API handler that receives form data and call like this.

```python
from sendmail import sendEmail
# .....previous code
def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            phone = form.cleaned_data['phone']
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']

            sendEmail()
.........

For more info on the sending methodology, check our detailed article on sending with Django, or go to the official Python SDK documentation

How to test your emails before sending?

To test emails sent by your Django application contact form or application, you need a propper testing tool. And here, I’ll be using Mailtrap Email Testing.  

It’s a part of Mailtrap Email Delivery Platform and a useful tool for testing email functionality in a development environment without the risk of spamming users.

By intercepting and capturing all emails sent by your Django app, Email Testing lets you: 

  • Evaluate the compatibility of your email’s HTML/CSS with different email clients 
  • Check how emails will appear on various devices 
  • Get a detailed spam analysis 
  • Review raw email data

Also, you can check if your sending domain appears in any of the blacklists. 

Now, I’ll show you how to integrate SMTP testing with Django. 

Once you have a Mailtrap account, configure Email Testing SMTP credentials in the settings.py file and enter your username and password, which can be found on the “My Inbox” page. 

This will allow Mailtrap to intercept any email sent from your application’s contact form and display it in the dashboard for further inspection. 

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'sandbox.smtp.mailtrap.io'
EMAIL_PORT = 2525
EMAIL_HOST_USER = 'example_username'
EMAIL_HOST_PASSWORD = 'example_password'
EMAIL_USE_TLS = True

If you need a quick visual reminder of the steps necessary to create a contact form in Django, make sure to watch our dedicated video:

Wrapping up

With these steps, you’ll be able to develop a reliable and efficient contact form for your website that’ll help you to connect with your users. So go ahead and implement a Django contact form on your website today! And if you need more helpful topics about Django and Python, check these out: 

Article by Denys Kontorskyy Technical Content Writer @Mailtrap

I am an experienced Technical Content Writer offering insights on email infrastructure, sending, testing, and optimizing emails. With a strong passion for product marketing, I love creating content that educates audiences and provides practical, applicable knowledge.

Article by Veljko Ristić Content Manager @ Mailtrap

Linguist by trade, digital marketer at heart, I’m a Content Manager who’s been in the online space for 10+ years. From ads to e-books, I’ve covered it all as a writer, editor, project manager, and everything in between. Now, my passion is with email infrastructure with a strong focus on technical content and the cutting-edge in programming logic and flows. But I still like spreading my gospels while blogging purely about marketing.