Beta privataMailbeam è in beta privata: l'API pubblica non è ancora aperta.Iscriviti alla lista d'attesa

Mailbeam
Django + DRFBase15 minutiAggiornato a gennaio 2025

Verifica delle email in Django

Questo tutorial mostra come aggiungere la verifica delle email in tempo reale a un progetto Django. Costruirai un helper riutilizzabile e lo collegherai sia a un modulo classico di Django sia a un serializer di Django REST Framework (DRF), così che gli indirizzi non validi, usa e getta e non recapitabili vengano rifiutati prima che venga creato qualsiasi utente.

Che cosa costruirai

  • Un helper verify_email che avvolge l'API di Mailbeam e in caso di errore lascia passare
  • Un validatore validate_email_deliverable per i moduli di Django
  • Un validatore di campo di serializer di DRF per i progetti orientati alle API

Prerequisiti

  • Python 3.9+ e Django 4.2 o successivo
  • Una chiave API di Mailbeam (iscriviti gratis)
  • python-dotenv (o il caricatore di settings che preferisci)

Passo 1 — Aggiungi un client HTTP

Non c'è nessun SDK da installare. Mailbeam è un unico endpoint HTTP, quindi l'integrazione qui sotto è tutto il client che ti serve. Gli SDK ufficiali sono nella roadmap.

pip install httpx        # oppure usa requests, se è già nel progetto

Passo 2 — Configura i settings

Tieni la chiave fuori dal controllo di versione. Caricala dall'ambiente in settings.py:

# settings.py
import os

MAILBEAM_KEY = os.environ["MAILBEAM_KEY"]

# Punteggio minimo di qualità per accettare (0-100). 60 è un valore ragionevole.
MAILBEAM_MIN_SCORE = int(os.environ.get("MAILBEAM_MIN_SCORE", "60"))
# .env
MAILBEAM_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx

Passo 3 — Scrivi un helper di verifica riutilizzabile

Metti l'integrazione in un punto solo, così moduli, serializer e viste condividono lo stesso comportamento.

# accounts/verification.py
import logging

import httpx
from django.conf import settings

logger = logging.getLogger(__name__)

ENDPOINT = "https://api.mailbeam.dev/v1/verify"


def verify_email(email: str) -> tuple[bool, str | None]:
    """
    Restituisce (è_accettabile, codice_del_motivo).
    In caso di errore dell'API di Mailbeam LASCIA PASSARE (restituisce True),
    così un guasto non blocca mai registrazioni legittime.
    """
    try:
        response = httpx.post(
            ENDPOINT,
            json={"email": email.strip().lower()},
            headers={"Authorization": f"Bearer {settings.MAILBEAM_KEY}"},
            timeout=3.0,
        )
        response.raise_for_status()
        result = response.json()
    except httpx.HTTPError as exc:
        logger.error("Verifica di Mailbeam fallita: %s", exc)
        return True, None  # lascia passare

    if not result["valid"] or result["score"] < settings.MAILBEAM_MIN_SCORE:
        return False, result["reason"] or "invalid_email"
    return True, None

Passo 4 — Usalo in un modulo di Django

# accounts/forms.py
from django import forms
from django.core.exceptions import ValidationError
from .verification import verify_email


class SignupForm(forms.Form):
    email = forms.EmailField()
    password = forms.CharField(widget=forms.PasswordInput)

    def clean_email(self):
        email = self.cleaned_data["email"]
        ok, reason = verify_email(email)
        if not ok:
            raise ValidationError(
                "Inserisci un indirizzo email valido e recapitabile.",
                code=reason,
            )
        return email

Django esegue clean_email automaticamente durante form.is_valid(), quindi la tua vista non cambia:

# accounts/views.py
from django.shortcuts import render, redirect
from .forms import SignupForm


def signup(request):
    if request.method == "POST":
        form = SignupForm(request.POST)
        if form.is_valid():
            create_user(email=form.cleaned_data["email"])
            return redirect("welcome")
    else:
        form = SignupForm()
    return render(request, "accounts/signup.html", {"form": form})

Passo 5 — Usalo in un serializer di DRF

Nei progetti orientati alle API, valida dentro il serializer:

# accounts/serializers.py
from rest_framework import serializers
from .verification import verify_email


class SignupSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    def validate_email(self, value):
        ok, reason = verify_email(value)
        if not ok:
            raise serializers.ValidationError(
                f"Email rifiutata: {reason}"
            )
        return value
# accounts/views.py (DRF)
from rest_framework.generics import CreateAPIView
from .serializers import SignupSerializer


class SignupView(CreateAPIView):
    serializer_class = SignupSerializer
    # DRF restituisce automaticamente un 400 con gli errori di campo se la validazione fallisce

Passo 6 — Aggiungi la cache

Evita di riverificare lo stesso indirizzo (per esempio quando qualcuno riprova il modulo). Il framework di cache di Django ci sta bene:

# accounts/verification.py
from django.core.cache import cache

def verify_email(email: str) -> tuple[bool, str | None]:
    normalized = email.strip().lower()
    cached = cache.get(f"mb:{normalized}")
    if cached is not None:
        return cached

    try:
        result = _client.verify_sync(normalized)
        ok = result.valid and result.score >= settings.MAILBEAM_MIN_SCORE
        outcome = (ok, None if ok else (result.reason or "invalid_email"))
        cache.set(f"mb:{normalized}", outcome, timeout=86_400)  # 24 h
        return outcome
    except mailbeam.APIError as exc:
        logger.error("Verifica di Mailbeam fallita: %s", exc)
        return True, None  # lascia passare (non mettere in cache i fallimenti)

Prove

I domini di prova di Mailbeam restituiscono risultati deterministici e non consumano quota:

# accounts/tests.py
from django.test import TestCase
from .forms import SignupForm


class SignupFormTests(TestCase):
    def test_valid_email_passes(self):
        form = SignupForm(data={
            "email": "user@valid.mailbeam-test.dev",
            "password": "pass1234",
        })
        self.assertTrue(form.is_valid())

    def test_disposable_email_rejected(self):
        form = SignupForm(data={
            "email": "temp@disposable.mailbeam-test.dev",
            "password": "pass1234",
        })
        self.assertFalse(form.is_valid())
        self.assertIn("email", form.errors)

Buone pratiche

PraticaPerché
Centralizzare in verification.pyModuli, serializer e viste si comportano allo stesso modo
Lasciar passare davanti a mailbeam.APIErrorUn guasto non deve rompere le registrazioni
Normalizzare (strip().lower())Cache coerente e meno interrogazioni doppie
Mettere in cache ~24 hRiduce le chiamate all'API nei ritentativi e nei reinvii
Usare i domini di provaTest deterministici e senza consumo di quota

Lista di controllo per la produzione

  • MAILBEAM_KEY caricata dall'ambiente, non caricata nel repository
  • Registrazione degli errori configurata per mailbeam.APIError
  • Backend di cache definito (Redis o Memcached in produzione)
  • MAILBEAM_MIN_SCORE regolato sul tuo imbuto
  • Il messaggio di errore che vede l'utente è gentile nei tuoi modelli

Prossimi passi