Newsletter-Anmeldeformular

Newsletter-Anmeldeformular6 Min. Lesezeit

Double-Opt-in für ein selbst gebautes Newsletter-Formular

Ikiform sendet keine Bestätigungs-E-Mails, also läuft Double-Opt-in in deinem E-Mail-Tool: Ein Relay legt jede Anmeldung als unbestätigt an, und das Tool sendet den Link.

Preet SutharGründer, Ikiform

Ikiform schreibt der Person, die sich anmeldet, nie eine E-Mail, also muss die Bestätigungs-E-Mail aus dem Tool kommen, das deinen Newsletter versendet. Ein Relay empfängt den signierten Webhook von Ikiform und legt den Leser in diesem Tool als unbestätigt an, das Tool schickt ihm einen Link, und erst ein Klick macht ihn zum Abonnenten. Jedes Tool schaltet das anders ein, und das Relay sollte nie eine zweite Bestätigung an jemanden senden, der bereits abonniert hat.

Was hier anders ist

Ikiform schreibt der Person, die das Formular ausfüllt, keine E-Mail. Benachrichtigungs-E-Mails gehen nur an dich und dein Team, es gibt also keinen Autoresponder, keine Bestätigungs-E-Mail und kein Double-Opt-in. Sende diese aus deinem E-Mail-Tool, ausgelöst durch einen Webhook. Beim Embed eines Anbieters ist die Bestätigung eine Einstellung am Formular des Anbieters. Mit deinem eigenen Formular sind zwei Systeme beteiligt, und die Bestätigung gehört zu dem, das die Liste führt. Die Arbeit besteht darin, sicherzustellen, dass jede Anmeldung dieses Tool in einem Zustand erreicht, der seine Bestätigung auslöst, und keine auslöst, wenn sie nicht sollte.

Double-Opt-in ist ein Zustandsautomat im E-Mail-Tool. Der Leser startet unbestätigt, darf keine Ausgaben bekommen und wird erst durch seinen Klick zum Abonnenten. Der Teil von Ikiform endet, wenn das Relay 204 antwortet.

Der Weg einer Double-Opt-in-Anmeldung vom Formular zum bestätigten AbonnentenFormularEinwilligungangehaktIkiformspeichert,signiertWebhookRelaylegtunbestätigtanE-Mail-Toolsendet denLinkbestätigtbekommt jedeAusgabekein Klickbleibtunbestätigt,keineAusgabenPostWebhookAPIKlickDer Weg einer Double-Opt-in-Anmeldung vom Formular zum bestätigten AbonnentenFormularEinwilligung angehaktIkiformspeichert, signiertWebhookRelaylegt unbestätigt anE-Mail-Toolsendet den Linkbestätigtbekommt jedeAusgabekeinKlickbleibtunbestätigt,keineAusgabenPostWebhookAPIKlick
  1. Der Leser hakt die Einwilligungs-Box an und sendet dein Formular ab, das an Ikiform sendet.
  2. Ikiform speichert die Anmeldung und sendet einen signierten Webhook an dein Relay.
  3. Das Relay prüft die Signatur und legt den Leser im E-Mail-Tool als unbestätigt an.
  4. Das E-Mail-Tool schickt dem Leser einen Bestätigungslink.
  5. Klickt er, markiert das Tool ihn als bestätigt und schickt ihm jede Ausgabe.
  6. Klickt er nie, bleibt er unbestätigt und bekommt keinen Newsletter.
Alles nach dem Relay passiert im E-Mail-Tool, auch der Wortlaut der Bestätigungs-E-Mail, die Seite, die der Link öffnet, und Erinnerungen.

Der Schalter in jedem Tool

Jedes Tool hat seine eigene Vorstellung von unbestätigt und seinen eigenen Weg, einen neuen API-Abonnenten in diesen Zustand zu bringen. Machst du das falsch, werden Abonnenten als bereits bestätigt angelegt, ganz ohne E-Mail:

ToolWie eine API-Anmeldung eine Bestätigungs-E-Mail bekommtDie Falle
KitLeg den Abonnenten mit state: "inactive" an und füge ihn dann einem Formular hinzu, dessen Incentive-E-Mail aktiviert ist. Laut Kits Doku zu Bulk-Formularen sendet das die Incentive-E-Mail; teste den Einzel-Endpunkt mit einer Adresse, die dir gehörtCreate subscriber setzt standardmäßig state: "active", und der Zustand lässt sich über diesen Endpunkt danach nicht mehr ändern
MailerLiteAktiviere in den Abo-Einstellungen Double opt-in for API and integrations. Sende zusätzlich status: "unconfirmed", das MailerLite braucht, bevor es einem bestehenden Abonnenten eine E-Mail schicktunconfirmed für eine bereits aktive Adresse zu senden, bittet sie erneut um Bestätigung
beehiivSende double_opt_override: "on" beim Anlegen des Abos oder "not_set", um die Einstellung der Publikation zu nutzen"off" macht den Abonnenten sofort aktiv, ohne E-Mail

Teste jede Variante mit einer Adresse, die dir gehört, bevor du dich darauf verlässt. Tool-Einstellungen ändern sich, und die E-Mail selbst wird im Tool eingerichtet: ihr Betreff, ihr Text und die Seite, die der Link öffnet.

Ein Relay, das nur einmal bestätigen lässt

Ein einfaches Relay fordert bei jedem eintreffenden Webhook eine Bestätigung an. Zwei Fälle machen das falsch: Ein Leser, der dreimal in einer Minute absendet, bekommt drei E-Mails, und ein Bot, der die Adresse eines Opfers anmeldet, landet mit jedem Versuch mit deiner Bestätigung im Posteingang dieses Opfers. Dieser Cloudflare Worker fordert beim Tool höchstens eine Bestätigung pro Adresse und Tag an:

src/index.ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { addUnconfirmed } from "./tool";

export interface Env {
  IKIFORM_WEBHOOK_SECRET: string;
  TOOL_API_KEY: string;
  SEEN: KVNamespace;
}

const DAY = 86_400;

async function digest(text: string) {
  const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
  return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}

export default {
  async fetch(request: Request, env: Env) {
    if (request.method !== "POST") return new Response(null, { status: 405 });
    const payload = await request.text();
    let event;
    try {
      event = await verifyWebhook({ payload, headers: request.headers, secret: env.IKIFORM_WEBHOOK_SECRET });
    } catch (error) {
      if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
      throw error;
    }
    if (event.type !== "submission.created" || event.data.fields.consent !== true) {
      return new Response(null, { status: 204 });
    }

    const email = String(event.data.fields.email).trim().toLowerCase();
    const key = `confirm:${await digest(email)}`;
    if (await env.SEEN.get(key)) return new Response("Confirmation already requested today", { status: 200 });

    const answer = await addUnconfirmed(env, email, event.data.fields.first_name);
    if (answer.status === 429) {
      return new Response("Rate limited", { status: 503, headers: { "retry-after": answer.headers.get("retry-after") ?? "60" } });
    }
    if (!answer.ok) return new Response(`Email tool answered ${answer.status}`, { status: 502 });

    await env.SEEN.put(key, event.id, { expirationTtl: DAY });
    return new Response(null, { status: 204 });
  },
};
wrangler.jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "newsletter-relay",
  "main": "src/index.ts",
  "compatibility_date": "2026-10-01",
  "routes": [{ "pattern": "hooks.example.com", "custom_domain": true }],
  "kv_namespaces": [{ "binding": "SEEN", "id": "<your KV namespace id>" }]
}
  • addUnconfirmed in ./tool ist der Aufruf des Tools aus der Tabelle oben. Kopiere seinen Body von der Seite zu Kit, MailerLite oder beehiiv.
  • Der KV-Key ist ein SHA-256 der kleingeschriebenen Adresse, sodass der Store nie die Adresse selbst enthält. Er läuft nach einem Tag ab.
  • Der Key wird erst geschrieben, nachdem das Tool den Request angenommen hat. Scheitert das Tool, versucht Ikiform es erneut, und die Wiederholung wird nicht blockiert.
  • Mit 200 auf eine Wiederholung zu antworten, sagt Ikiform, dass die Zustellung geklappt hat, sodass sie nicht wiederholt wird, und der Body erklärt im Zustellungsprotokoll, warum.
  • Der Worker läuft auf einer eigenen Domain. Ikiform lehnt workers.dev-Hostnamen als Webhook-URLs ab. Die Webhook-Doku listet jede URL-Regel und die Bedeutung jeder Antwort, und dein eigener Server zeigt ein Relay, das jede Zustellung einmal speichert.
KV ist über Standorte hinweg nur eventual consistent, also können zwei Zustellungen für dieselbe Adresse innerhalb weniger Sekunden beide durchkommen. Für eine Bestätigungs-E-Mail ist das akzeptabel. Brauchst du eine strikte Garantie, halte den Key in einem Durable Object oder einer Datenbank mit eindeutiger Spalte.

Was das Formular sagen sollte

Ein Leser, der „Danke fürs Abonnieren“ sieht und dann nichts in seinem Newsletter-Ordner findet, denkt, es sei fehlgeschlagen. Sag ihm auf der Seite, auf der er landet, was als Nächstes passiert:

  1. Lass die Erfolgszeile oder deine Dankeseite sagen, dass eine E-Mail zu öffnen ist: „Fast geschafft. Öffne die E-Mail, die wir dir geschickt haben, und bestätige deine Adresse.“
  2. Nenne den Absender, nach dem sie suchen sollen, und schlag den Spam-Ordner vor, falls nach ein paar Minuten nichts ankommt.
  3. Stell im E-Mail-Tool die Seite, die der Bestätigungslink öffnet, auf deine eigene Seite „Du bist angemeldet“ ein, damit der Weg auf deiner Site endet.

Die Einwilligungs-Checkbox des Formulars und die Bestätigungs-E-Mail erfüllen unterschiedliche Aufgaben. Die Checkbox hält fest, dass jemand auf deiner Seite Ja gesagt hat. Der Klick beweist, dass die Adresse der Person gehört, die Ja gesagt hat. Die meisten Listen wollen beides. Die Vorlage für Newsletter-Formulare hat die Pflicht-Checkbox.

Stolperfallen

  • Bestehende Abonnenten. Jemand, der schon bestätigt hat, meldet sich auf einer neuen Seite erneut an. Setz ihn nicht zurück auf unbestätigt; die MailerLite-Seite zeigt ein Relay, das die Adresse zuerst nachschlägt.
  • Leute, die sich abgemeldet haben. Eine Anmeldung ist nicht immer die Erlaubnis, eine Abmeldung rückgängig zu machen. beehiiv reaktiviert nur, wenn du reactivate_existing: true sendest, und MailerLite meldet nur mit resubscribe: true erneut an. Sende das nur, wenn das Formular es sagt.
  • Link-Scanner. Manche Mailfilter von Unternehmen öffnen Links in eingehenden E-Mails, um sie zu prüfen. Bestätigt ein Tool schon beim einfachen Laden der Seite, kann ein Scanner eine Adresse bestätigen, die niemand angeklickt hat. Prüf, ob die Bestätigungsseite deines Tools einen Klick auf einen Button verlangt.
  • Zustellbarkeit. Die Bestätigung ist die erste E-Mail, die ein Leser von dir bekommt. Versende sie in deinem Tool von einer authentifizierten Domain, sonst landet sie im Spam, und die Anmeldung wird nie abgeschlossen.
  • Unbestätigte Leute sammeln sich an. Sie sind noch keine Abonnenten. Entscheide in deinem Tool, ob du eine Erinnerung schickst, und lass sie dann in Ruhe.

Prüfen, ob es funktioniert

  1. Sende das Formular mit einer Adresse ab, die dir gehört. Die Seite sagt dir, dass du in deinen Posteingang schauen sollst.
  2. Öffne die Zustellung unter Webhooks in Ikiform. Sie zeigt succeeded mit dem 204 des Relays.
  3. Öffne den Abonnenten in deinem E-Mail-Tool. Er ist je nach Tool unbestätigt, inaktiv oder ausstehend.
  4. Öffne die Bestätigungs-E-Mail und klick. Der Abonnent wird aktiv oder bestätigt.
  5. Sende dieselbe Adresse innerhalb eines Tages erneut. Die Zustellung zeigt 200 mit „Confirmation already requested today“, und es kommt keine zweite E-Mail.
  6. Melde eine bereits bestätigte Adresse an. Sie bleibt bestätigt und bekommt keine neue Bestätigungs-E-Mail.

Fragen

Hängst du bei einem Schritt fest oder willst eine Anleitung für deinen Fall? Schreib an hello@ikiform.com.