Developer resources

Validate emails in Python, Flask, and Django

Python has good built-in tools for email validation, but none of them actually verify the mailbox. Here is the upgrade with Flask and Django examples.

AD

Admin

June 1, 2026 · 3 min read

Python developers have a few solid built-in libraries for email validation. email-validator, django.core.validators, plain regex. They all confirm the address looks valid. None tell you whether the mailbox is real. This guide bridges the gap with copy-paste integrations for Flask and Django.

The starting point: email-validator

Most Python projects use the email-validator library. It checks syntax, normalizes case, and optionally does DNS.

from email_validator import validate_email, EmailNotValidError

try:
    info = validate_email(raw_email, check_deliverability=True)
    email = info.normalized
except EmailNotValidError as e:
    return {'error': str(e)}

check_deliverability=True runs an MX lookup, so it catches obviously-bad domains. It does not verify the specific mailbox.

The real verification call

import os
import requests

def verify_email(address: str) -> dict:
    response = requests.post(
        'https://mailoclean.com/api/v1/verify',
        headers={
            'Authorization': f'Bearer {os.environ["MAILOCLEAN_KEY"]}',
            'Content-Type': 'application/json',
        },
        json={'email': address},
        timeout=5,
    )
    response.raise_for_status()
    return response.json()

Wiring into Flask

from flask import Flask, request, jsonify
app = Flask(__name__)

@app.post('/signup')
def signup():
    email = request.json.get('email', '').strip().lower()
    if not email:
        return jsonify(error='Email is required.'), 422

    try:
        result = verify_email(email)
    except requests.RequestException:
        result = {'status': 'unknown'}

    if result.get('status') in ('invalid', 'disposable'):
        return jsonify(error='Please use a valid, permanent email address.'), 422

    user = create_user(email)
    return jsonify(user=user)

Wiring into Django

Cleanest with a custom validator:

# validators.py
from django.core.exceptions import ValidationError
from django.core.cache import cache
import requests, os

def verify_real_email(value):
    cache_key = f'verify:{value.lower()}'
    result = cache.get(cache_key)
    if result is None:
        try:
            r = requests.post(
                'https://mailoclean.com/api/v1/verify',
                headers={'Authorization': f'Bearer {os.environ["MAILOCLEAN_KEY"]}'},
                json={'email': value},
                timeout=5,
            )
            result = r.json()
            cache.set(cache_key, result, 86400)
        except requests.RequestException:
            return  # fail open

    if result.get('status') in ('invalid', 'disposable'):
        raise ValidationError('Please use a valid, permanent email address.')

Then in your form or serializer:

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

class SignupForm(forms.Form):
    email = forms.EmailField(validators=[verify_real_email])

Async with Django

If you want verification to be non-blocking, run it in Celery after account creation:

@shared_task
def verify_user_email(user_id):
    user = User.objects.get(pk=user_id)
    result = verify_email(user.email)
    user.email_status = result.get('status', 'unknown')
    user.email_score = result.get('score')
    user.save()

Bulk verification in Python

For lists, hit the bulk endpoint instead of looping. Submit a single batch, poll for status, download the result.

r = requests.post(
    'https://mailoclean.com/api/v1/bulk',
    headers={'Authorization': f'Bearer {os.environ["MAILOCLEAN_KEY"]}'},
    json={'emails': '\n'.join(emails_list)},
)
batch_id = r.json()['id']
# poll /api/v1/bulk/{id} until status is 'done'

FAQ

What about the verify-email PyPI package?

It works for syntax and MX, same as email-validator. Neither runs an SMTP handshake. For real mailbox verification you need an external service like MailoClean.

Is the API call slow inside a request handler?

Median 1.4 seconds. For synchronous signup endpoints, that is acceptable. For latency-sensitive flows, verify async after account creation.

Plug it in

Grab a key from the dashboard, set the env var, paste the verifier function. Five-minute integration in Flask or Django.

Ready to try MailoClean?

Clean your list and start sending with confidence.

Free verifications included with every account. Credits never expire.

AD

Admin

Email deliverability writer at MailoClean

Back to all posts

Keep reading

Related posts