Django registration with confirmation email

When we signup on website its send a email for confirmation to active an account. Or sometime need to change password or change email of an account.

Here i will show you how to send a confirmation email when someone register on your web app that deploy on Django.

I will discuss about the normal way to deploy this. But there other option also to deploy this. Like django-registration, django-registration-redux, django-allauth application. Those application made this very easy, also integrated with authentication, account management, social account authentication etc.

Lets start

I have a project called mysite and an app called blog.

There is my project directory

django_blog
    blog
        admin.py
        forms.py
        models.py
        urls.py
        views.py
        templates
            signup.html
            acc_active_email.html
            
    django_blog
        settings.py
        urls.py
    manage.py

Configure settings

Firstly we configure email host server in in settings.py for sending confirmation email.

mysite/settings.py

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'youremail@gmail.com'
EMAIL_HOST_PASSWORD = 'yourpassword'
EMAIL_PORT = 587

Added this lines in your settings.py file.

Here, I used gmail smtp host server, you can use others smtp server also. If you get error then follow this answer, its says that allow less secure apps and display unlock captcha

Create Tokens

Now we have to create token that we will send for confirmation.

Create a new files named tokens.py in blog app

blog/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.is_active)

account_activation_token = AccountActivationTokenGenerator()

Basically it extends PasswordResetTokenGenerator to create token.

Django forms

I think best simple way to implement a user registration page on Django is using UserCreationForm. Here is my forms.py file.

blog/forms.py

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')

I have import UserCreationForm forms and User models. Then added an extra field email in SignupForm. This email field take email address while registering for email confirmation.

blog/views.py

from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import SignupForm
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from .tokens import account_activation_token
from django.contrib.auth.models import User
from django.core.mail import EmailMessage


def signup(request):
    if request.method == 'POST':
        form = SignupForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False
            user.save()
            current_site = get_current_site(request)
            message = render_to_string('acc_active_email.html', {
                'user':user, 
                'domain':current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'token': account_activation_token.make_token(user),
            })
            mail_subject = 'Activate your blog account.'
            to_email = form.cleaned_data.get('email')
            email = EmailMessage(mail_subject, message, to=[to_email])
            email.send()
            return HttpResponse('Please confirm your email address to complete the registration')
    
    else:
        form = SignupForm()
    
    return render(request, 'signup.html', {'form': form})

Here it got the form information using POST method, then valid it. Notice that i have write user.is_active = False so that user can’t login without email confirmation.

Then write email subject, message and send it by EmailMessage() function. Email message create by a template.

blog/templates/acc_active_email.html:

{% autoescape off %}
Hi {{ user.username }},
Please click on the link to confirm your registration,

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

This template create a email body with activate link that will send for application.

Activate function

User will get an activate link to their email address. Now we have to active their account through activation link.

By clicking on activation link the user send to the activate view.

blog/views.py

def activate(request, uidb64, token):
    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.save()
        login(request, user)
        # return redirect('home')
        return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
    else:
        return HttpResponse('Activation link is invalid!')

Added this activate function after signup function in blog/views.py file. This function will check token if it valid then user will active and login. Notice that i have write user.is_active=True. Before confirming email this was False.

Urls

blog/urls

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.home, name='home'),
    url(r'^signup/$', views.signup, name='signup'),
    url(r'^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.activate, name='activate'),
]

This is the urls for this app. Last url for email activate confirmation.

Sign up Template

Finally we have create the signup template, that user use for registration.

blog/templates/signup.html

{% block content %}
  <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>
{% endblock %}

This template will shown like this

signup

comments powered by Disqus