Easy modal newsletter signup form using Sendgrid, Python Django, and Tailwind CSS

I had a lot of trouble with Sendgrid’s documentation so wanted to put together this quick tutorial for setting up a modal newsletter signup form.

I’m using Sendgrid, Python Django, and Tailwind CSS (will write a review of Tailwind CSS at a later time. Short story is…I don’t love it and if I could start over, I’d go back to something with better support like plain old Bootstrap but the ability to quickly finagle with your CSS directly in HTML classes and make pretty good-looking UI is helpful).

When you’re done, you’ll get something like this:

Image for post
Image for post
Finished modal newsletter signup.

A modal, simple newsletter signup form that appears when a user lands on your page for the first time and does not pop-up for subsequent visits to the page. When a user submits their email, they will be added to your Sendgrid contacts list for future newsletters.

Ok, let’s get started:


You’ll need a Django project set up with Tailwind CSS and a Sendgrid free account. Please note you will need both Sendgrid Email API and Sendgrid Marketing activated. Sendgrid split these into two separate products which is very confusing for developers. If you had signed up for both, you will see on the left hand side of your Sendgrid dashboard, both products:

Image for post
Image for post
For some reason, you need to sign up for both because Email API gives you access to the Python API and Marketing gives you the contact lists to store into.

Sendgrid API Key

You will need to create an API key in Sendgrid for this project. The easiest way to do this is to go to your settings > API key page: https://app.sendgrid.com/settings/api_keys

Provide a reasonable name for your key and select “Full Access” for Permissions.

Image for post
Image for post
Creating an API key in Sendgrid

When you are done, it will display your API Key. Do not lose this and copy it immediately as this will be the only time you can access it!


To your home page HTML template, add the following HTML.

<div class="modal opacity-0 pointer-events-none fixed w-full h-full top-0 left-0 flex items-center justify-center">
<div class="modal-overlay absolute w-full h-full bg-gray-900 opacity-50"></div>

<div class="modal-container bg-white w-11/12 md:max-w-md mx-auto rounded shadow-lg z-50 overflow-y-auto">

<div class="modal-close absolute top-0 right-0 cursor-pointer flex flex-col items-center mt-4 mr-4 text-white text-sm z-50">
<svg class="fill-current text-white" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
<path d="M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z"></path>
<span class="text-sm">(Esc)</span>
<!-- Add margin if you want to see some of the overlay behind the modal-->
<div class="modal-content py-4 text-left px-6 leading-normal">
<div class="flex justify-between items-center pb-3">
<p class="text-2xl font-bold">Hey, smarty pants!</p>
<div class="modal-close cursor-pointer z-50">
<svg class="fill-current text-black" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
<path d="M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z"></path>
Let's keep in touch. Sign up for our newsletter
<form action="{% url 'YOURPROJECTNAME:subscriber-add' %}" method="POST" >
{% csrf_token %}
<input type="email" name="subscriber-email" class="mt-4 border-solid border border-teal-500 focus:border-teal-400 active:border-teal-400 w-full rounded px-3 py-2" placeholder="Email"/>

<button class="subscribe bg-teal-500 text-white px-3 py-2 rounded w-full mt-4 font-semibold">SUBSCRIBE</button>


Basically, what this is doing is creating a modal box with a form in it that POSTs to your subscriber-add end point, which we will add later. You can set up the CSS classes to your heart’s content and change background colors, border colors per the Tailwind CSS documentation (please note, to make this CSS work, you will need to import Tailwind CSS to your project via NPM or via static CSS stylesheet CDN link).


Now, let’s get into the JS.

<script>window.onload = function(e){ 
if(sessionStorage.getItem('homePageAlreadyVisited') == null)//The first time this will be null
sessionStorage.setItem('homePageAlreadyVisited', 'true'); //true can be anything. You are just concerned about checking whether 'homePageAlreadyVisited' key has some value or not.
setTimeout(function(){ toggleModal(); }, 1500);

const overlay = document.querySelector('.modal-overlay')
overlay.addEventListener('click', toggleModal)

var closemodal = document.querySelectorAll('.modal-close')
for (var i = 0; i < closemodal.length; i++) {
closemodal[i].addEventListener('click', toggleModal)

function toggleModal () {
const body = document.querySelector('body')
const modal = document.querySelector('.modal')


What this does is: upon the window loading, it checks to see if the visitor is a new visitor. If so, it will set the sessionStorage value for future visits and toggle the modal to appear. If the user has already been to the site, the sessionStorage value will already be set and the modal will not appear. I set a short delay before the modal appears because I’d like the visitor to be able to explore a bit of the website before signing up for the newsletter so they understand the value proposition better.

The next part of the Javascript controls the toggling functionality to open the modal up and also links the close button to hiding the modal.


In your urls.py file, add the subscriber-add path to the urlpatterns array.

urlpatterns = [
path('add_subscriber', views.subscriber_add, name='subscriber-add'),


In your views.py file, add your Sendgrid API key and a function to call when the add_subscriber end point is hit by the form. This function will handle the addition of the subscriber’s email to Sendgrid via the Sendgrid API.

import http.client
import requests
import json
def subscriber_add(request):
if request.method == 'POST':
conn = http.client.HTTPSConnection("api.sendgrid.com")
email = request.POST.get('subscriber-email')
payload = json.dumps({"contacts": [{"email": email}]})
headers = {
'authorization': "Bearer %s" % SENDGRID_API_KEY,
'content-type': "application/json"
conn.request("PUT", "/v3/marketing/contacts", payload, headers) res = conn.getresponse()
data = res.read()
except Exception as e:
return redirect('/')

That’s it! 🎉🎉🎉

Hope that helped save you some time. Sendgrid’s documentation had the wrong endpoint for adding contacts in the documentation (the correct documentation is here). Additionally, no one had put all the disparate tutorials from the Internet together into a functional guide for creating a newsletter signup modal with the form, new visitors only functionality, and Sendgrid integration.

Adapted from:

Tailwind Modal Component

StackOverview Answer

Sendgrid Documentation

Written by

Ex VC @ Kleiner Perkins, Former Apple/Microsoft intern

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store