Skip to main content

Check signup emails in Django

This guide adds Signitize to a Django signup form. It uses requests, which you probably already have (pip install requests).

1. Add your key​

settings.py
import os

SIGNITIZE_API_KEY = os.environ["SIGNITIZE_API_KEY"]

Get a free key if you don't have one.

2. The model fields​

accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
email_canonical = models.CharField(max_length=254, unique=True, null=True, blank=True)
email_check = models.CharField(max_length=10, default="pending")

null=True lets several pending users have no canonical email without breaking the unique constraint.

3. The check​

accounts/signitize.py
import logging

import requests
from django.conf import settings

logger = logging.getLogger(__name__)


def check_email(email):
"""Return the Signitize result, {"invalid": True}, or None when unavailable."""
try:
response = requests.post(
"https://api.signitize.io/v1/check",
headers={"Authorization": f"Bearer {settings.SIGNITIZE_API_KEY}"},
json={"email": email},
timeout=5,
)
except requests.RequestException:
return None
if response.ok:
return response.json()
if response.status_code == 400:
return {"invalid": True}
logger.warning("Signitize answered %s", response.status_code)
return None

4. The form​

accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm

from .models import User
from .signitize import check_email


class SignupForm(UserCreationForm):
class Meta:
model = User
fields = ("username", "email")

def clean_email(self):
email = self.cleaned_data["email"].strip()
result = check_email(email)

if result and result.get("invalid"):
raise forms.ValidationError("Enter a valid email address.")
if result and result["disposable"]:
raise forms.ValidationError("Please use a permanent email address.")
if result and not result["deliverable"]:
raise forms.ValidationError("This email address cannot receive mail. Please check it for typos.")
if result and User.objects.filter(email_canonical=result["email"]).exists():
raise forms.ValidationError("You already have an account.")

self.email_result = result
return email

def save(self, commit=True):
user = super().save(commit=False)
result = self.email_result
user.email_canonical = result["email"] if result else None
user.email_check = "passed" if result else "pending"
if commit:
user.save()
return user

Django's EmailField validates the format first, so Signitize is called only for well-formed addresses. Send your verification email to user.email, the address the user typed.

5. Recheck pending users​

Users created while Signitize was unavailable are pending. Run a management command every 10 minutes (cron, Celery beat or similar) with the recheck logic from Never block a signup, and grant free perks only to passed users.