Skip to content
Starten Sie mit 100 kostenlosen Verifizierungs-Credits
Qualisend
Alle Artikel
Engineering / 8. Mai 2026

E-Mail-Adressen in ASP.NET Core validieren

8 minutes read

Qualisend team
Codefenster mit dem Titel Program.cs, das eine E-Mail in ASP.NET Core über drei sich verengende Schichten validiert — Syntax, MX, Postfach — bis hin zu einem grünen Zustellbarkeits-Badge.

Um eine E-Mail-Adresse in ASP.NET Core zu validieren, verlassen sich die meisten Anwendungen auf die eingebaute [EmailAddress]-DataAnnotation, lassen das Model Binding sie ausführen und prüfen ModelState.IsValid. Das ist ein solider erster Schritt — das Attribut wird mit dem Framework ausgeliefert und weist Unsinn ohne selbst gebaute Regex ab — aber es beantwortet nur die erste der drei Fragen, die echte Validierung stellt. Ist die Adresse korrekt geformt? Kann ihre Domain E-Mails empfangen? Existiert das Postfach tatsächlich? ASP.NET Core beantwortet die erste Frage von Haus aus, braucht für die zweite ein bekanntes NuGet-Paket und überlässt die dritte einem Netzwerkproblem, das man besser abgibt. Dieser Leitfaden baut die Prüfung als drei Schichten auf, die in die framework-eigene Validierungspipeline eingebunden sind, und zeigt genau, wo [EmailAddress] aufhört. Er ist das Web-Framework-Gegenstück zum Leitfaden zur E-Mail-Validierung in C#, der dieselben Grundbausteine außerhalb der Request-Pipeline behandelt.

Die kurze Antwort#

Verwenden Sie [EmailAddress] (oder FluentValidations .EmailAddress()) für die Syntax, DnsClient.NET für die MX-Abfrage und eine Verifizierungs-API für die SMTP-Postfachprüfung — das Günstigste zuerst, mit Kurzschluss, sobald eine Schicht ein eindeutiges Ergebnis liefert. Die DNS- und die API-Schicht sind asynchrone I/O, passen also nicht in ein synchrones ValidationAttribute; ihr idiomatischer Platz ist ein FluentValidation-Validator mit über DI injizierten Diensten. Öffnen Sie keine rohen SMTP-Sockets aus Ihrer Anwendung heraus, um Postfächer selbst abzutasten: Der ausgehende Port 25 ist auf den meisten Hosts blockiert, und die Antwort hängt von der Reputation der sendenden IP und vom Greylisting ab, das Sie nicht nachbauen wollen. Jede Schicht schließt Adressen günstiger aus als die vorige; nur die letzte kann eine Adresse einschließen. Falls die Pipeline neu für Sie ist, erklärt was E-Mail-Verifizierung ist zuerst die Begriffe.

Schicht 1: Formatvalidierung mit DataAnnotations#

Die eingebaute Prüfung für Schicht eins ist das [EmailAddress]-Attribut aus System.ComponentModel.DataAnnotations. Setzen Sie es an Ihrem Request-Modell neben [Required], und das Model Binding führt es bei jedem Bind aus:

using System.ComponentModel.DataAnnotations;

public class SignupRequest
{
    [Required]
    [EmailAddress]
    public string Email { get; init; } = string.Empty;
}

In einem MVC- oder API-Controller, der mit [ApiController] markiert ist, schließt ein fehlgeschlagenes Attribut vor dem Ausführen Ihres Action-Bodys mit einer 400-ValidationProblemDetails-Antwort kurz — Sie müssen ModelState nie von Hand prüfen:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("signup")]
public class SignupController : ControllerBase
{
    [HttpPost]
    public IActionResult Register(SignupRequest request)
    {
        // With [ApiController], an invalid [EmailAddress] already returned 400.
        // Reaching here means the string is well-formed.
        return Ok();
    }
}

Machen Sie sich genau klar, was Ihnen das bringt. EmailAddressAttribute prüft die Form — tatsächlich verlangt es nur ein einzelnes @ mit etwas auf beiden Seiten — und nicht mehr. Es löst niemals DNS auf, öffnet nie einen Socket und hat keine Ahnung, ob die Domain existiert. definitely-fake@gmail.com besteht. info@company-that-folded.com besteht. typo@gmial.com besteht. Alle drei sind unzustellbar, und kein Attribut, das nur den String liest, wird Ihnen das je verraten — aus demselben Grund, aus dem Regex-basierte E-Mail-Validierung scheitert: Form und Zustellbarkeit sind unterschiedliche Fragen, die eine eine Tatsache über den String, die andere eine Tatsache über das Internet.

Warum die nächsten beiden Schichten keine Attribute sein können#

Hier ist der Haken, der den Rest dieses Leitfadens prägt: Die DataAnnotations-Validierung ist synchron. ValidationAttribute.IsValid gibt ein ValidationResult zurück, kein Task, es gibt also keinen sauberen Weg, eine DNS-Abfrage oder einen HTTP-Aufruf darin zu await-en. Mit .Result oder .GetAwaiter().GetResult() zu blockieren, um einen asynchronen Aufruf in ein synchrones Attribut zu zwingen, lädt unter Last zu Thread-Pool-Aushungerung und Deadlocks ein — genau das, was Sie auf einem Anmeldepfad nicht wollen.

Deshalb lautet die idiomatische ASP.NET-Core-Antwort für die asynchronen Schichten FluentValidation: Seine MustAsync-Regeln sind vollwertige, Task-zurückgebende Validatoren, und es löst Abhängigkeiten über denselben DI-Container auf wie der Rest Ihrer Anwendung, sodass ein Validator einen HttpClient oder einen DNS-Dienst in seinem Konstruktor entgegennehmen kann. Sie können [EmailAddress] für Schicht eins beibehalten und FluentValidation für Schicht zwei und drei hinzufügen — oder, wie unten, FluentValidations eigenes .EmailAddress() auch die Syntax abdecken lassen und alle drei Schichten an einem Ort halten.

Schicht 2: Kann die Domain E-Mails empfangen?#

Eine Domain ohne Mail-Route kann für niemanden E-Mails annehmen, also eliminiert eine einzige Abfrage tote Domains, falsch geschriebene Firmennamen und erfundene TLDs. Der Haken: ASP.NET Core hat keinen eingebauten MX-Resolver. System.Net.Dns löst A- und AAAA-Einträge auf, aber kein MX, daher ist der Standardansatz DnsClient.NET — ein weit verbreitetes NuGet-Paket. Kapseln Sie es hinter einer kleinen Schnittstelle, damit der Validator von einer Abstraktion abhängt und nicht von der Bibliothek:

using DnsClient; // dotnet add package DnsClient
using System.Linq;

public interface IMailRouteChecker
{
    Task<bool> HasMailRouteAsync(string email, CancellationToken ct = default);
}

public sealed class DnsMailRouteChecker : IMailRouteChecker
{
    private readonly ILookupClient _dns;

    public DnsMailRouteChecker(ILookupClient dns) => _dns = dns;

    public async Task<bool> HasMailRouteAsync(string email, CancellationToken ct = default)
    {
        var domain = email[(email.LastIndexOf('@') + 1)..];
        try
        {
            var response = await _dns.QueryAsync(domain, QueryType.MX, cancellationToken: ct);
            return response.Answers.MxRecords().Any();
        }
        catch (DnsResponseException)
        {
            // No reachable resolver, SERVFAIL, and similar — treat as "check later".
            return false;
        }
    }
}

Trennen Sie die Domain am letzten @ mit einem Bereichsausdruck ab, damit Sie eine Adresse, die legal mehr als ein @ enthält, nie falsch parsen. Registrieren Sie einen einzigen LookupClient als Singleton — er ist thread-sicher und cacht Antworten, sodass eine Instanz pro Request diesen Cache einfach wegwirft. Manche Domains nehmen E-Mails über einen A-Eintrag ohne MX an; wenn Sie diesen Sonderfall berücksichtigen wollen, fallen Sie auf QueryType.A zurück, wenn die MX-Menge leer ist.

Schicht 3: Existiert das Postfach tatsächlich?#

Die Schichten eins und zwei können eine Adresse nur ausschließen. Eine Domain kann perfekte MX-Einträge veröffentlichen und trotzdem kein Postfach an der Adresse haben, die Sie in Händen halten — noreply-9f2x@gmail.com ist gültige Syntax auf einer aktiven Mail-Route und dennoch ein Postfach, das nie angelegt wurde. Ein bestimmtes Postfach zu bestätigen bedeutet die SMTP-Zustellkonversation: sich mit dem Mail-Host verbinden, RCPT TO absetzen, die Antwort lesen und die Verbindung trennen, bevor irgendetwas gesendet wird. Wie E-Mail-Verifizierung funktioniert durchläuft diese vollständige Pipeline, samt Catch-all-Domains.

Im Prinzip können Sie das in C# mit einem TcpClient und rohen SMTP-Befehlen skripten. In der Praxis sollten Sie es nicht von Ihrem Anwendungsserver aus ausführen: Die meisten Cloud-Anbieter blockieren den ausgehenden Port 25, die Antwort hängt von der Reputation der IP ab, von der aus Sie sich verbinden, und empfangende Server betreiben Greylisting und Rate-Limiting bei unbekannten Absendern. Dies ist die Schicht, die es sich lohnt an eine dafür gebaute Infrastruktur zu delegieren.

Der Verify-Endpoint von Qualisend führt die gesamte Pipeline von reputationsverwalteter Infrastruktur aus und liefert in Echtzeit ein Urteil. Modellieren Sie ihn als typisierten HttpClient, damit Basis-URL, Timeout und Schlüssel an einem Ort liegen, und deserialisieren Sie den Antwort-Envelope mit System.Text.Json:

using System.Net.Http.Json;
using System.Text.Json.Serialization;

public interface IEmailVerifier
{
    Task<bool> IsDeliverableAsync(string email, CancellationToken ct = default);
}

public sealed class QualisendVerifier : IEmailVerifier
{
    private readonly HttpClient _http;

    public QualisendVerifier(HttpClient http) => _http = http;

    public async Task<bool> IsDeliverableAsync(string email, CancellationToken ct = default)
    {
        using var response = await _http.PostAsJsonAsync("verify", new { email }, ct);

        // On our own outage or a rate limit, don't block a real signup.
        if (!response.IsSuccessStatusCode)
            return true;

        var body = await response.Content.ReadFromJsonAsync<VerifyResponse>(ct);
        return body?.Result.Status != "undeliverable";
    }
}

public record VerifyResponse(
    [property: JsonPropertyName("result")] VerifyResult Result);

public record VerifyResult(
    [property: JsonPropertyName("status")] string Status,
    [property: JsonPropertyName("score")] int Score,
    [property: JsonPropertyName("reason")] string? Reason,
    [property: JsonPropertyName("sub_flags")] IReadOnlyDictionary<string, bool> SubFlags);

Die Antwort kommt in einem result-Envelope zurück:

{
  "result": {
    "status": "deliverable",
    "score": 95,
    "reason": null,
    "sub_flags": { "role": false, "disposable": false, "free": false, "catch_all": false }
  }
}

status ist Ihr entscheidendes Urteil — deliverable, risky, undeliverable oder unknown. Der Helfer oben lässt nur undeliverable hart scheitern und alles andere durch, aber score, reason und sub_flags (Rolle, Wegwerf, kostenlos, Catch-all) sind da, damit Sie Ihre eigene Richtlinie anwenden können — risky zur Prüfung zurückhalten, disposable bei der Anmeldung markieren. POST https://api.qualisend.com/v1/verify ist eine Platzhalterform; sehen Sie in der API-Referenz unter /developers nach dem genauen Endpoint, dem Format der Scoped Keys und jedem Feld. Erfinden Sie keine Felder aus dem obigen Beispiel — lesen Sie sie aus der Dokumentation.

Die Schichten zusammensetzen, um eine E-Mail-Adresse in ASP.NET Core zu validieren#

Setzen Sie nun alle drei in einem FluentValidation-Validator zusammen. Verketten Sie die Regeln, das Günstigste zuerst, und setzen Sie CascadeMode.Stop, damit er bei der ersten fehlschlagenden Schicht abbricht — die asynchronen DNS- und API-Regeln laufen nur bei Adressen, die die Syntax bereits bestanden haben:

using FluentValidation;

public class SignupRequestValidator : AbstractValidator<SignupRequest>
{
    public SignupRequestValidator(IMailRouteChecker dns, IEmailVerifier verifier)
    {
        RuleFor(x => x.Email)
            .Cascade(CascadeMode.Stop)   // bail at the first failing layer
            .NotEmpty()
            .EmailAddress()              // layer 1: syntax
            .MustAsync((email, ct) => dns.HasMailRouteAsync(email, ct))
                .WithMessage("Enter an email on a domain that can receive mail.")
            .MustAsync((email, ct) => verifier.IsDeliverableAsync(email, ct))
                .WithMessage("We couldn't confirm a mailbox at this address.");
    }
}

Verdrahten Sie die Dienste in Program.cs — den LookupClient als Singleton, den Verifier als typisierten Client mit dem aus der Konfiguration gelesenen Schlüssel (eine Umgebungsvariable oder User-Secrets in der Produktion, niemals hart codiert) und den Validator per Assembly-Scan:

using DnsClient;
using FluentValidation;
using System.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<ILookupClient>(new LookupClient());
builder.Services.AddScoped<IMailRouteChecker, DnsMailRouteChecker>();

builder.Services.AddHttpClient<IEmailVerifier, QualisendVerifier>(client =>
{
    client.BaseAddress = new Uri("https://api.qualisend.com/v1/");
    client.Timeout = TimeSpan.FromSeconds(10);
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
        "Bearer", builder.Configuration["Qualisend:ApiKey"]);
});

builder.Services.AddValidatorsFromAssemblyContaining<SignupRequestValidator>();

var app = builder.Build();

app.MapPost("/signup", async (
    SignupRequest request,
    IValidator<SignupRequest> validator,
    CancellationToken ct) =>
{
    var result = await validator.ValidateAsync(request, ct);
    if (!result.IsValid)
        return Results.ValidationProblem(result.ToDictionary());

    // Every layer passed — safe to persist.
    return Results.Ok();
});

app.Run();

IValidator<SignupRequest> zu injizieren und ValidateAsync im Endpoint aufzurufen ist das aktuell empfohlene Muster — es führt die asynchronen Regeln korrekt aus, was die alte automatische MVC-Integration nie tat. Derselbe Validator lässt sich unverändert in einen MVC-Controller einsetzen; lösen Sie ihn aus dem Konstruktor auf und rufen Sie ValidateAsync auf, bevor Sie die Datenbank berühren.

Genau diese Reihenfolge ist der ganze Trick: Die Syntaxregel schließt Müll gratis kurz, die lokale DNS-Prüfung schließt tote Domains für nichts aus, und die API wird nur für Adressen aufgerufen, die beides bestanden haben. Es ist dieselbe Dreischichten-Form wie in den Leitfäden für Node.js und C# — die Schichtung, nicht das Framework, macht die Validierung zuverlässig. Lassen Sie diese schnelle Pipeline bei der Anmeldung synchron laufen und behalten Sie die tiefere, im Batch durchgeführte Verifizierung für das Bereinigen einer bestehenden Liste vor, wo Latenz keine Rolle spielt und Gründlichkeit schon.

Häufig gestellte Fragen#

Reicht das EmailAddress-Attribut aus, um eine E-Mail in ASP.NET Core zu validieren?#

Für die Syntax ja — es ist die richtige Prüfung für Schicht eins und die bessere Wahl als eine selbst gebaute Regex. Aber EmailAddressAttribute validiert die Form (im Grunde nur ein einzelnes @ mit Text auf beiden Seiten); es löst niemals DNS auf und kontaktiert keinen Mailserver. Ein erfolgreiches ModelState.IsValid bedeutet also "sieht aus wie eine E-Mail", nicht "wird zugestellt". Kombinieren Sie es mit einer MX-Abfrage und einer SMTP-Postfachprüfung, bevor Sie der Adresse vertrauen.

Wie führe ich in ASP.NET Core eine asynchrone E-Mail-Validierung durch?#

DataAnnotations-Attribute sind synchron, daher gehört eine DNS-Abfrage oder ein API-Aufruf nicht hinein — den asynchronen Aufruf zu blockieren birgt die Gefahr von Deadlocks. Verwenden Sie stattdessen FluentValidation: Schreiben Sie MustAsync-Regeln, injizieren Sie Ihre DNS- und Verifizierungsdienste in den Validator und rufen Sie await validator.ValidateAsync(request) aus Ihrem Endpoint oder Controller auf. Das ist der aktuell empfohlene Ansatz, denn die alte automatische MVC-Integration hat asynchrone Validatoren nie ausgeführt.

Bietet ASP.NET Core eine eingebaute Möglichkeit, MX-Einträge nachzuschlagen?#

Nein. System.Net.Dns löst A- und AAAA-Host-Einträge auf, unterstützt aber kein MX, weshalb der Standardansatz das NuGet-Paket DnsClient.NET ist. Fragen Sie QueryType.MX ab, registrieren Sie einen LookupClient als Singleton und behandeln Sie eine leere Antwortmenge — oder eine DnsResponseException — als "keine Mail-Route", anstatt sie eine Exception werfen zu lassen.

Sollte ich E-Mails bei der Anmeldung oder beim Bereinigen einer Liste validieren?#

Beides, in unterschiedlicher Tiefe. Führen Sie Syntax und MX-Abfrage bei der Anmeldung synchron aus — sie sind schnell genug, um den Request zu blockieren und sofortiges Feedback zu geben — und handeln Sie auch dort nach dem unmittelbaren API-Urteil; der Leitfaden zur Serverless-Anmeldung zeigt das Muster von Anfang bis Ende. Behalten Sie die tiefere, im Batch durchgeführte Verifizierung für das Bereinigen einer bestehenden Liste vor, wo Latenz keine Rolle spielt.


Bereit, die SMTP-Schicht hinzuzufügen? Die API-Referenz enthält die genaue /verify-Form, Scoped Keys und Copy-and-paste-Beispiele, oder werfen Sie eine einzelne Adresse in den kostenlosen E-Mail-Checker, um zuzusehen, wie ein von [EmailAddress] gebilligter String als undeliverable zurückkommt.

Your reputation, protected.

Clean your first list in minutes. 100 free credits, no card required.

Get started