12k
All articles

E-Mail-Adressen verifizieren, ohne eine E-Mail zu senden

Erfahren Sie, wie die E-Mail-Verifizierung im Browser den Zugriff auf ein Postfach ohne Nachricht belegt – mit Formular, Node.js-Tokenprüfung in fünf Schritten und Testlimits.

OpenReplay Team
OpenReplay Team
E-Mail-Adressen verifizieren, ohne eine E-Mail zu senden

Mit dem Email Verification Protocol kann eine Website bestätigen, dass ein Nutzer eine E-Mail-Adresse kontrolliert, ohne eine E-Mail zu versenden: Der Browser erhält ein signiertes Token vom E-Mail-Anbieter des Nutzers und übermittelt es zusammen mit dem Formular.

Die meisten Registrierungsabläufe fordern Nutzer nach wie vor auf, „ihren Posteingang zu prüfen“, und ein Teil derjenigen, die den Tab wechseln, um den Code zu suchen, kehrt nie zurück. Chrome testet derzeit eine Alternative. Der am 8. Juli 2026 angekündigte Chrome Origin Trial startete mit Chrome 150, und Chrome hat anschließend ein Update vom August 2026 veröffentlicht. Das Protokoll selbst ist im IETF-Internet-Draft draft-hardt-email-verification spezifiziert.

Es handelt sich dabei nicht um SMTP- oder MX-basierte Listenbereinigung. Solche Tools prüfen, ob ein Postfach existiert. Dieses Protokoll weist dagegen nach, dass die Person, die das Formular ausfüllt, in diesem Postfach angemeldet ist. Die folgenden Abschnitte behandeln das Drei-Parteien-Modell, das Formular-Markup, einen vollständigen Node.js-Verifier in fünf Schritten und die Frage, wie weit Sie sich während der Testphase darauf verlassen können.

Das Wichtigste in Kürze

  • Das Email Verification Protocol liefert ein SD-JWT mit Key Binding zurück: ein vom Issuer signiertes Email Verification Token, gefolgt von einer Tilde und einem vom Browser signierten Key-Binding-JWT.
  • Der Browser steht zwischen Ihrer Website und dem E-Mail-Anbieter, sodass der Anbieter das Token ausstellt, ohne zu erfahren, welche Website es angefordert hat.
  • Ein gültiges Token belegt eine aktive Sitzung beim E-Mail-Anbieter für diese Adresse. Es belegt nicht, dass an diese Adresse gesendete E-Mails auch zugestellt werden.
  • Das Feature ist ein Vorschlag im Rahmen eines Chrome Origin Trials mit Traffic-Beschränkungen; Chromes Beiträge nennen kein Enddatum. In ihren Folien zur IETF 126 schätzten die Autoren des Drafts (nicht Chrome) eine Dauer von drei bis sechs Monaten. Chromes Dokumentation nennt ausschließlich Gmail als teilnehmenden Anbieter.
  • Wenn das versteckte Token-Feld leer ankommt oder ein Prüfschritt fehlschlägt, senden Sie Ihre übliche Bestätigungs-E-Mail.

Was ersetzt die browserbasierte E-Mail-Verifizierung?

Die browserbasierte E-Mail-Verifizierung ersetzt die E-Mail mit Einmalcode oder Magic Link, die Nutzer von Ihrer Website wegführt. Der IETF-Draft beschreibt, was der Code-Ablauf von Nutzern verlangt: zur Mail-App wechseln, auf die Zustellung warten, eventuell den Spam-Ordner durchsuchen, den Code kopieren, dann zurückkehren und ihn einfügen. Der Draft merkt an, dass viele Nutzer unterwegs abspringen. Ein Magic Link erspart zwar das Kopieren und Einfügen, doch der Nutzer muss trotzdem zum Posteingang wechseln und auf die Nachricht warten.

Social Login kommt ganz ohne E-Mail aus. Der Draft weist auf den Preis dafür hin: Der Nutzer muss ein Konto bei diesem Anbieter besitzen, und Sie müssen für jeden Anbieter eine eigene Integration entwickeln. Das Email Verification Protocol nutzt dasselbe Prinzip (der Anbieter bürgt für die Adresse), arbeitet aber über den Browser und benötigt auf Ihrer Website kein anbieterspezifisches SDK.

So funktioniert das Email Verification Protocol: drei Parteien

Am Email Verification Protocol sind drei Parteien beteiligt. Ihre Website ist der Verifier (die Relying Party). Der Browser steht zwischen Ihnen und dem Issuer, also dem Dienst, der das E-Mail-Konto des Nutzers betreibt. Da jeder Austausch über den Browser läuft, erfährt der Issuer nie, welche Website das Token angefordert hat.

Verifier (your site) <--> Browser <--> Issuer (e.g. accounts.google.com)
   nonce, validation      binds token      checks session,
                          to your origin   signs EVT

E-Mail-Anbieter und Issuer können unterschiedliche Hosts sein. In Chromes Beispiel ist der Anbieter gmail.com und der Issuer accounts.google.com.

Auf Issuer-Seite veröffentlicht die E-Mail-Domain einen DNS-TXT-Record, der an den Issuer delegiert. Der Issuer stellt unter /.well-known/email-verification Metadaten bereit, meldet dem Browser den Anmeldestatus über die Login Status API und prüft vor jeder Signatur die bestehenden First-Party-Session-Cookies des Nutzers (wie diese Cookies konfiguriert sein sollten, erfahren Sie unter Secure Cookies and HttpOnly). Der Draft erlaubt dem Browser außerdem, websitespezifische private Adressen anzufordern, die im EVT mit is_private_email: true gekennzeichnet werden. Die Trial-Dokumentation von Chrome beschreibt private Adressen nicht. Frühere Revisionen des Drafts erlaubten dem Issuer, auf eine WebAuthn-Challenge auszuweichen, wenn kein gültiges Cookie vorhanden war. Revision -02 hat diese Option jedoch gestrichen, sodass eine Anfrage ohne Sitzung jetzt schlicht fehlschlägt.

Die Website-Seite: Formular-Markup und Nonce

Auf Ihrer Seite benötigt das Formular zwei Eingabefelder: ein normales E-Mail-Feld mit autocomplete="email" und ein verstecktes Feld mit autocomplete="email-verification-token", das eine an die Sitzung des Nutzers gebundene Nonce trägt. Beim Absenden des Formulars befüllt der Browser das versteckte Feld mit dem Token. Dies ist das Markup aus Chromes Beitrag, wobei die Nonce vom Server gerendert wird:

<input
  name="email-address"
  type="email"
  autocomplete="email">
<input
  type="hidden"
  name="token"
  nonce="rAnD0m-VaLuE"
  autocomplete="email-verification-token">

Die Session-Binding-Regeln des Drafts verlangen eine zufällige Nonce mit mindestens 128 Bit Entropie. Erzeugen Sie für jede Verifizierungsanfrage eine neue Nonce und lassen Sie sie nach kurzer Zeit ablaufen. Speichern Sie den Renderzeitpunkt zusammen mit ihr, da Schritt 2 des Verifiers ihn benötigt:

import { randomBytes } from "node:crypto";

const nonce = randomBytes(32).toString("base64url"); // 256 bits
req.session.evp = { nonce, renderedAt: Date.now() };

Die Seite benötigt außerdem Ihr Origin-Trial-Token. Die Dokumentation zu Origin Trials von Chrome erklärt, wie Sie es einbinden. Laut dem August-Update werden Third-Party Origin Trials für dieses Feature nicht unterstützt.

Serverseitige Prüfung des Tokens

Die serverseitige Prüfung eines Email-Verification-Protocol-Tokens umfasst fünf Schritte: Parsen, Prüfen der erwarteten Werte, Prüfen des Key Bindings, Prüfen der DNS-Delegation und Verifizieren der Issuer-Signatur. Der Formularwert hat das Format <EVT>~<KB-JWT>. Das EVT ist das vom Issuer signierte Token und enthält email, email_verified, iss, iat sowie einen Browser-Schlüssel in cnf.jwk. Das KB-JWT ist vom Browser signiert und enthält aud, nonce, iat und sd_hash. Vertrauen Sie keinem dekodierten Claim, bevor nicht alle nachfolgenden Schritte erfolgreich waren. Der Code verwendet jose und Node-Bordmittel. Jeder Block läuft innerhalb eines try-Blocks in einer einzigen Funktion verifyEmailToken(), die false zurückgibt, sobald eine Exception auftritt.

Dies sind die Imports, die für die fünf Schritte benötigt werden:

import { createHash } from "node:crypto";
import { resolveTxt } from "node:dns/promises";
import {
  createRemoteJWKSet,
  decodeJwt,
  decodeProtectedHeader,
  importJWK,
  jwtVerify,
} from "jose";

1. Parsen. Teilen Sie den Wert an der Tilde auf und prüfen Sie die typ-Header.

const [evt, kb, ...rest] = token.split("~");
if (!evt || !kb || rest.length) return false;
const evtHeader = decodeProtectedHeader(evt);
const kbHeader = decodeProtectedHeader(kb);
if (evtHeader.typ !== "evt+jwt" || kbHeader.typ !== "kb+jwt") return false;
const evtClaims = decodeJwt(evt);
const kbClaims = decodeJwt(kb);

Aktuelle Tokens enthalten keine Selective Disclosures, sodass sich der Wert sauber in zwei Teile aufspalten lässt. Das August-Update bezeichnet diese Abkürzung als fragil, da sie nicht mehr funktionieren würde, sobald Disclosures hinzukommen. Chrome empfiehlt, das Token mit einer SD-JWT-Bibliothek wie @sd-jwt/core zu parsen, die inzwischen auch in Chromes eigener Demo zum Einsatz kommt.

2. Erwartete Werte. Chromes Validierungsschritte prüfen email_verified, email, nonce, aud sowie einen iat-Wert, der nach dem Rendern des Formulars liegt. Vergleichen Sie die E-Mail-Adresse ohne Berücksichtigung der Groß- und Kleinschreibung: Das August-Update warnt, dass Anbieter die Adresse möglicherweise in einer anderen Schreibweise zurückliefern, als der Nutzer sie eingegeben hat.

const { nonce, renderedAt } = req.session.evp ?? {};
delete req.session.evp; // single use
if (evtClaims.email_verified !== true) return false;
if (String(evtClaims.email).toLowerCase() !== submittedEmail.toLowerCase()) return false;
if (!nonce || kbClaims.nonce !== nonce) return false;
if (kbClaims.aud !== "https://example.com") return false;
if (kbClaims.iat < Math.floor(renderedAt / 1000)) return false;
// Any maximum age is your own policy; the sources define none.

3. Key Binding. sd_hash ist der SHA-256-Hash des EVT einschließlich der abschließenden ~. Zusätzlich muss das KB-JWT gegen den Schlüssel in cnf.jwk verifiziert werden.

const hash = createHash("sha256").update(evt + "~").digest("base64url");
if (hash !== kbClaims.sd_hash) return false;
const holderKey = await importJWK(evtClaims.cnf.jwk, kbHeader.alg);
await jwtVerify(kb, holderKey, { typ: "kb+jwt" });

4. DNS-Delegation. Fragen Sie _email-verification.<domain> ab. Der Draft verlangt genau einen TXT-Record, dessen Wert mit iss= beginnen muss. Mit dig +short TXT _email-verification.gmail.com können Sie eine Domain manuell prüfen.

const domain = submittedEmail.split("@").pop().toLowerCase();
const records = (await resolveTxt(`_email-verification.${domain}`))
  .map((chunks) => chunks.join(""));
if (records.length !== 1 || !records[0].startsWith("iss=")) return false;
const issuer = records[0].slice(4);

5. Discovery und EVT-Signatur. Rufen Sie die Issuer-Metadaten ab und verifizieren Sie anschließend das EVT gegen deren jwks_uri. Der Draft definiert den Issuer-Identifier als https:// gefolgt vom Host aus dem DNS-Record, und der iss-Claim des EVT muss exakt damit übereinstimmen.

const meta = await (await fetch(`https://${issuer}/.well-known/email-verification`)).json();
const jwks = createRemoteJWKSet(new URL(meta.jwks_uri));
const { payload } = await jwtVerify(evt, jwks, {
  algorithms: meta.signing_alg_values_supported,
  typ: "evt+jwt",
}); // written so it does not depend on a kid header
// The draft's issuer identifier is "https://" plus the DNS host, compared byte for byte.
if (payload.iss !== `https://${issuer}`) return false;
return true;
PrüfungArtefaktBei Fehlschlag
ParsenAufteilung an ~, typ-HeaderBestätigungs-E-Mail senden
Erwartete Werteemail_verified, email, nonce, aud, iatBestätigungs-E-Mail senden
Key Bindingsd_hash, KB-JWT-Signatur gegen cnf.jwkBestätigungs-E-Mail senden
DNSeinzelner TXT-Record mit iss=Bestätigungs-E-Mail senden
Issuer-SignaturMetadaten, jwks_uri, issBestätigungs-E-Mail senden

Das DNS-Modul von Node liefert jeden TXT-Record als Array von Chunks zurück, weshalb Schritt 4 diese zusammenfügt.

Wo liegen die Grenzen der browserbasierten E-Mail-Verifizierung?

Eine erfolgreiche Prüfung über das Email Verification Protocol zeigt, dass der Nutzer aktuell mit dieser Adresse bei seinem E-Mail-Anbieter angemeldet ist. Sie sagt nichts darüber aus, ob E-Mails, die Sie dorthin senden, auch ankommen. Sowohl Chrome als auch der Draft weisen ausdrücklich darauf hin – versenden Sie also weiterhin Willkommens-E-Mails.

Das Browserprofil, in dem der Nutzer das Formular ausfüllt, muss bereits eine angemeldete Sitzung beim Anbieter haben, und bei der ersten Verifizierung einer Adresse sieht der Nutzer einen Berechtigungsdialog – einmal pro Adresse. Im Juli-Release musste die Adresse aus dem Autofill stammen. Laut dem August-Update löst nun auch das Eintippen oder Einfügen der Adresse die Verifizierung aus, sobald das Feld den Fokus verliert. Der Draft weist außerdem auf ein kleines Datenschutzleck hin: Ob ein Token ankommt, verrät Ihrer Website, ob der Nutzer beim Issuer angemeldet ist.

Was Sie jetzt tun sollten

Das Email Verification Protocol ist noch nicht so weit, Ihre Bestätigungs-E-Mail zu ersetzen. Die Browser-API befindet sich in der Inkubation bei der WICG, und das Protokoll ist ein individueller Internet-Draft (Revision -02, August 2026). Chrome begrenzt den Traffic im Trial, damit Websites nicht vor dem offiziellen Launch auf das Feature aufbauen. Chromes Beiträge nennen kein Enddatum. Die Schätzung von drei bis sechs Monaten stammt von den Autoren des Drafts aus ihren Folien für IETF 126 DISPATCH, nicht von Chrome. Chrome warnt zudem vor nicht abwärtskompatiblen Änderungen, und laut dem August-Update ist das Feature bis Chrome 152 nur auf dem Desktop verfügbar, während die Unterstützung für Android noch geprüft wird. Chromes Dokumentation nennt ausschließlich Gmail als teilnehmenden Anbieter. Der Draft führt außerdem Hellō als implementierenden Issuer auf und erwähnt einen Origin Trial in Microsoft Edge.

Die Token-Ausstellung hat sich bereits einmal geändert. Der Juli-Beitrag beschrieb ein formularkodiertes request_token-JWT. Der Draft ersetzt dieses durch HTTP Message Signatures (RFC 9421) und kennzeichnet das alte Format als veraltet. Ab Chrome 153 sendet Chrome application/json mit den Headern Signature, Signature-Input und Signature-Key sowie einem Body, der nur die E-Mail-Adresse enthält. Dies ist eine Änderung auf Issuer-Seite; Ihr Verifier-Code ist davon nicht betroffen.

Behalten Sie Ihren OTP- oder Magic-Link-Ablauf als Standardpfad bei. Wenn Sie am Trial teilnehmen, behandeln Sie das Token als Progressive Enhancement: Lässt es sich erfolgreich verifizieren, überspringen Sie die E-Mail. Legen Sie nach der Verifizierung Ihre Sitzung wie gewohnt an (siehe Cookies vs localStorage for JWT Auth). Das EVT+KB ist ein einmaliger Nachweis und sollte nicht als Session-Token verwendet werden.

Das Protokoll ersetzt „Prüfen Sie Ihren Posteingang“ durch eine Signaturprüfung, die Sie auf Ihrem eigenen Server ausführen, und der Verifier kommt mit fünf Schritten aus. Fügen Sie das versteckte Eingabefeld und die Nonce hinzu, setzen Sie verifyEmailToken() vor Ihre bestehende Bestätigungs-E-Mail und lesen Sie vor jedem Chrome-Release den Update-Beitrag von Chrome auf Änderungen hin durch.

FAQs

Worin unterscheidet sich das Email Verification Protocol von Sign in with Google?

Sign in with Google ist eine anbieterspezifische Login-Integration, die eine Identitätsbeziehung zwischen Ihrer Website und Google herstellt. Das Email Verification Protocol bestätigt lediglich, dass der Nutzer eine E-Mail-Adresse kontrolliert. Es benötigt auf Ihrer Website kein Anbieter-SDK, und da der Browser den Austausch vermittelt, signiert der Issuer das Token, ohne zu erfahren, welche Website es angefordert hat.

Kann ich crypto.randomUUID() zum Erzeugen der Nonce verwenden?

Nein. Eine UUID der Version 4 enthält nur 122 Zufallsbits, da die Version- und Variant-Felder die übrigen 6 Bits belegen. Der IETF-Draft verlangt eine Nonce mit mindestens 128 Bit Entropie. Verwenden Sie stattdessen randomBytes(32).toString('base64url') aus node:crypto, was 256 Bit ergibt. Speichern Sie die Nonce in der Server-Session und löschen Sie sie nach einmaliger Verwendung.

Funktioniert das Email Verification Protocol auch für Adressen mit eigener Domain oder bei anderen Anbietern als Gmail?

Nur wenn die E-Mail-Domain genau einen _email-verification-TXT-Record veröffentlicht, der mit iss= beginnt und an einen Issuer delegiert, der das Protokoll unterstützt. Chromes Dokumentation nennt Gmail als teilnehmenden E-Mail-Anbieter. Für jede andere Domain ohne diesen Record kann der Browser kein Token beziehen; Ihr Verifier sollte dies daher als fehlgeschlagene Prüfung behandeln und die normale Bestätigungs-E-Mail senden.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.