Django User Registration with Email Confirmation

User registration is a crucial component of many web applications. Adding an email confirmation step enhances security and ensures that the registered email address is valid. In this tutorial, we will walk you through the process of implementing user registration with email confirmation in Django.

Prerequisites

Before we begin, make sure you have the following prerequisites:

  1. Django: Install Django using pip by running the following command:
pip install django
  1. A working email server or SMTP settings for sending confirmation emails.

Step 1: Create a Django Project and App

Start by creating a new Django project and app:

django-admin startproject projectname
cd projectname
python manage.py startapp appname

Replace projectname and appname with your desired project and app names.

Step 2: Configure Email Settings

Open your project’s settings.py file and configure your email settings. For this example, we will use Gmail’s SMTP server for sending emails:

# settings.py

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your_email_password'

Replace [email protected] and your_email_password with your Gmail email and password.

Please watch bellow video, to send email using Gmail.

Note that using your actual email and password directly in your code is not recommended for production. Instead, consider using environment variables or other secure methods to store these credentials. Read more on How to Protect Sensitive Data in Python Projects like Django and Flask

Step 3: Create a Custom User Model

Django provides a built-in user model. However, if you need custom user fields, you can create a custom user model. In your app’s models.py file, create a custom user model by extending User Model.

  • AbstractUser: Use when you want to add simple fields to the User model, preserving default authentication and admin functionality.
  • AbstractBaseUser: Use when you need full control over authentication logic, and want to customize User fields extensively.
  • One-to-One Link: Use when you want to keep the default User model intact but add separate custom fields in a related model.
  • Proxy Model: Use when you want to add methods or properties to the existing User model without changing the database structure.

Learn more about Extending the Django User Model: Exploring Various Approaches

Note: For this example, we have extended user model using AbstractUser. But you can extend and use this blog as it is (same implmentation)

If you want to add custom fields to your user model, create a custom user model in your app’s models.py file:

# appname/models.py

from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    email_confirmed = models.BooleanField(default=False)

Then, update your project’s settings.py to use the custom user model:

# settings.py

AUTH_USER_MODEL = 'appname.CustomUser'

Change the appname.

Step 4: Create Registration Views and Templates

Create views and templates for user registration and email confirmation. In your app’s views.py file, add the following:

# appname/views.py

from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes, force_str
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect, get_object_or_404
from .models import CustomUser
from django.http import HttpResponseBadRequest

from .forms import CustomUserCreationForm
from .tokens import account_activation_token

def signup(request):
    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False  # Deactivate the user until email confirmation
            user.save()
            
            # Send email confirmation
            current_site = get_current_site(request)
            subject = 'Activate your account'
            message = render_to_string('account_activation_email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'token': account_activation_token.make_token(user),
            })
            user.email_user(subject, message)
            
            return redirect('account_activation_sent')
    else:
        form = CustomUserCreationForm()
    return render(request, 'signup.html', {'form': form})

@login_required
def account_activation_sent(request):
    return render(request, 'account_activation_sent.html')

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = CustomUser.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, CustomUser.DoesNotExist):
        user = None

    if user is not None and account_activation_token.check_token(user, token):
        user.is_active = True
        user.save()
        login(request, user)
        return redirect('account_activation_complete')
    else:
        return HttpResponseBadRequest('Activation link is invalid!')

@login_required
def account_activation_complete(request):
    return render(request, 'account_activation_complete.html')    

In the code above:

  • The signup view handles user registration, deactivates the user, sends an email with an activation link, and redirects to a confirmation page.
  • The account_activation_sent view displays a message to inform users that the activation email has been sent.
  • The activate view verifies the activation link and activates the user’s account.
  • The account_activation_complete view shows a message confirming the successful activation of the user’s account.

Step 5: Create Registration Forms and Tokens

Create a registration form and tokens for email confirmation in your app. In your app’s directory, create a forms.py file with the following code:

# appname/forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ('email',)

Now, create a tokens.py file in your app’s directory to define the account_activation_token:

# appname/tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six

class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.email_confirmed)
        )

account_activation_token = AccountActivationTokenGenerator()

Make sure you install six package: pip install six

Step 6: Create Email Templates

Create email templates for the activation email. In your app’s templates/registration directory, create an account_activation_email.html template:

{% load static %}

{% autoescape off %}
Hello {{ user.username }},

Please click the link below to activate your account:

{% block reset_link %}
<a href="http://{{ domain }}{% url 'activate' uidb64=uid token=token %}">Activate your account</a>
{% endblock %}

If you did not register on our site, please ignore this message.

Best regards,
Your Website Team
{% endautoescape %}

Step 7: Define URLs

Define the URLs for the registration views in your app’s urls.py:

# appname/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('signup/', views.signup, name='signup'),
    path('account_activation_sent/', views.account_activation_sent, name='account_activation_sent'),
    path('activate/<uidb64>/<token>/', views.activate, name='activate'),
    path('account_activation_complete/', views.account_activation_complete, name='account_activation_complete'),
]

And Finally, create add the app urls in your projectname/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('appname.urls')),
]

Step 8: Create Templates

Create templates for the registration views. In your app’s templates directory,create the following templates:

base.html: This html will be inherited in other templates


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Your Website Title{% endblock %}</title>
    <!-- Add your CSS and JavaScript links here -->
</head>
<body>

    <main>
        {% block content %}
        {% endblock %}
    </main>

    <!-- Add your JavaScript files here -->
</body>
</html>

signup.html: The registration form.

{% extends "base.html" %}

{% block title %}Sign Up{% endblock %}

{% block content %}
  <h2>Sign Up</h2>
  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Sign Up</button>
  </form>
{% endblock %}

account_activation_sent.html: A message confirming that the activation email has been sent.

{% extends "base.html" %}

{% block title %}Activation Email Sent{% endblock %}

{% block content %}
  <h2>Activation Email Sent</h2>
  <p>An activation link has been sent to your email address. Please check your inbox and click the activation link to activate your account.</p>
{% endblock %}

account_activation_complete.html: A message confirming the successful activation of the user’s account.

{% extends "base.html" %}

{% block title %}Activation Email Sent{% endblock %}

{% block content %}
    {% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}! You have Successfully Activated the Account and Logged in!</p>
    {% endif %}
{% endblock %}

Customize these templates to match your application’s design and style.

Step 9: Run the Development Server

Start the development server:

python manage.py runserver

Visit http://localhost:8000/signup/ in your web browser to access the registration page. After registering, you will receive an activation email. Click the activation link to activate your account.

Learn more on How to Create Login Logout in Django and Implement Change and Forgot Password Functionality in Django

Conclusion

Congratulations! You have successfully implemented user registration with email confirmation in Django. This adds an extra layer of security to your application and ensures that users provide valid email addresses during registration.

Find this project on Github.

Blogs You Might Like to Read!