Django · Python

Block disposable email in Django

Add a form validator that calls Piisend before saving the user. Works in Django 3, 4, and 5. Pairs cleanly with django-allauth or Django's built-in auth.

The code

# validators.py
import os
import httpx
from django.core.exceptions import ValidationError

PIISEND_URL = "https://api.piisend.com/api/v1/intelligence/email"

def reject_disposable_email(value: str) -> None:
    try:
        r = httpx.post(
            PIISEND_URL,
            headers={
                "Authorization": f"Bearer {os.environ['PIISEND_API_KEY']}",
                "Content-Type": "application/json",
            },
            json={"email": value},
            timeout=5.0,
        )
        if not r.is_success:
            return  # fail open
        if r.json().get("signals", {}).get("disposable"):
            raise ValidationError("Please use a permanent email address.")
    except httpx.HTTPError:
        return  # fail open

# forms.py
from django import forms
from .validators import reject_disposable_email

class SignupForm(forms.Form):
    email = forms.EmailField(validators=[reject_disposable_email])
    password = forms.CharField(widget=forms.PasswordInput)

API key

Store `PIISEND_API_KEY` in environment variables or Django settings — never commit live keys.

Fail-open vs fail-closed

Network errors silently pass validation. Log failures if you need to monitor API health.

Pair with verification

Call the validator in `UserCreationForm.clean_email()` or allauth's adapter `clean_email` hook.

Send verification email with Piisend

After blocking disposable addresses, send OTP and verification mail through the same Piisend account. One API key for intelligence checks and transactional sends.