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.