How to Signup User and Send Confirmation Email in Django

In this tutorial, you’ll learn how to create a Registration Form for User Signup. We’ll add more functionality by adding validation and sending a confirmation link on users’ email. With confirming account user cannot sign in. You can also find this tutorial code on GitHub.

For example, we will be using the project in which we have created previously a login/logout and password reset/change view. For this tutorial, I have created an app named core.

Here you will be learning the following example –

Let’s get started.

For the testing purpose, I will be using Email Console which prints email in the terminal instead of sending an email.

settings.py

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

Django sign up with email confirmation

Create a model named Profile in models.py for determinant if the e-mail is confirmed or not. We will additionally add a signal bellow the model. A new entry is added within the User model, the signal is going to be trigger and add details in Profile model with default email confirm as false.

models.py

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    email_confirmed = models.BooleanField(default=False)

@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
        instance.profile.save()

Django has internal APIs for creating One Time Link with user details. PasswordResetTokenGenerator API is used for generating token. We will extend PasswordResetTokenGenerator with our class to generate a unique token. This will make use of your SECRET_KEY of your project.

Create a module tokens.py in your app. For example core.

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils 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.profile.email_confirmed)
        )

account_activation_token = AccountActivationTokenGenerator()

Now let’s create forms.py. We will extend form with UserCreationForm.

forms.py

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

# Sign Up Form
class SignUpForm(UserCreationForm):
    first_name = forms.CharField(max_length=30, required=False, help_text='Optional')
    last_name = forms.CharField(max_length=30, required=False, help_text='Optional')
    email = forms.EmailField(max_length=254, help_text='Enter a valid email address')

    class Meta:
        model = User
        fields = [
            'username', 
            'first_name', 
            'last_name', 
            'email', 
            'password1', 
            'password2', 
            ]

In views.py, we will create a view SignUpView which will send account activation details on email.

views.py

from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from django.views.generic import View, UpdateView
from core.forms import SignUpForm
from django.contrib.auth.models import User

from django.contrib import messages
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.template.loader import render_to_string
from core.tokens import account_activation_token

# Sign Up View
class SignUpView(View):
    form_class = SignUpForm
    template_name = 'commons/signup.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class()
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():

            user = form.save(commit=False)
            user.is_active = False # Deactivate account till it is confirmed
            user.save()

            current_site = get_current_site(request)
            subject = 'Activate Your MySite Account'
            message = render_to_string('emails/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)

            messages.success(request, ('Please Confirm your email to complete registration.'))

            return redirect('login')

        return render(request, self.template_name, {'form': form})

Notice in the above code, I am setting user.is_active = False. This will prevent the user from login until the user email is confirmed.

For sending email we need email template.

account_activation_email.html

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

Please click on the link below to confirm your registration:

http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}

signup.html

{% extends 'base.html' %}

{% block title %}Sign Page{% endblock title %}

{% block content %} 
    <h2>Sign Page</h2>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Register</button>
        <br><br>
        <a href="{% url 'home' %}">Home</a>
    </form>
{% endblock content %}

And here are the routes you will need –

urls.py

from django.urls import path
from core.views import SignUpView, ActivateAccount

urlpatterns = [
    path('signup/', SignUpView.as_view(), name='signup'),
    path('activate/<uidb64>/<token>/', ActivateAccount.as_view(), name='activate'),
]

Note – You have not created ActivateAccount View yet. If you try to runserver it will give an error.

Here far it will look like this –

How to Signup User and Send Confirmation Email in Django - SignUp
Sign up Page
How to Signup User and Send Confirmation Email in Django - login
Login page with Confirmation message
How to Signup User and Send Confirmation Email in Django - email
Email using Email Console

By clicking on the link in email, the user will be sent to ActivateAccount View.

views.py

from django.contrib.auth import login
from django.contrib.auth.models import User
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from core.tokens import account_activation_token

class ActivateAccount(View):

    def get(self, request, uidb64, token, *args, **kwargs):
        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except (TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        if user is not None and account_activation_token.check_token(user, token):
            user.is_active = True
            user.profile.email_confirmed = True
            user.save()
            login(request, user)
            messages.success(request, ('Your account have been confirmed.'))
            return redirect('home')
        else:
            messages.warning(request, ('The confirmation link was invalid, possibly because it has already been used.'))
            return redirect('home')

Here is the logic after registration. The ActivateAccount view will check – if the user exists if the token is valid. If everything is valid and check, then we will set user.is_active = True and user.profile.email_confirmed = True and log in the user.

How to Signup User and Send Confirmation Email in Django - after login

GitHub – Run Example Locally

Code is also available on GitHub – https://github.com/studygyaan/How-to-Export-Excel-File-With-Django

Clone the Repository

git clone https://github.com/studygyaan/How-to-Signup-User-and-Send-Confirmation-Email-in-Django.git

Change Directory

cd How-to-Signup-User-and-Send-Confirmation-Email-in-Django

Create Virtual Environment – VirtualENV

virtualenv env

Activate Virtual Environment

source env/bin/activate

Run requirements file to install libraries using Pip3

pip3 install -r requirements.txt

Run the server

python3 manage.py runserver

And open http://localhost:8000/ in your browser.

Share