mailcheck

API

API-Dokumentation

Eine Adresse rein, ein Urteil mit Gründen raus. Ohne Schlüssel nutzbar, keine Anmeldung, JSON in beiden Richtungen. Höhere Limits gibt es mit API-Schlüssel.

POST /api/v1/pruefen

Basis-URL: https://mailcheck.moersbergerit.de. Aktuelle Version ist v1; die älteren Pfade ohne /v1 (/api/pruefen, /api/stand) bleiben als Alias erhalten, werden aber nicht mehr dokumentiert. Der Endpunkt erwartet einen JSON-Body mit dem Feld email und liefert das Prüfergebnis.

Anfrage
{"email": "name@beispiel.de"}
Immer POST verwenden

Es gibt zusätzlich GET /api/v1/pruefen?email=… für schnelle Tests im Browser oder in der Shell. Dabei steht die Adresse in der URL und kann in Protokollen von Proxys oder Browsern landen. Nutzen Sie deshalb POST.

Beispielantwort
{
  "ergebnis": "wegwerf",
  "punkte": 98,
  "gruende": [
    {
      "code": "liste",
      "text": "Die Domain steht auf Listen bekannter Wegwerf-Anbieter.",
      "quellen": ["burner-email-providers", "disposable-email-domains", "fakefilter", "mailchecker"],
      "eintrag": "mailinator.com"
    }
  ],
  "domain": "mailinator.com",
  "empfehlung": "ablehnen",
  "vorschlag": null
}

Aufbau der Antwort

Felder
FeldTypBedeutung
ergebnisStringEines von ungueltig, wegwerf, verdaechtig, alias, frei, firma.
punkteGanzzahlRisikowert von 0 (unbedenklich) bis 100 (sicher unbrauchbar).
gruendeListeObjekte mit code (stabil, für Maschinen), text (Klartext, deutsch) und je nach Grund Zusatzfeldern.
domainStringDie Domain in technischer Schreibweise, klein geschrieben. Leer, wenn die Adresse syntaktisch ungültig ist.
empfehlungStringablehnen (ungültig, Wegwerf), bestaetigen_lassen (verdächtig) oder annehmen (alle übrigen).
vorschlagString oder nullKorrekturvorschlag bei einem wahrscheinlichen Tippfehler in der Domain, etwa gmail.com statt gmial.com. Ohne Vorschlag null (oder das Feld fehlt). Die Weboberfläche zeigt dann „Meinten Sie name@gmail.com?“ mit einem Knopf zum Übernehmen und erneuten Prüfen.
Werte von gruende[].code
CodeBedeutung
syntaxDie Adresse ist formal ungültig.
keine_domainHinter dem @ steht keine gültige Domain.
nxdomainDie Domain existiert nicht.
null_mxDie Domain nimmt ausdrücklich keine E-Mails an.
mx_lokalDer Mailserver der Domain zeigt auf eine interne Adresse (z. B. localhost), Mails können nicht zugestellt werden.
keine_mailDie Domain hat weder einen Mailserver (MX) noch eine Adresse.
positivlisteGroßer, bekannter E-Mail-Anbieter.
aliasWeiterleitungs-/Alias-Dienst: ein echtes Postfach dahinter.
listeDie Domain steht auf Listen bekannter Wegwerf-Anbieter. Zusatzfelder: quellen, eintrag.
liste_subdomainDie Domain gehört zu einem gelisteten Anbieter (Subdomain). Zusatzfelder: quellen, eintrag.
reserviertReservierte Domain wie example.com (RFC 2606, RFC 6761), sie nimmt nie Mails an.
liste_grosser_hosterDie Domain steht auf einer Liste, der Mailserver gehört aber zu einem großen Hoster (etwa Google Workspace oder Microsoft 365). Das spricht eher für einen Fehleintrag und führt zu „verdächtig“ mit der Empfehlung bestaetigen_lassen. Zusatzfelder: quellen, eintrag, mx_host.
liste_schwachDie Domain steht nur auf schwächeren Listen (mailchecker, groundcat), nicht auf den starken. Führt allein zu „verdächtig“, zusammen mit beiden schwachen Listen oder einem Wegwerf-Mailserver zu „wegwerf“. Zusatzfelder: quellen, eintrag.
mxDer Mailserver bedient überwiegend Wegwerf-Domains. Zusatzfeld: mx_host.
mx_schwachKein MX-Eintrag, nur ein Adress-Eintrag.
dns_fehlerZeitüberschreitung bei der DNS-Abfrage.
zufallDer Teil vor dem @ wirkt zufällig erzeugt.
domain_neuDie Domain ist erst wenige Wochen alt. Zusatzfeld: alter_tage.
tippfehlerDie Domain ähnelt einem großen Anbieter (etwa gmial.com). Zusatzfeld: vorschlag mit der korrigierten Adresse; dieselbe Adresse steht im Feld vorschlag der Antwort.
rolleDer Teil vor dem @ ist eine Funktionsadresse wie info@ oder admin@, kein persönliches Postfach.
eigene_domainEigene Domain mit funktionierendem Mailserver.

Der Grund rolle markiert Funktionsadressen und ist ein schwaches Signal; Sie können ihn etwa nutzen, um bei Registrierungen nach einer persönlichen Adresse zu fragen. Neue Felder und Codes können hinzukommen: Ignorieren Sie unbekannte Werte, statt zu scheitern.

Verlassen Sie sich für Programmlogik auf ergebnis, empfehlung und die code-Werte. Die Klartexte in text können sich ändern. Wie die Punkte zustande kommen, steht auf der Methodik-Seite.

POST /api/v1/pruefen/stapel

Prüft bis zu 10 Adressen in einer Anfrage. Jede Adresse zählt einzeln gegen das Limit. Gleiche Domains werden innerhalb einer Anfrage nur einmal abgefragt.

Anfrage
{"emails": ["name@beispiel.de", "x@mailinator.com"]}
Antwort (Status 200)
{
  "anzahl": 2,
  "geprueft": 2,
  "ergebnisse": [
    { "ergebnis": "frei", "punkte": 10, "gruende": [], "domain": "beispiel.de", "empfehlung": "annehmen", "vorschlag": null },
    { "ergebnis": "wegwerf", "punkte": 98, "gruende": [ { "code": "liste", "…": "…" } ], "domain": "mailinator.com", "empfehlung": "ablehnen", "vorschlag": null }
  ]
}

ergebnisse enthält genau einen Eintrag je Adresse in der Reihenfolge der Anfrage, aufgebaut wie die Einzelantwort. Die Adressen selbst kommen nicht zurück; ordnen Sie über die Position zu.

Wird das Limit mitten im Stapel erreicht, antwortet die API mit Status 207 (Multi-Status). Die bereits geprüften Adressen stehen mit ihrem Ergebnis in der Liste, alle übrigen als {"fehler": "limit", "text": "…"}. Zusätzlich nennt wiederholen_nach die Sekunden, bis wieder Platz im Limit ist. geprueft sagt, wie viele Einträge ein echtes Ergebnis haben. Ist das Limit schon vor der ersten Adresse erschöpft, gibt es 429 mit Retry-After und dem normalen Fehlerformat. Bei mehr als 10 Adressen antwortet die API mit 413 und prüft nichts.

Antwort bei Überschreitung (Status 207)
{
  "anzahl": 3,
  "geprueft": 1,
  "wiederholen_nach": 42,
  "ergebnisse": [
    { "ergebnis": "frei", "punkte": 0, "…": "…" },
    { "fehler": "limit", "text": "Zu viele Anfragen. Bitte später erneut versuchen." },
    { "fehler": "limit", "text": "Zu viele Anfragen. Bitte später erneut versuchen." }
  ]
}

Fehler

Statuscodes
StatusWannBody
200Prüfung durchgeführt. Auch ungültige Adressen liefern 200 mit ergebnis: "ungueltig".Ergebnis wie oben
207Nur Stapel: Limit mitten im Stapel erreicht, Teilergebnis.geprueft, ergebnisse, wiederholen_nach
400Der Body ist kein gültiges JSON, oder die Stapelliste ist leer.{"fehler": "kein_json", …}, leere_liste
413Mehr als 10 Adressen im Stapel oder Body über 64 KiB.zu_viele_adressen, anfrage_zu_gross
415Der Content-Type ist nicht application/json.falscher_inhaltstyp
422Das Feld email bzw. emails fehlt oder hat den falschen Typ.email_fehlt, emails_fehlt
429Limit überschritten. Der Header Retry-After nennt die Wartezeit in Sekunden.{"fehler": "limit", "text": "Zu viele Anfragen. Bitte später erneut versuchen."}
404, 405, 500Unbekannter Pfad, falsche Methode, interner Fehler.nicht_gefunden, methode_nicht_erlaubt, intern

Alle Fehler haben dieselbe Form: {"fehler": "<code>", "text": "<Klartext>"}. Verlassen Sie sich auf fehler, nicht auf text. Die Antworten tragen Cache-Control: no-store, die Fehlermeldung spiegelt die Eingabe nie zurück.

Limits und Header

Standardmäßig 10 Anfragen pro Minute und 500 Anfragen pro Tag je Client; im Stapel zählt jede Adresse einzeln. Als Client zählt die IP-Adresse, bei IPv6 das Netz (/64, zusätzlich ein größeres /48-Netz mit vierfachem Limit). Mit einem API-Schlüssel gelten höhere Limits ohne Tageslimit, siehe Pro und Business.

Jede Antwort enthält den Stand des engeren der beiden Fenster:

Header
HeaderBedeutung
X-RateLimit-LimitAnfragen, die das aktuell maßgebliche Fenster (Minute oder Tag) erlaubt.
X-RateLimit-RemainingNoch verfügbare Anfragen in diesem Fenster.
X-RateLimit-ResetUnix-Zeit in Sekunden, zu der das Fenster wieder Platz bietet.
Retry-AfterNur bei 429: Wartezeit in Sekunden.

CORS und Formular-Widget

Alle Pfade unter /api/v1/ sind aus dem Browser fremder Seiten aufrufbar: Access-Control-Allow-Origin: *, erlaubt sind nur GET, POST und OPTIONS sowie die Request-Header Content-Type, X-API-Key und Authorization. Cookies werden nicht verwendet. Die Preflight-Antwort (204) darf 24 Stunden zwischengespeichert werden (Access-Control-Max-Age: 86400). Die Rate-Limit-Header sind für Skripte lesbar. Das Beispiel unten prüft die Adresse beim Absenden eines Formulars: bei ablehnen wird das Absenden blockiert, bei bestaetigen_lassen erscheint nur ein Hinweis. Fällt der Dienst aus, sollte Ihr Formular trotzdem funktionieren.

Beachten Sie, dass das Limit je Besucher-IP gilt und die Adresse im Browser des Besuchers an mailcheck übertragen wird. Erwähnen Sie das in Ihrer Datenschutzerklärung.

POST /api/v1/domains/pruefen

Prüft Domains statt Adressen. Gedacht für Listen: Ihr Browser oder Server sammelt die Domains und schickt nur diese, nie die Adressen. Der Body enthält domains mit 1 bis 100 Einträgen. Doppelte werden zusammengefasst.

curl
curl -s -X POST https://mailcheck.moersbergerit.de/api/v1/domains/pruefen \
  -H "Content-Type: application/json" \
  -d '{"domains": ["gmail.com", "mailinator.com"]}'
Antwort (JSON, gekürzt)
{
  "anzahl": 2,
  "geprueft": 2,
  "ergebnisse": [
    {"domain": "gmail.com", "ergebnis": "frei", "punkte": 0, "empfehlung": "annehmen", "gruende": []},
    {"domain": "mailinator.com", "ergebnis": "wegwerf", "punkte": 95, "empfehlung": "ablehnen", "gruende": []}
  ]
}

anzahl ist die Zahl der Einträge in der Anfrage, geprueft die Zahl der Domains mit echtem Ergebnis. Die Ergebnisse stehen in Anfragereihenfolge. Es gelten dieselben Regeln wie bei der Adressprüfung, ohne Signale aus dem Teil vor dem @. Eine formal ungültige Domain kommt als ungueltig mit leerem domain zurück, ohne die Eingabe zu spiegeln, und zählt nicht gegen das Limit. Ohne Schlüssel gelten 300 Domains pro Minute und 3.000 pro Tag je Client, jede eindeutige Domain zählt eins. Bei erreichtem Limit antwortet die API wie beim Stapel mit 207 oder 429 samt Retry-After.

Domain-Gesundheit (SPF, DMARC)

Bei den Ergebnissen frei, firma, alias und verdaechtig kann die Einzelprüfung Angaben zur E-Mail-Einrichtung der Domain mitliefern. Senden Sie dazu "gesundheit": true im Body oder ?gesundheit=1 bei GET. Standardmäßig ist das Feld aus, damit die Antwort für bestehende Nutzer gleich bleibt.

Feld gesundheit
"gesundheit": {
  "mx":    {"status": "ok", "anzahl": 2},
  "spf":   {"status": "ok", "wert": "v=spf1 include:_spf.google.com ~all"},
  "dmarc": {"status": "nur_beobachten", "richtlinie": "none"},
  "hinweis": "https://www.moersbergerit.de/email-check/"
}
  • spf.status: ok, fehlt (kein SPF-Eintrag), mehrfach (mehr als ein SPF-Eintrag), zu_offen (+all oder ?all) oder kein_abschluss (der Eintrag endet ohne all-Mechanismus und ohne redirect). Die optionalen Felder redirect (Ziel einer redirect=-Angabe) und hinweis_subdomain (true) erscheinen nur, wenn sie zutreffen.
  • dmarc.status: ok, fehlt, nur_beobachten (Richtlinie none), teilweise (pct unter 100) oder mehrfach (mehr als ein DMARC-Eintrag). richtlinie nennt none, quarantine oder reject. anteil ist eine Zahl (der pct-Wert) und steht bei teilweise sowie bei pct=0 (dann mit Status nur_beobachten).
  • mx.status: ok, fehlt, nur_a (kein MX, nur ein Adress-Eintrag) oder ungueltig (der Mailserver zeigt auf ein unzustellbares Ziel). anzahl nennt die Zahl der Mailserver.
  • Werte sind auf 255 Zeichen gekürzt. Scheitert die DNS-Abfrage, fehlt das Feld ganz, statt falsche Werte zu melden.

API-Schlüssel

Mit einem Schlüssel gelten höhere Limits: je nach Stufe 60 (Pro) oder 300 (Business) Prüfungen pro Minute, kein Tageslimit, dafür ein Monatskontingent von 10.000 oder 100.000. Domain-Prüfungen zählen wie Adressen. Schlüssel gibt es auf Anfrage, siehe Pro und Business.

  • Senden Sie den Schlüssel im Header X-API-Key: mc_… oder als Authorization: Bearer mc_….
  • Als URL-Parameter wird er abgelehnt: Status 400, Code schluessel_in_url.
  • Ungültig oder gesperrt: 401 mit schluessel_ungueltig, ohne Hinweis auf den Grund.
  • Kontingent aufgebraucht: 429 mit kontingent_erschoepft, Retry-After nennt die Sekunden bis zum Monatsanfang.
  • Jede Antwort mit Schlüssel trägt X-Kontingent-Monat (Kontingent) und X-Kontingent-Rest (verbleibend).
  • Setzen Sie den Schlüssel möglichst nur serverseitig ein. Ein Schlüssel im Browser-Code, etwa per data-key im Formular-Widget, ist für jeden Besucher lesbar und damit öffentlich. Verwenden Sie dort nur einen eigens dafür ausgestellten Schlüssel, den wir bei Missbrauch sperren können, nie den Schlüssel Ihres Servers.

GET /api/v1/schluessel

Nur mit Schlüssel. Zeigt Stufe, Limits und den Verbrauch im laufenden Monat.

curl
curl -s https://mailcheck.moersbergerit.de/api/v1/schluessel \
  -H "X-API-Key: mc_IHR_SCHLUESSEL"
Antwort (JSON)
{
  "stufe": "pro",
  "praefix": "mc_ABCDE",
  "limit_minute": 60,
  "kontingent_monat": 10000,
  "verbraucht_monat": 1234
}

GET /api/v1/neu

Domains, die in den letzten Tagen neu auf den Sperrlisten aufgetaucht sind. Der Parameter tage (1 bis 90, Standard 7) wählt den Zeitraum. Höchstens 1.000 Einträge, neueste zuerst. Ohne Schlüssel erlaubt, die Abfrage zählt eins gegen das Limit. Dieselben Daten gibt es als Seite, RSS-Feed und Textdatei.

Antwort (JSON, gekürzt)
{
  "erfassung_seit": "2026-11-05",
  "tage": 7,
  "domains": [
    {"domain": "beispiel-wegwerf.example", "erstmals": "2026-11-09", "quellen": ["fakefilter"]}
  ]
}

erstmals ist der Tag, an dem mailcheck die Domain zum ersten Mal auf den Listen gesehen hat. erfassung_seit nennt den Beginn dieser Erfassung. Domains, die schon davor auf den Listen standen, erscheinen nicht als neu.

GET /api/v1/stand

Liefert den Stand der Sperrlisten, auch je Quelle.

Antwort
{
  "domains": 90947,
  "mx_hosts": 131,
  "letztes_update": "2026-11-05T13:19:01",
  "quellen": [
    {"name": "disposable-email-domains", "anzahl": 10142, "vertrauen": "stark"},
    {"name": "burner-email-providers", "anzahl": 27266, "vertrauen": "stark"},
    {"name": "fakefilter", "anzahl": 4808, "vertrauen": "stark"},
    {"name": "mailchecker", "anzahl": 57679, "vertrauen": "schwach"},
    {"name": "groundcat", "anzahl": 18511, "vertrauen": "schwach"}
  ]
}

domains ist die Zahl der gelisteten Domains, mx_hosts die Zahl der als Wegwerf gewerteten Mailserver, letztes_update der Zeitpunkt der letzten Listenaktualisierung (Serverzeit). quellen nennt je Liste die Zahl der Domains und das Vertrauen (stark oder schwach), siehe Starke und schwache Listen.

OpenAPI

Das maschinenlesbare Schema (OpenAPI 3, Version 1.0.0) liegt unter https://mailcheck.moersbergerit.de/api/v1/openapi.json. Sie können es in Postman, Insomnia oder einen Client-Generator laden.

Beispiele

curl
curl -s -X POST https://mailcheck.moersbergerit.de/api/v1/pruefen \
  -H "Content-Type: application/json" \
  -d '{"email": "name@beispiel.de"}'
curl (Stapel)
curl -s -X POST https://mailcheck.moersbergerit.de/api/v1/pruefen/stapel \
  -H "Content-Type: application/json" \
  -d '{"emails": ["name@beispiel.de", "x@mailinator.com"]}'
JavaScript (fetch, Browser, Node.js)
const antwort = await fetch("https://mailcheck.moersbergerit.de/api/v1/pruefen", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email: "name@beispiel.de" }),
});
if (antwort.status === 429) {
  const warten = antwort.headers.get("Retry-After"); // Sekunden
  throw new Error("Limit erreicht, erneut in " + warten + " s");
}
const { ergebnis, punkte, empfehlung } = await antwort.json();
if (empfehlung === "ablehnen") { /* Eingabe zurückweisen */ }
JavaScript (fetch, Stapel)
const r = await fetch("https://mailcheck.moersbergerit.de/api/v1/pruefen/stapel", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ emails: ["a@beispiel.de", "b@beispiel.de"] }),
});
const { ergebnisse } = await r.json();           // Status 200, 207 oder 429
ergebnisse.forEach((e, i) => {                   // gleiche Reihenfolge wie in der Anfrage
  if (e.fehler === "limit") return;              // später erneut senden
  console.log(i, e.ergebnis, e.empfehlung);
});
JavaScript: Formular-Widget auf Ihrer Seite
// Formular auf Ihrer Seite: Prüfung beim Absenden (CORS ist freigegeben).
const form = document.querySelector("#anmeldung");
form.addEventListener("submit", async (ev) => {
  ev.preventDefault();
  const feld = form.elements.email;
  let urteil = null;
  try {
    const r = await fetch("https://mailcheck.moersbergerit.de/api/v1/pruefen", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email: feld.value.trim() }),
    });
    if (r.ok) urteil = await r.json();
  } catch (e) { /* Dienst nicht erreichbar: nicht blockieren */ }

  if (urteil && urteil.empfehlung === "ablehnen") {
    feld.setCustomValidity("Bitte eine echte E-Mail-Adresse verwenden.");
    feld.reportValidity();
    return;                       // Absenden blockieren
  }
  feld.setCustomValidity("");
  if (urteil && urteil.empfehlung === "bestaetigen_lassen") {
    document.querySelector("#hinweis").textContent =
      "Bitte prüfen Sie die Adresse. Wir senden Ihnen eine Bestätigungs-Mail.";   // nur Hinweis
  }
  form.submit();
});
PHP (cURL)
<?php
$ch = curl_init("https://mailcheck.moersbergerit.de/api/v1/pruefen");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
    CURLOPT_POSTFIELDS => json_encode(["email" => "name@beispiel.de"]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($status === 200) {
    $daten = json_decode($body, true);
    if ($daten["empfehlung"] === "ablehnen") {
        // Eingabe zurückweisen
    }
}
Python (requests)
import requests

r = requests.post("https://mailcheck.moersbergerit.de/api/v1/pruefen",
                  json={"email": "name@beispiel.de"}, timeout=10)
r.raise_for_status()
daten = r.json()
if daten["empfehlung"] == "ablehnen":
    ...  # Eingabe zurückweisen

Datenschutz

Die Adresse wird nicht gespeichert und nicht protokolliert. Gezählt werden Tageszähler je Ergebnisart und bei Wegwerf- und Alias-Treffern die Domain. Wenn Sie Adressen Ihrer Nutzer weitergeben, benötigen Sie dafür Ihre eigene Rechtsgrundlage, siehe Datenschutzerklärung.

Fragen?