Django's form and model validation system makes it straightforward to add external email validation. This guide shows how to integrate Mailchk using a custom validator, a service with caching, and DRF serializer integration.
Step 1: Validation Service
# utils/email_validation.py
import requests
from django.conf import settings
from django.core.cache import cache
def validate_email_address(email: str) -> dict:
cache_key = f"email_validation:{email}"
cached = cache.get(cache_key)
if cached is not None:
return cached
try:
response = requests.post(
"https://api.mailchk.io/v1/check",
json={"email": email},
headers={
"X-API-Key": settings.MAILCHK_API_KEY,
"Content-Type": "application/json",
},
timeout=5,
)
response.raise_for_status()
result = response.json()
except requests.RequestException:
result = {"valid": True, "disposable": False}
cache.set(cache_key, result, timeout=86400)
return result
Step 2: Custom Validator
# validators/email.py
from django.core.exceptions import ValidationError
from utils.email_validation import validate_email_address
def validate_real_email(email: str) -> None:
result = validate_email_address(email)
if not result.get("valid", False):
raise ValidationError("Please enter a valid email address.")
if result.get("disposable", False):
raise ValidationError("Disposable email addresses are not allowed.")
Step 3: Use in Models and Forms
# models.py
from validators.email import validate_real_email
class User(models.Model):
email = models.EmailField(unique=True, validators=[validate_real_email])
# forms.py
class SignupForm(forms.Form):
email = forms.EmailField(validators=[validate_real_email])
password = forms.CharField(widget=forms.PasswordInput)
Django REST Framework Integration
# serializers.py
from rest_framework import serializers
from utils.email_validation import validate_email_address
class SignupSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField(min_length=8)
def validate_email(self, value):
result = validate_email_address(value)
if not result.get("valid"):
raise serializers.ValidationError("Invalid email address.")
if result.get("disposable"):
raise serializers.ValidationError("Disposable emails not allowed.")
if result.get("did_you_mean"):
self.context["email_suggestion"] = result["did_you_mean"]
return value
Async Support (Django 4.1+)
import httpx
async def validate_email_async(email: str) -> dict:
async with httpx.AsyncClient() as client:
response = await client.post(
"https://api.mailchk.io/v1/check",
json={"email": email},
headers={"X-API-Key": settings.MAILCHK_API_KEY},
timeout=5.0,
)
return response.json()
Best Practices
- Cache results — use Redis or Memcached in production for fast lookups.
- Fail open — allow signups if the validation service is temporarily unreachable.
- Use the typo suggestion — return
did_you_meanto the user as a helpful prompt. - Validate in forms/serializers, not views — keeps validation reusable across your app.
Getting Started
Get your free API key at mailchk.io/signup. 200 validations/month free, sub-50ms response times.



