Django User Registration with Email Confirmation

Oct. 26, 2022


0
6 min read
1.03K

Generally, we sign up on any website, it sends the confirmation link to activate the account. Or sometimes it asks email to change the email or reset the password of an account.

In this tutorial, we will learn how to send confirmation mail using Django when someone registers on our web app. We will discuss an easy way to build this. But Django provides many other options like Django all auth application, Django-registration, and django-registration-redux. Those applications make this task very straightforward.

Before starting, make sure that you must knowledge of Django and Python programming languages. Create the basic setup of Django and configure the settings.

Configure Settings

First, we need to configure the email host server in the settings.py for the confirmation mail. Add the below configuration in the settings.py file.

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'email@gmail.com'
EMAIL_HOST_PASSWORD = 'password'

We used the email-id along with the password and Gmail SMTP host server. You can use the other SMTP server as well. Create tokens.py

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


class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            text_type(user.pk) + text_type(timestamp) +
            text_type(user.is_active)
        )


account_activation_token = TokenGenerator()

We used the PasswordTokenGenerator class that is used to reset the password. In the above code, we generated the unique token for confirmation.

Create Registration Form

Django provides the built-in UserCreationForm which is an excellent class to create forms. We create a forms.py file in the app and import the UserCreationForm class. Let's understand the following code.

from django import forms  
from django.contrib.auth.forms import UserCreationForm  
from django.contrib.auth.models import User  
  
class SignupForm(UserCreationForm):  
    email = forms.EmailField(max_length=200, help_text='Required')  
    class Meta:  
        model = User  
        fields = ('username', 'email', 'password1', 'password2')  

In the above code, we imported the UserCreationForm and built-in User. Then we created a SignupForm including an extra field email in SignupForm.

from django.shortcuts import render, HttpResponse, redirect
from django.contrib.sites.shortcuts import get_current_site
from django.template.loader import render_to_string
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from django.core.mail import EmailMultiAlternatives
from .tokens import account_activation_token
from django.http import HttpResponseRedirect
from django.contrib import messages
from .forms import CustomUserForm



def sign_up(request):
    if not request.user.is_authenticated:
        _next = request.GET.get("next")
        # breakpoint()
        if request.method == "POST":
            form = CustomUserForm(request.POST)
            if form.is_valid():
                # save form in the memory not in database
                user = form.save(commit=False)
                user.is_active = False
                user.save()
                # to get the domain of the current site
                current_site = get_current_site(request)
                mail_subject = "Activation link has been sent to your email id"
                message = render_to_string(
                    "acc_activate.html",
                    {
                        "user": user,
                        "domain": current_site.domain,
                        "uid": urlsafe_base64_encode(force_bytes(user.pk)),
                        "token": account_activation_token.make_token(user),
                    },
                )
                to_email = form.cleaned_data.get("email")
                # email = EmailMessage(
                email = EmailMultiAlternatives(mail_subject, message, to=[to_email])
                email.attach_alternative(message, "text/html")
                email.send()
                messages.success(
                    request,
                    "Please check your email and confirm your email address to complete the registration",
                )
                if _next:
                    return HttpResponseRedirect(_next)
                return HttpResponseRedirect("/signup/")

        else:
            form = CustomUserForm()
        return render(request, "signup.html", {"form": form})
    else:
        return HttpResponseRedirect("/profile/")

Here we create a view of sign up, it got information using the POST method and valid it. We have used the commit = False because it allows us to get the model object and add some extra attributes. Here we have done user.is_active = False which means the user cannot log in until the email is verified.

Then we used the EmailMessage() function to send mail along with the subject, message. Email messages created by a template.


<!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>Document</title>
</head>
<body style="background-color: pink;">
    {% autoescape off %}  
    <table cellspacing="0" border="0" cellpadding="0" width="100%" bgcolor="#f2f3f8"
    style="@import url(https://fonts.googleapis.com/css?family=Rubik:300,400,500,700|Open+Sans:300,400,600,700); font-family: 'Open Sans', sans-serif;">
    <tr>
        <td>
            <table style="background-color: #f2f3f8; max-width:670px;  margin:0 auto;" width="100%" border="0"
            align="center" cellpadding="0" cellspacing="0">
            <tr>
                <td style="height:80px;">&nbsp;</td>
            </tr>
            <tr>
                <td style="text-align:center;">
                    <a style="color: black; font-size: 20px; text-shadow: #1e1e2d;" href="#?" title="logo" target="_blank">
                        Welcome to Espére
                    </a>
                    <p>Hi {{ user.username }},</p>
                </td>
            </tr>
            <tr>
                <td style="height:20px;">&nbsp;</td>
            </tr>
            <tr>
                <td>
                    <table width="95%" border="0" align="center" cellpadding="0" cellspacing="0"
                            style="max-width:670px;background:#fff; border-radius:3px; text-align:center;-webkit-box-shadow:0 6px 18px 0 rgba(0,0,0,.06);-moz-box-shadow:0 6px 18px 0 rgba(0,0,0,.06);box-shadow:0 6px 18px 0 rgba(0,0,0,.06);">
                            <tr>
                                <td style="height:40px;">&nbsp;</td>
                            </tr>
                            <tr>
                                <td style="padding:0 35px;">
                                    <h1 style="color:#1e1e2d; font-weight:500; margin:0;font-size:32px;font-family:'Rubik',sans-serif;">You have
                                        requested to confirm your Account</h1>
                                        <span
                                        style="display:inline-block; vertical-align:middle; margin:29px 0 26px; border-bottom:1px solid #cecece; width:100px;"></span>
                                        <p style="color:#455056; font-size:15px;line-height:24px; margin:0;">
                                            We're excited to have you get started. First, you need to confirm your account. Just press the button below.
                                        </p>
                                        <a href="http://{{ domain }}{% url 'activate' uidb64=uid token=token %}"
                                        style="background:#206ee2;text-decoration:none !important; font-weight:500; margin-top:35px; color:#fff;text-transform:uppercase; font-size:14px;padding:10px 24px;display:inline-block;border-radius:50px;">Confirm
                                        Account</a>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="height:40px;">&nbsp;</td>
                                </tr>
                            </table>
                        </td>
                <tr>
                    <td style="height:20px;">&nbsp;</td>
                </tr>
                <tr>
                    <td style="text-align:center;">
                        <p style="font-size:14px; color:rgba(69, 80, 86, 0.7411764705882353); line-height:18px; margin:0 0 0;"><strong>© 2022 Copyright: Espére</strong></p>
                    </td>
                </tr>
                <tr>
                    <td style="height:80px;">&nbsp;</td>
                </tr>
            </table>
        </td>
    </tr>
</table>
{% endautoescape %}
</body>
</html>

This template creates an email body by activating the link that will send for application.

Now we need to create a view for the activation link.

Create Activation View

 

Once the user clicks on the activation link, we need to activate their account through the activation link. This process is handled by the activated view.

views.py
def activate(request, uidb64, token):
    User = get_user_model()
    try:
        uid = force_str(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.save()
        # return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
        messages.success(
            request,
            "Thank you for your email confirmation. Now you can login your account.",
        )
        return HttpResponseRedirect("/login/")
    else:
        return HttpResponseRedirect("/invalid/")

We have added the activate function after the signup function. This view will check token it valid then the user will activate and login. We set user.is_active = True which means the user can log in.

Now we will map the views to the URLs.

from django.urls import path
from .import views

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

Create a signup form in template/signup.html.

{% extends 'base.html' %}  
  
{% block content %}  
<div class = "container">  
  <h2>Sign up</h2>  
  <form method="post">  
    {% csrf_token %}  
      {% for field in form %}  
      <p>  
        {{ field.label_tag }}<br>  
        {{ field }}  
        {% if field.help_text %}  
          <small style="display: none ">{{ field.help_text }}</small>  
        {% endif %}  
        {% for error in field.errors %}  
          <p style="color: red">{{ error }}</p>  
        {% endfor %}  
      </p>  
      {% endfor %}  
    <button type="submit">Sign up</button>  
  </form>  
</div>  
{% endblock %}  

The form will look like below. When the user clicks on the submit button the activation link sends their entered email id.

Click on the received link and now you are ready to log in.

note: Make sure that the click here to generate your app password. Otherwise, you will face smtp error.

Tada, we have successfully created an email configuration-based user registration. This process is straightforward and requires less code to complete. You can improve it by adding more functionality such as an attractive template, redirect to login, etc.

 

django UserRegistration Email-Confirmation OPT Appreciate you stopping by my post! 😊

Add a comment


Note: If you use these tags, write your text inside the HTML tag.
Login Required
Author's profile
Profile Image

Abdulla Fajal

Django Developer

With 'espere.in' under my care, I, Abdulla Fajal, graciously invite your insights and suggestions, as we endeavour to craft an exquisite online experience together.