Sunday, 30 April 2017

django send one time use account activation email

django one time activation link email
  • After success registration of the user, we will send activation link email to the users email account.
  • After clicking the activation link we have to activate users account & make user login. 
  • This process will avoid the fake accounts in our application.
app/urls.py
from django.conf.urls import url
from app import views

urlpatterns = [
    # ......
    url(r'^activate/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/account/$',
        views.activate_user_account, name='activate_user_account'),
    # ......
]
app/views.py
from django.core.urlresolver import reverse
from django.contrib.auth import login
from django.conf import settings
from django.utils.encoding import force_bytes
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_encode
from django.core.mail import EmailMultiAlternatives
from django.contrib.auth.tokens import default_token_generator
from django.core.urlresolvers import reverse
from django.template.loader import render_to_string
from django.http import HttpResponse

from app.models import User


def send_account_activation_email(request, user):
    text_content = 'Account Activation Email'
    subject = 'Email Activation'
    template_name = "emails/account/activation.html"
    from_email = settings.DEFAULT_FROM_EMAIL
    recipients = [user.email]
    kwargs = {
        "uidb64": urlsafe_base64_encode(force_bytes(user.pk)).decode(),
        "token": default_token_generator.make_token(user)
    }
    activation_url = reverse("app:activate_user_account", kwargs=kwargs)

    activate_url = "{0}://{1}{2}".format(request.scheme, request.get_host(), activation_url)

    context = {
        'user': user,
        'activate_url': activate_url
    }
    html_content = render_to_string(template_name, context)
    email = EmailMultiAlternatives(subject, text_content, from_email, recipients)
    email.attach_alternative(html_content, "text/html")
    email.send()


def activate_user_account(request, uidb64=None, token=None):
    try:
        uid = force_text(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except User.DoesNotExist:
        user = None
    if user and default_token_generator.check_token(user, token):
        user.is_email_verified = True
        user.is_active = True
        user.save()
        login(request, user)
        return redirect('hr:user_profile')
    else:
        return HttpResponse("Activation link has expired")
emails/account/activation.html
<html>
<title> Email Activation </title>
<body>
    <p> Dear {{ user }}</p>
    <p>Your account has successfully created. Please click below link to activate your account.</p>
    <p><a href="{{ activate_url }}"> Activate your account </a></p>
</body>
</html>
In the last blog post "User Registration" we have seen how to register a user.

Let's start our discussion,
  • "urlsafe_base64_encode" takes user id and generates the base64 code(uidb64)
  • "default_token_generator.make_token" takes the user object and generates the onetime usable token for the user(token)
  • we create activation email using uidb64 and token and send it to user's email.
  • after clicking the activation url it will dispatched to the "activate_user_account" view
  • Here we receive "uidb64", "token". By using the "urlsafe_base64_decode" we decode the base64 encoded "uidb64" user id. We query the database with user id to get user.
  • We check the token validation using "default_token_generator.check_token" and "user object"
Reference: https://github.com/django/django/blob/master/django/contrib/auth/tokens.py#L80
Please comment if you have any questions.
 


EmoticonEmoticon