Skip to content

Email Verification

Resources:

In this video, we are going to implement the feature of email verification. Using this feature we will send one link to the user's email to verify their email address.

This video is divided into 4 part.

  • In the first part, we will create a token generator.
  • After that, we will write code to handle sending emails to the user.
  • Then, we will create a view so that user can send a email verification request.
  • At last, we will create a view to verify the email address once the user clicks the email verification link.

Token Generation

At first, lets start with token generation part.

Create a utils.py file in the user app.

Now, import the PasswordResetTokenGenerator. Django uses this token generator to generate tokens for resetting password.

from django.contrib.auth.tokens import PasswordResetTokenGenerator

You might be wondering why I am importing PasswordResetTokenGenerator. Actually, we will use this token generator to create our own token generator for email verification. By following this approach, we will write less code and implement the functionality.

Now, create a class named TokenGenerator and inherit the PasswordResetTokenGenerator

class TokenGenerator(PasswordResetTokenGenerator):
    # In this class, we only need to modify the make hash value method.
    def _make_hash_value(self, user, timestamp):
        login_timestamp = (
            ""
            if user.last_login is None
            else user.last_login.replace(microsecond=0, tzinfo=None)
        )
        # Get the user email address
        email = user.email
        # Now return such a value that will change once the user verifies the email address.
        return f"VerifyEmail-{user.pk}{user.password}{login_timestamp}{timestamp}{email}{user.is_active}"

# After that, create a instance of this token generator.
EmailVerificationTokenGenerator = TokenGenerator()

In this way, we have wrote a class for generating token for email verification.

Email Handling

Now, we need to work on handle the email sending code.

Create a email.py file. In this file, we will write a code for sending email to the user.

Here, we need to import some methods and functions before writing the function.

# At first, we need EmailMessage for sending emails to the user
from django.core.mail import EmailMessage

# Now, we need a method named render_to_string that takes a html file with some context and returns a string value.
from django.template.loader import render_to_string

# After that, we need to get the domain name of this project, so we can create a link for redirecting user to our website from their email inbox.
from django.contrib.sites.shortcuts import get_current_site

# Then, we need a helper method called urlsafe_base64_encode.
# It is used to encode a given string into a URL-safe base64 format so that encoded string can be safely transmitted over the internet without any loss of information.
from django.utils.http import urlsafe_base64_encode

# Then, we will import force_bytes method. It is used to ensure that a given value is converted to bytes, regardless of its original type. 
from django.utils.encoding import force_bytes

# Then, we will import EmailVerificationTokenGenerator
from user.utils import EmailVerificationTokenGenerator

# After that, import get_user_model.
from django.contrib.auth import get_user_model

# At last, instantiate the get_user_model.
User = get_user_model()

# Now create a function named send_email_verification.
# This function takes request as well as id in the parameters.
def send_email_verification(request, id):

    # At first, get the user details from the database.
    user = User.objects.get(pk=id)

    # Then, get the current site that means the domain name on which the django project is accessible. 
    current_site = get_current_site(request)

    # Now, write the subject of the email
    subject = "Request for Email Verification | Vaccination Scheduling App Account"

    # Then create a message.
    message = render_to_string(
        # We will use render to string to convert our html template into string form.
        "user/email-verify.html",
        {
            # Now provide some context information to the html file.
            "full_name": user.get_full_name(),
            "domain": current_site.domain,

            # Here, we will encode the user id in base64 format so that encoded user id can be safely transmitted over the internet without any loss of information.
            "uid": urlsafe_base64_encode(force_bytes(user.id)),

            # Then, we will generate token for the user
            "token": EmailVerificationTokenGenerator.make_token(user),
        },
    )

    # Now, specify where the email needs to be sent
    to_email = user.email

    # After that, construct the email message with subject message and to
    email = EmailMessage(subject, message, to=[to_email])

    # And at last, send the email.
    return email.send()

In this way, we have wrote a function that sends an email verification link to the user email addres.

Now, lets create the email-verify.html file.

I have attached email-verify.html file. Download it, copy its content and paste it in this html file.

{% autoescape off %}  
Hi {{ full_name }},  
Please click on the link to verfy your email,  
http://{{ domain }}{% url 'user:email-activate' uidb64=uid token=token %}  
{% endautoescape %}  

At last, we need to specify the email account credentials so that django can use that credentials to send email to the user. Since, we are in development mode, so we can use console EmailBackend to print the email messages to the console. In the production application, you can provide the actual email account information to send email messages to the user.

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

Views

[Open views.py file]

Now, lets work on views for sending and verifying email verification request.

Email Verification Request

At first, import the send_email_verification function in this views.py file.

from user.email import send_email_verification

Now create a view for sending email verification request

def email_verification_request(request):
    # In this view, at first we will check whether the user email is verified or not.

    # If the user email is not verified we will send email verification  link
    if not request.user.is_email_verified:
        send_email_verification(request, request.user.id)
        return HttpResponse("Email Verification Link sent to your email address")

    # If the user email is already verified, we will return HTTPResponseForbidden.
    # from django.http import HttpResponseForbidden, 
    return HttpResponseForbidden("Email Already Verified")

After that, lets write the url path for this view.

path("verify-email/", views.email_verification_request, name="verify-email"),

Now, open your profile-view template and update the url path for verifying email

(<a href="{% url 'accounts:verify-email' %}">Verify Email</a>)

[Run the development server and see the changes.]

Email Verifier

Now, lets write the view for verifying the user email address once the user clicks the link from their email inbox.

In the views.py file at first import the user model

from django.contrib.auth import get_user_model

User = get_user_model()

Then after, import the email verification token generator.

from user.utils import EmailVerificationTokenGenerator

Then import the force_str method. This method converts data of any type into string.

from django.utils.encoding import force_str

Then import the urlsafe_base64_decode to decode the user id from the url.

from django.utils.http import urlsafe_base64_decode

Now, create a view for email verifier.

def email_verifier(request, uidb64, token):
    # This view takes user id in encoded in base 64 format and token.

    # Now at first, extract the user id and get the user information from the database.
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None

    # If the user is request.user
    if user == request.user:

        # Then we will check the token for that user.
        if EmailVerificationTokenGenerator.check_token(user, token):

            # If this value is true then we need to verify the email address.
            user.is_email_verified = True

            # Now save the user information
            user.save()

            # Also send the success message
            messages.success(request, "Email Address Verified Successfully")

            # At last, redirect the user to the profile view page.
            return HttpResponseRedirect(reverse("accounts:profile-view"))

        # If the token is not valid, then return HTTPResponseBadRequest
        return HttpResponseBadRequest("Activation link is invalid!")

    # If the user is not logged in or if it is different user, then return HTTPResponseForbidden
    return HttpResponseForbidden(content="You don't have permission to use this link")

At last, add the url path for this view.

path("email/activate/<uidb64>/<token>/", views.email_verifier, name="email-activate"),

[Run the development server and see the changes.]