DEV Community

Cover image for How to build a Email Newsletter Subscriber in Django?
Shubham Singh Kshatriya
Shubham Singh Kshatriya

Posted on • Updated on

How to build a Email Newsletter Subscriber in Django?

An email newsletter is an email that is sent out on a regular basis (e.g. weekly or monthly) to certain users. As you’ll probably know by looking at your inboxes, email newsletters are a popular medium for businesses. Stats says that 85% of B2B marketers send email newsletters as part of their content marketing strategy.

In this article we will build our own email newsletter subscriber using Django and AJAX.

Requirements: Basics of Django and AJAX. You can refer to this article if you wanna learn how to use AJAX in Django.

Setting up UI

index.html

This is the HTML file which will contain the UI. As you may have noticed, we will use bootstrap 4 components and some custom CSS. PS: Make sure to include csrf_token in the form :)

{% load static %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
        integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
        crossorigin="anonymous">
    <title>Newsletter Subscribtion Example</title>
    <link rel="stylesheet" href="{% static 'assets/app.css' %}">
</head>
<body>
    <div class="col-lg-6 col-md-6" style="margin: 100px auto; display: block;">
        <form enctype="multipart/form-data" method="POST" action="" style="text-align: center;">
            {% csrf_token %}
            <div class="form-group">
                <label>Subscribe to our Newsletter.</label>
                <input type="email" class="form-control" id="userEmail" placeholder="Enter email" required>
                <small style="font-weight: 600;color: red;" class="error"></small>
                <input type="text" class="form-control mt-2" id="userName" placeholder="Enter name" required>
                <small style="font-weight: 600;color: green;" class="success"></small>
            </div>
            <input type="submit" value="Subscribe" id="submit" class="btn">     
        </form>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="{% static 'assets/app.js' %}"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

app.css

Let's add some of our own CSS to make our UI more aligned.

label {
    font-size: 22px;
    font-weight: bold;
}

.btn {
    padding: 7px 21px;
    background-color: rgb(143, 1, 1);
    color: white;
    font-size: 18px;
}

body {
    background-color: azure;
}
Enter fullscreen mode Exit fullscreen mode

This is how our UI will appear.
Alt Text

app.js
We will retrieve the values that are entered by user in input box and check if the email entered by user is valid or already exists in our database.

We will use AJAX request to validate the email as soon as user enters the email by binding a change event on email input box. If the email and name of the user are valid we will add it to our database using another AJAX request.

const validateEmail = function(email) {
    var formData = new FormData();
    formData.append('email', email)
    $.ajaxSetup({
        headers: {
            "X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value,
        }
    });
    $.ajax({
        url: '/validate/',
        type: 'POST',
        dataType: 'json',
        cache: false,
        processData: false,
        contentType: false,
        data: formData,
        error: function (xhr) {
            console.error(xhr.statusText);
        },
        success: function (res) {
            $('.error').text(res.msg);
        }
    });
};

const subscribeUser = function(email, name) {
    var formData = new FormData();
    formData.append('email', email);
    formData.append('name', name);
    $.ajaxSetup({
        headers: {
            "X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value,
        }
    });
    $.ajax({
        url: '/newsletter/',
        type: 'POST',
        dataType: 'json',
        cache: false,
        processData: false,
        contentType: false,
        data: formData,
        error: function (xhr) {
            console.error(xhr.statusText);
        },
        success: function (res) {
            $('.success').text(res.msg);
            $('#userEmail').val(' ');
            $('#userName').val(' ');
        }
    });
};

(function ($) {
    $('#submit').on('click', () => {
        event.preventDefault();
        const userEmail = $('#userEmail').val();
        const userName = $('#userName').val();
        if (userEmail && userName) {
            subscribeUser(userEmail, userName);
        }
    });

    $('#userEmail').on('change', (event) => {
        event.preventDefault();
        const email = event.target.value;
        validateEmail(email);
    });
})(jQuery);
Enter fullscreen mode Exit fullscreen mode

With this we are done with the front end. Now let's build a model and a server to try this code.

Setting up server

urls.py

The url where the request will be made

from django.urls import path
from . import views

urlpatterns = [
    path('newsletter/', views.index, name='index'),
    path('validate/', views.validate_email, name='validate_email'),
]
Enter fullscreen mode Exit fullscreen mode

views.py

The request made to the server are handled by function defined in views.py. When we get a POST request, we retrieve the data and add them to the database.

  • validate_email: to validate the email entered by user
  • index: to add user to database

We will also send a confirmation mail to the user using Google's SMTP server. If you want to know how it works, you can check this article.

from django.shortcuts import render
from django.http import JsonResponse
import re
from .models import SubscribedUsers
from django.core.mail import send_mail
from django.conf import settings

def index(request):
    if request.method == 'POST':
        post_data = request.POST.copy()
        email = post_data.get("email", None)
        name = post_data.get("name", None)
        subscribedUsers = SubscribedUsers()
        subscribedUsers.email = email
        subscribedUsers.name = name
        subscribedUsers.save()
        # send a confirmation mail
        subject = 'NewsLetter Subscription'
        message = 'Hello ' + name + ', Thanks for subscribing us. You will get notification of latest articles posted on our website. Please do not reply on this email.'
        email_from = settings.EMAIL_HOST_USER
        recipient_list = [email, ]
        send_mail(subject, message, email_from, recipient_list)
        res = JsonResponse({'msg': 'Thanks. Subscribed Successfully!'})
        return res
    return render(request, 'index.html')

def validate_email(request): 
    email = request.POST.get("email", None)   
    if email is None:
        res = JsonResponse({'msg': 'Email is required.'})
    elif SubscribedUsers.objects.get(email = email):
        res = JsonResponse({'msg': 'Email Address already exists'})
    elif not re.match(r"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", email):
        res = JsonResponse({'msg': 'Invalid Email Address'})
    else:
        res = JsonResponse({'msg': ''})
    return res
Enter fullscreen mode Exit fullscreen mode

models.py

We cannot store data until we have a model. Let's create one.

from django.db import models

class SubscribedUsers(models.Model):
    email = models.CharField(unique=True, max_length=50)
    name = models.CharField(max_length=50)
Enter fullscreen mode Exit fullscreen mode

Run these commands in the terminal to migrate your model

python manage.py makemigrations
python manage.py  migrate
Enter fullscreen mode Exit fullscreen mode

Now we are all set to test our application. Go to your browser, run the serving URL and test your app.

This are few snapshots of the output.
Alt Text
Alt Text
Alt Text

With this we have build a way for users to subscribe to our website. All the users who fill these detail and hit the subscribe button will be added into our database. The next step for will be sending a mail to all the users that we have in our database for any article we want. That's it for this article. Thanks for reading.

You can also connect with me on Twitter for any discussion.

Adios!

Top comments (9)

Collapse
 
giftedstan profile image
giftedstan

This is a lovely tutorial

Collapse
 
shubhamkshatriya25 profile image
Shubham Singh Kshatriya

Thank you, glad you liked it!

Collapse
 
laurianoelmiroduarte profile image
Lauriano Elmiro Duarte

better to use django-newsletter
django-newsletter.readthedocs.io

Collapse
 
dewhallez profile image
Akin Wale

Great writeup

Collapse
 
shubhamkshatriya25 profile image
Shubham Singh Kshatriya

Glad you liked it, thank you!

Collapse
 
fleepgeek profile image
Emmanuel Okiche

How is this a newsletter subscriber?
Your title is misleading.

Collapse
 
shubhamkshatriya25 profile image
Shubham Singh Kshatriya

Oh, sorry for that. Could you please point what made you feel this so that I can correct

Collapse
 
fleepgeek profile image
Emmanuel Okiche

There is no where the tutorial shows the newsletter subscription.
I couldn't find any newsletter service.
The tutorial just shows how to use insert to db with ajax and how to send an email.

Thread Thread
 
shubhamkshatriya25 profile image
Shubham Singh Kshatriya

Every site I visited so far, ask to enter an email and click on subscribe. This way my email is with them. Now if they want to send any updates to subscribed users, they will draft a mail and send to every email that's in the database. These 2 things together constitute a newsletter service. I guess this tutorial helps to make a way for users to subscribe to a site (store their emails in our db through UI). Next step will be to send updates to all the subscribed users( I did mentioned this at the end).

I referred to few articles across web and most of them have this logic. If I am wrong with my understanding, apologies for that.