EmailVerify LogoEmailVerify

Django

Email checker for Django. Python email verification in Django views and forms.

Integrieren Sie EmailVerify mit Django-Anwendungen mit Hilfe von benutzerdefinierten Validatoren, Formularfeldern und Middleware.

Installation

pip install emailverify

Konfiguration

Fügen Sie zu Ihren Django-Einstellungen hinzu:

# settings.py
EMAILVERIFY_API_KEY = os.environ.get('EMAILVERIFY_API_KEY')

# Optionale Einstellungen
EMAILVERIFY_TIMEOUT = 10  # seconds
EMAILVERIFY_BLOCK_DISPOSABLE = True
EMAILVERIFY_BLOCK_ROLE_BASED = False
EMAILVERIFY_CACHE_DURATION = 3600  # 1 hour

Benutzerdefinierter Validator

Erstellen Sie einen wiederverwendbaren E-Mail-Validator.

# validators.py
from django.core.exceptions import ValidationError
from django.conf import settings
from emailverify import Client
import logging

logger = logging.getLogger(__name__)

def validate_email_deliverable(email):
    """Überprüfen Sie, dass eine E-Mail-Adresse zustellbar ist."""
    client = Client(api_key=settings.EMAILVERIFY_API_KEY)

    try:
        result = client.verify(email)

        if result.status == 'invalid':
            raise ValidationError(
                'Bitte geben Sie eine gültige E-Mail-Adresse ein.',
                code='invalid_email'
            )

        if getattr(settings, 'EMAILVERIFY_BLOCK_DISPOSABLE', True):
            if result.result.disposable:
                raise ValidationError(
                    'Wegwerfmail-Adressen sind nicht zulässig.',
                    code='disposable_email'
                )

        if getattr(settings, 'EMAILVERIFY_BLOCK_ROLE_BASED', False):
            if result.result.role:
                raise ValidationError(
                    'Rollenbasierte E-Mail-Adressen sind nicht zulässig.',
                    code='role_email'
                )

    except Exception as e:
        # Fehler protokollieren, aber Einreichung nicht blockieren
        logger.warning(f'E-Mail-Verifikation für {email} fehlgeschlagen: {e}')


class EmailDeliverableValidator:
    """Klassenbasierter Validator mit anpassbaren Optionen."""

    def __init__(self, block_disposable=True, block_role_based=False):
        self.block_disposable = block_disposable
        self.block_role_based = block_role_based
        self.client = Client(api_key=settings.EMAILVERIFY_API_KEY)

    def __call__(self, email):
        try:
            result = self.client.verify(email)

            if result.status == 'invalid':
                raise ValidationError(
                    'Bitte geben Sie eine gültige E-Mail-Adresse ein.',
                    code='invalid_email'
                )

            if self.block_disposable and result.result.disposable:
                raise ValidationError(
                    'Wegwerfmail-Adressen sind nicht zulässig.',
                    code='disposable_email'
                )

            if self.block_role_based and result.result.role:
                raise ValidationError(
                    'Rollenbasierte E-Mail-Adressen sind nicht zulässig.',
                    code='role_email'
                )

        except ValidationError:
            raise
        except Exception as e:
            logger.warning(f'Email verification failed: {e}')

    def __eq__(self, other):
        return (
            isinstance(other, EmailDeliverableValidator) and
            self.block_disposable == other.block_disposable and
            self.block_role_based == other.block_role_based
        )

Modellfeld

Fügen Sie Verifikation zu Modellfeldern hinzu.

# models.py
from django.db import models
from .validators import validate_email_deliverable

class User(models.Model):
    email = models.EmailField(
        unique=True,
        validators=[validate_email_deliverable]
    )
    name = models.CharField(max_length=255)
    email_verification_status = models.CharField(
        max_length=20,
        blank=True,
        null=True
    )
    email_verification_score = models.FloatField(
        blank=True,
        null=True
    )
    email_verified_at = models.DateTimeField(
        blank=True,
        null=True
    )

    class Meta:
        db_table = 'users'

Formular-Integration

Basis-Formular

# forms.py
from django import forms
from django.core.validators import EmailValidator
from .validators import EmailDeliverableValidator

class RegistrationForm(forms.Form):
    name = forms.CharField(max_length=255)
    email = forms.EmailField(
        validators=[
            EmailValidator(),
            EmailDeliverableValidator(
                block_disposable=True,
                block_role_based=False
            )
        ]
    )
    password = forms.CharField(widget=forms.PasswordInput)
    password_confirm = forms.CharField(widget=forms.PasswordInput)

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password_confirm = cleaned_data.get('password_confirm')

        if password and password_confirm and password != password_confirm:
            raise forms.ValidationError('Passwörter stimmen nicht überein.')

        return cleaned_data

Modellformular

# forms.py
from django import forms
from .models import User
from .validators import validate_email_deliverable

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['name', 'email']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Validator zu E-Mail-Feld hinzufügen
        self.fields['email'].validators.append(validate_email_deliverable)

View-Integration

# views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.views import View
from emailverify import Client
from django.conf import settings
from .forms import RegistrationForm
from .models import User

class RegistrationView(View):
    template_name = 'registration/register.html'

    def get(self, request):
        form = RegistrationForm()
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = RegistrationForm(request.POST)

        if form.is_valid():
            # Zusätzliche Verifikation mit vollem Ergebnis
            client = Client(api_key=settings.EMAILVERIFY_API_KEY)
            email = form.cleaned_data['email']

            try:
                result = client.verify(email)

                # Benutzer mit Verifikationsdaten erstellen
                user = User.objects.create(
                    name=form.cleaned_data['name'],
                    email=email,
                    email_verification_status=result.status,
                    email_verification_score=result.score,
                )
                user.set_password(form.cleaned_data['password'])
                user.save()

                messages.success(request, 'Registrierung erfolgreich!')
                return redirect('login')

            except Exception as e:
                messages.error(request, 'Registrierung fehlgeschlagen. Bitte versuchen Sie es erneut.')

        return render(request, self.template_name, {'form': form})

Middleware

Überprüfen Sie E-Mails in eingehenden Anfragen.

# middleware.py
from django.http import JsonResponse
from django.conf import settings
from emailverify import Client
import logging
import json

logger = logging.getLogger(__name__)

class EmailVerificationMiddleware:
    """Middleware zur Verifikation von E-Mail-Adressen in POST-Anfragen."""

    def __init__(self, get_response):
        self.get_response = get_response
        self.client = Client(api_key=settings.EMAILVERIFY_API_KEY)
        self.protected_paths = getattr(
            settings,
            'EMAILVERIFY_PROTECTED_PATHS',
            ['/api/register/', '/api/subscribe/']
        )

    def __call__(self, request):
        if request.method == 'POST' and self._should_verify(request.path):
            email = self._extract_email(request)

            if email:
                try:
                    result = self.client.verify(email)

                    if result.status == 'invalid':
                        return JsonResponse(
                            {'error': 'Ungültige E-Mail-Adresse'},
                            status=400
                        )

                    # Verifikationsergebnis an Anfrage anhängen
                    request.email_verification = result

                except Exception as e:
                    logger.warning(f'Email verification failed: {e}')

        return self.get_response(request)

    def _should_verify(self, path):
        return any(path.startswith(p) for p in self.protected_paths)

    def _extract_email(self, request):
        # Versuchen Sie, den JSON-Body zu lesen
        if request.content_type == 'application/json':
            try:
                data = json.loads(request.body)
                return data.get('email')
            except json.JSONDecodeError:
                pass

        # Versuchen Sie, POST-Daten zu lesen
        return request.POST.get('email')

Middleware registrieren

# settings.py
MIDDLEWARE = [
    # ... other middleware
    'myapp.middleware.EmailVerificationMiddleware',
]

EMAILVERIFY_PROTECTED_PATHS = [
    '/api/register/',
    '/api/subscribe/',
    '/api/contact/',
]

Zwischenspeicherung

Zwischenspeicherung von Verifikationsergebnissen zur Reduzierung von API-Aufrufen.

# services.py
from django.core.cache import cache
from django.conf import settings
from emailverify import Client
import hashlib

class EmailVerificationService:
    def __init__(self):
        self.client = Client(api_key=settings.EMAILVERIFY_API_KEY)
        self.cache_duration = getattr(
            settings,
            'EMAILVERIFY_CACHE_DURATION',
            3600
        )

    def verify(self, email):
        cache_key = self._get_cache_key(email)
        cached = cache.get(cache_key)

        if cached:
            return cached

        result = self.client.verify(email)
        cache.set(cache_key, result, self.cache_duration)

        return result

    def is_valid(self, email):
        result = self.verify(email)
        return result.status == 'valid'

    def is_disposable(self, email):
        result = self.verify(email)
        return result.result.disposable

    def clear_cache(self, email):
        cache.delete(self._get_cache_key(email))

    def _get_cache_key(self, email):
        email_hash = hashlib.md5(email.lower().encode()).hexdigest()
        return f'email_verification:{email_hash}'


# Usage
verification_service = EmailVerificationService()

if verification_service.is_valid(email):
    # Gültige E-Mail verarbeiten
    pass

Django REST Framework

Serializer-Validierung

# serializers.py
from rest_framework import serializers
from django.conf import settings
from emailverify import Client

class RegistrationSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=255)
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    def validate_email(self, value):
        client = Client(api_key=settings.EMAILVERIFY_API_KEY)

        try:
            result = client.verify(value)

            if result.status == 'invalid':
                raise serializers.ValidationError(
                    'Bitte geben Sie eine gültige E-Mail-Adresse ein.'
                )

            if result.result.disposable:
                raise serializers.ValidationError(
                    'Wegwerfmail-Adressen sind nicht zulässig.'
                )

            # Ergebnis für späteren Gebrauch speichern
            self.context['email_verification'] = result

        except serializers.ValidationError:
            raise
        except Exception as e:
            # Log but don't block
            pass

        return value

Benutzerdefinierte Berechtigung

# permissions.py
from rest_framework.permissions import BasePermission
from django.conf import settings
from emailverify import Client

class ValidEmailPermission(BasePermission):
    """Nur Anfragen mit gültigen E-Mail-Adressen zulassen."""

    message = 'Eine gültige E-Mail-Adresse ist erforderlich.'

    def has_permission(self, request, view):
        email = request.data.get('email')

        if not email:
            return True  # Andere Validatoren kümmern sich um fehlende E-Mail

        client = Client(api_key=settings.EMAILVERIFY_API_KEY)

        try:
            result = client.verify(email)
            return result.status != 'invalid'
        except Exception:
            return True  # Auf API-Fehler zulassen

Management-Befehl

E-Mails von Benutzern in Massen überprüfen.

# management/commands/verify_emails.py
from django.core.management.base import BaseCommand
from django.conf import settings
from emailverify import Client
from myapp.models import User
import time

class Command(BaseCommand):
    help = 'Überprüfen Sie alle E-Mail-Adressen des Benutzers'

    def add_arguments(self, parser):
        parser.add_argument(
            '--batch-size',
            type=int,
            default=100,
            help='Anzahl der E-Mails pro Batch'
        )

    def handle(self, *args, **options):
        client = Client(api_key=settings.EMAILVERIFY_API_KEY)
        batch_size = options['batch_size']

        users = User.objects.filter(
            email_verification_status__isnull=True
        )

        total = users.count()
        self.stdout.write(f'Überprüfe {total} E-Mails...')

        # E-Mails für Massenverifikation sammeln
        emails = list(users.values_list('email', flat=True)[:10000])

        # Masse-Job einreichen
        job = client.verify_bulk(emails)
        self.stdout.write(f'Job-ID: {job.job_id}')

        # Auf Fertigstellung warten
        while True:
            status = client.get_bulk_job_status(job.job_id)
            self.stdout.write(
                f'Fortschritt: {status.progress_percent}%',
                ending='\r'
            )

            if status.status == 'completed':
                break

            time.sleep(5)

        self.stdout.write('')

        # Ergebnisse abrufen und verarbeiten
        results = client.get_bulk_job_results(job.job_id)

        for result in results.results:
            User.objects.filter(email=result.email).update(
                email_verification_status=result.status,
                email_verification_score=result.score,
            )

        self.stdout.write(self.style.SUCCESS('Verifikation abgeschlossen!'))

        # Zusammenfassung ausgeben
        summary = {}
        for result in results.results:
            summary[result.status] = summary.get(result.status, 0) + 1

        for status, count in summary.items():
            self.stdout.write(f'  {status}: {count}')

Signale

Reagieren Sie auf Modellereignisse.

# signals.py
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.conf import settings
from emailverify import Client
from .models import User
import logging

logger = logging.getLogger(__name__)

@receiver(pre_save, sender=User)
def verify_user_email(sender, instance, **kwargs):
    """Überprüfen Sie die E-Mail vor dem Speichern des Benutzers."""
    # Überspringen, wenn E-Mail nicht geändert hat
    if instance.pk:
        try:
            old_instance = User.objects.get(pk=instance.pk)
            if old_instance.email == instance.email:
                return
        except User.DoesNotExist:
            pass

    client = Client(api_key=settings.EMAILVERIFY_API_KEY)

    try:
        result = client.verify(instance.email)
        instance.email_verification_status = result.status
        instance.email_verification_score = result.score

    except Exception as e:
        logger.warning(f'E-Mail-Verifikation fehlgeschlagen: {e}')

Testen

# tests.py
from django.test import TestCase
from unittest.mock import patch, MagicMock
from .validators import validate_email_deliverable
from django.core.exceptions import ValidationError

class EmailValidationTest(TestCase):
    @patch('validators.Client')
    def test_valid_email_passes(self, mock_client):
        mock_result = MagicMock()
        mock_result.status = 'valid'
        mock_result.result.disposable = False
        mock_result.result.role = False

        mock_client.return_value.verify.return_value = mock_result

        # Sollte nicht auslösen
        validate_email_deliverable('valid@example.com')

    @patch('validators.Client')
    def test_invalid_email_fails(self, mock_client):
        mock_result = MagicMock()
        mock_result.status = 'invalid'

        mock_client.return_value.verify.return_value = mock_result

        with self.assertRaises(ValidationError):
            validate_email_deliverable('invalid@example.com')

    @patch('validators.Client')
    def test_disposable_email_blocked(self, mock_client):
        mock_result = MagicMock()
        mock_result.status = 'valid'
        mock_result.result.disposable = True

        mock_client.return_value.verify.return_value = mock_result

        with self.assertRaises(ValidationError):
            validate_email_deliverable('temp@mailinator.com')

Zugehörige Ressourcen

On this page