Building a "Contact Me" Form with Django
In this tutorial, we'll walk through the process of creating a contact form for a Django web application. Users will submit messages with this form which will be sent to a Gmail inbox of your choosing. We'll integrate Google Mail SMTP for sending emails and implement Django Simple Captcha to prevent spam submissions.
Step 1: Setting up Google Mail SMTP
Before we begin, ensure you have a Google account which you would like the contact messages to be sent to. Follow these steps to set up Google Mail SMTP:
- 1. Go to your Google Account settings.
- 2. Navigate to Security.
- 3. Under "Signing in to Google," select "App passwords."
- 4. Generate an app password for your Django application.
- 5. Save the generated password securely; you'll need it later.
Step 2: Installing Django Simple Captcha
First, install Django Simple Captcha:
pip install django-simple-captcha
Add 'captcha'
to your INSTALLED_APPS
in settings.py
.
Step 3: Creating the Contact Form
Let's define the contact form in forms.py
:
from django import forms
from captcha.fields import CaptchaField
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
captcha = CaptchaField(error_messages={'invalid': 'Please enter the correct captcha code.'})
At this point, you may want to execute a migration to ensure that captcha is working properly with the command python manage.py migrate
.
Step 4: Configuring URLS
Define the URL patterns in your urls.py
to map the views to specific URLs:
from django.urls import path
from .views import contact, contact_submit
urlpatterns = [
path('contact/', contact, name='contact'),
path('contact/submit/', contact_submit, name='contact_submit'),
# Add other URL patterns as needed
]
Step 5: Setting Up Views
In your views.py
, define the view functions for rendering the contact form and handling form submissions:
from django.shortcuts import render, redirect
from django.core.mail import send_mail
from django.http import JsonResponse
from .forms import ContactForm
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']
# Send email using Google Mail SMTP
send_mail(
subject='New Message from Portfolio Website',
message=f'Name: {name}\nEmail: {email}\nMessage: {message}',
from_email='your_email@gmail.com', # Update with your email
recipient_list=['your_email@gmail.com'], # Update with your email
fail_silently=False,
)
return redirect('thankyou')
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
def contact_submit(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']
# Send email using Google Mail SMTP
send_mail(
subject='New Message from Portfolio Website',
message=f'Name: {name}\nEmail: {email}\nMessage: {message}',
from_email='your_email@gmail.com', # Update with your email
recipient_list=['your_email@gmail.com'], # Update with your email
fail_silently=False,
)
return JsonResponse({'status': 'success'})
else:
errors = form.errors.get_json_data()
return JsonResponse({'status': 'error', 'errors': errors})
else:
return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=405)
Step 6: Django Settings
Configure your Django project settings (settings.py
) to include the necessary configurations for email and captcha:
# Django Email Settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your_email@gmail.com' # Update with your email
EMAIL_HOST_PASSWORD = 'your_app_password' # Update with the app password generated
# Django Simple Captcha Settings
CAPTCHA_FONT_SIZE = 30
CAPTCHA_LETTER_ROTATION = (-10, 10)
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
Replace 'your_email@gmail.com'
with your Gmail address and 'your_app_password'
with the app password generated earlier.
Step 7: Creating HTML Templates
Create an HTML template contact.html
to render the contact form and thankyou.html
to render the thank you page when the form is submitted. You can use Bootstrap for styling.
<!-- contact.html -->
{% block content %}
{% load static %}
<head>
<link rel="stylesheet" type="text/css" href="{% static 'styles/contact.css' %}">
<!-- Add Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<div class="super_container">
<div class="card">
<div class="card-body">
<form method="post" id="contactForm">
{% csrf_token %}
<div class="form-group">
<div class="d-flex">
<label id="name-label" for="name">Name:</label>
<input type="text" id="name" name="name" class="form-control contact-input" required>
</div>
</div>
<div class="form-group">
<div class="d-flex">
<label id="email-label" for="email">Email:</label>
<input type="email" id="email" name="email" class="form-control contact-input" required>
</div>
</div>
<div class="form-group">
<label id="message-label" for="message">Message:</label>
<textarea id="message" name="message" rows="4" class="form-control" required></textarea>
</div>
<div class="form-group captcha-container">
<label id="captcha-label" for="captcha">Captcha:</label>
<div class="captcha-wrapper">
<div class="captcha-input-row">
{{ form.captcha }}
</div>
</div>
</div>
<button type="submit" class="button_fill intro_button contact-submit-button">Submit</button>
</form>
</div>
</div>
<div id="errorPopup" style="display: none;">
<p id="errorMessage"></p>
</div>
</div>
<!-- thankyou.html -->
{% block content %}
{%load static%}
<head>
<link rel="stylesheet" type="text/css" href="{% static 'styles/thankyou.css' %}">
</head>
<div class="super_container">
<div class="section_title text-center"><h1>Thank you for contacting me!</h1></div>
<div class="button_fill"><a href="{% url 'home' %}">return home</a></div>
</div>
{% endblock %}
Step 8: Adding JavaScript for Form Submission
Implement JavaScript to handle form submission via AJAX and refresh captcha. Why are we interrupting the normal form submission with a custom JavaScript AJAX one? Upon using the normal form submission and inputting an invalid captcha, the form submission would still try to send, and therefore clear all of the form data. A custom JavaScript form submission ensures that, when the submit button is pressed, we can check that the inputted captcha is correct and prevent the form from submitting if it isn't.
<!-- contact.html -->
<!-- rest of html -->
<script>
$(function() {
// Add refresh button after field (this can be done in the template as well)
$('img.captcha').after(
$('<a href="#void" class="captcha-refresh btn btn-secondary"><span class="fas fa-sync-alt"></span></a>')
);
// Click-handler for the refresh-link
$('.captcha-refresh').click(function(){
var $form = $(this).parents('form');
var url = location.protocol + "//" + window.location.hostname + ":"
+ location.port + "/captcha/refresh/";
// Make the AJAX-call
$.getJSON(url, {}, function(json) {
$form.find('input[name="captcha_0"]').val(json.key);
$form.find('img.captcha').attr('src', json.image_url);
});
$('#id_captcha_1').val('');
return false;
});
});
$(document).ready(function() {
$('#id_captcha_1').addClass('form-control');
} );
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#contactForm').on('submit', function(event) {
event.preventDefault(); // Prevent default form submission
// Serialize form data
var formData = $(this).serialize();
// Submit form via AJAX to the new URL for validation
$.ajax({
type: 'POST',
url: '{% url "contact_submit" %}',
data: formData,
dataType: 'json',
success: function(response) {
if (response.status === 'success') {
// Handle successful submission
window.location.href = '{% url "thankyou" %}';
} else {
if (response.errors) {
var firstErrorField = Object.keys(response.errors)[0];
var firstErrorMessage = response.errors[firstErrorField][0]["message"];
showError(firstErrorMessage);
if (firstErrorField === 'captcha') {
$('.captcha-refresh').click();
}
} else {
// Default error message
showError('Failed to submit the form. Please check your input and try again.');
}
}
},
error: function(xhr, status, error) {
// Handle AJAX errors
console.error(error['errors']);
showError('An error occurred while submitting the form. Please try again later.');
}
});
});
});
function showError(message) {
console.log(message);
$('#errorMessage').text(message);
$('#errorPopup').show();
// Hide popup div after 2 seconds
setTimeout(function() {
$('#errorPopup').hide();
}, 2000);
}
</script>
Conclusion
By following these steps, you've created a contact form for your Django application, integrated Google Mail SMTP for email notifications, and added a captcha to prevent spam submissions. This form will help you engage with your website visitors effectively while filtering out unwanted bot submissions.
Happy coding!