Newsletter-Anmeldung mit Double-Opt-in über Amazon SES, ohne Newsletter-Tool

Christian Drexler

Eine meiner Seiten hat einen Blog, den Leute über die Suche finden, einmal lesen und wieder verlassen. Ich wollte den Interessierten Bescheid geben können, wenn es etwas Neues gibt. Die übliche Antwort ist ein Newsletter-Tool. Das übliche Newsletter-Tool kostet ab dem ersten Abonnenten eine Monatsgebühr, lädt ein Skript auf meinen Seiten und hält die Liste auf den eigenen Servern.

Die Anmeldeseite eines Newsletters ist klein genug, um sie selbst zu besitzen. Sie ging an einem Nachmittag live, auf Mail-Infrastruktur, für die ich ohnehin Cent-Beträge zahle. Dieser Beitrag behandelt diese Hälfte: Adressen sauber einsammeln. Ausgaben verschicken ist eine eigene Aufgabe.

Die vier Teile

Eine Tabelle. Eine Zeile pro Adresse: die E-Mail, ein Status, der entweder pending oder confirmed ist, ein zufälliges Token, der Zeitpunkt der Anmeldung und der Zeitpunkt der Bestätigung. Die E-Mail-Spalte ist eindeutig. Mehr braucht es in diesem Stadium nicht.

Eine Anmelde-Route. Sie nimmt die Adresse aus dem Formular, prüft, ob sie wie eine aussieht, legt die Zeile als pending mit einem frischen Token an und verschickt eine Mail mit einem Bestätigungslink. Steht die Adresse schon auf der Liste, sollte die Antwort trotzdem „Schau in dein Postfach“ lauten. Ein Formular, das „Du bist bereits angemeldet“ sagt, verrät jedem, der eine Adresse eintippt, ob diese Person auf deiner Liste steht.

Eine Bestätigungs-Route. Der Link in der Mail führt mit dem Token hierher. Die Route sucht die Zeile, setzt sie auf confirmed, speichert den Zeitpunkt und zeigt eine kurze Dankesseite. Ein unbekanntes Token bekommt eine freundliche Seite, die sagt, dass der Link nicht mehr gültig ist, und sonst nichts.

Die Mail. Schlicht, kurz, ein Link. Kein Logo, kein Zählpixel, keine zweite Handlungsaufforderung. Sie hat eine einzige Aufgabe, und jedes zusätzliche Element lässt sie mehr wie die Art Mail aussehen, die Filter wegwerfen.

Das ist Double-Opt-in: Die Adresse steht erst auf der Liste, nachdem ihr Inhaber geklickt hat. In Deutschland ist es der Standard, den man erfüllen muss, und überall sonst schützt es vor Tippfehlern, vor Leuten, die ihre Kollegen anmelden, und vor Bots, die das Formular mit fremden Adressen füllen. Eine Liste bestätigter Adressen ist kleiner und mehr wert.

Die SES-Seite

Amazon SES verschickt die Bestätigungsmail. Vier Einstellungen entscheiden, ob sie ankommt.

Produktionszugang. Ein neues SES-Konto kann nur an Adressen schicken, die man selbst verifiziert hat. Über diese Falle habe ich gesondert geschrieben. Prüfe das vor allem anderen, in der Region, aus der du sendest.

Eine verifizierte Domain mit DKIM. Verifiziere die ganze Domain, nicht eine einzelne Adresse, und veröffentliche die drei DKIM-Einträge, die SES dir gibt. Mail von einer Domain ohne sie landet oft genug im Spam, um die ganze Übung sinnlos zu machen.

Eine eigene MAIL-FROM-Domain. Standardmäßig ist der technische Absender von SES-Mail eine Amazon-Adresse. Setzt man eine eigene Subdomain, etwa bounce.example.com, mit den MX- und SPF-Einträgen, die SES verlangt, gehören sichtbarer und technischer Absender zur selben Domain. Mail-Anbieter prüfen diese Übereinstimmung.

Ein Absender, der genau eines kann. Die Seite benutzt einen Zugangsschlüssel, der zu einem Benutzer gehört, der Mail senden darf und sonst nichts.

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["ses:SendEmail", "ses:SendRawEmail"],
    "Resource": "*"
  }]
}

Sollte dieser Schlüssel je aus einer Umgebungsdatei entweichen, ist der schlimmste Fall Mail in meinem Namen, bis ich es merke. Er kann nichts lesen und nichts ändern, und er kann keine Server starten.

Die Sendungen laufen außerdem über ein eigenes Configuration Set, damit sich Rückläufer und Beschwerden zum Newsletter später von der übrigen Mail der Seite trennen lassen.

Der Satz, den ich gestrichen habe

In der ersten Fassung des Formulars stand, wie oft der Newsletter kommt. Das klang gut und konkret. Es war auch ein Versprechen über einen Rhythmus, den ich nie gehalten hatte, weil es den Newsletter noch gar nicht gab.

Eine versprochene Häufigkeit wird in dem Moment zur Schuld, in dem die erste Person bestätigt. Hält man sie nicht ein, hat man das Erste gebrochen, was man ihr gesagt hat. Im Formular steht deshalb jetzt, dass nur dann eine Mail kommt, wenn es etwas Neues gibt, die Bestätigungsmail sagt dasselbe, und nirgends steht eine Zahl. Stellt sich ein Rhythmus ein, kann man ihn dann aufschreiben.

Es ist eine Kleinigkeit. Es ist auch die Art Satz, die in dreißig Sekunden geschrieben ist und fünf Jahre auf einer Seite stehen bleibt.

Der Platzhalter, der das erste Deployment gekippt hat

Das erste Deployment scheiterte auf die denkbar uninteressanteste Weise. Die Anmelde-Route antwortete mit einem Fehler, und im Log stand, dass die Datenbank die Anfrage mit einem 401 ablehnte.

Die Route liest den Datenbankschlüssel aus einer Umgebungsvariable. Die Variable war gesetzt. Ihren Wert hatte ich aus dem Eintrag des Passwortmanagers für diese Datenbank kopiert. Dieser Eintrag war lange vorher angelegt worden, in Eile, und im Feld für den Schlüssel stand das Wort TODO.

Das Deployment war, ganz gewissenhaft, mit dem Geheimnis TODO konfiguriert worden.

Zur Lösung gibt es nichts Kluges zu sagen: Der echte Schlüssel kam in den Eintrag und ins Deployment. Die Lehre betrifft den Test. Eine Anmeldung testet man nicht, indem man die Meldung auf der Seite ansieht. Man testet sie mit dem ganzen Weg: eine Adresse absenden, die Mail im Postfach finden, den Link klicken und sehen, dass die Zeile in der Tabelle confirmed sagt. Nur das beweist die Kette, und es hat den Platzhalter binnen Minuten gefunden. Genau das mache ich nach jedem Deployment, das die Route berührt, mit einer eigenen Adresse, und lösche danach die Testzeile und die Testmail.

Was es bewusst noch nicht gibt

Es gibt keinen Versand von Ausgaben. Wenn ich ihn baue, hat er drei Regeln, bevor er eine einzige Mail verschickt: Er schreibt nur Zeilen mit Status confirmed an, jede Mail trägt einen Abmeldelink aus dem Token der Zeile, und derselbe Link steht in einem List-Unsubscribe-Header, damit das Mailprogramm seinen eigenen Abmeldeknopf zeigen kann. Rückläufer und Beschwerden kommen über SES-Benachrichtigungen zurück und nehmen die Adresse ohne mein Zutun von der Liste.

Es gibt auch kein Pop-up. Das Anmeldefeld steht in der Mitte und am Ende jedes Artikels, und eine schmale Leiste erscheint, sobald jemand über die Hälfte hinaus gelesen hat. Wer die Leiste schließt, sieht sie dreißig Tage nicht mehr. Wer einen halben Artikel gelesen hat, hat mehr Interesse gezeigt als jemand, der gerade angekommen ist, und ihn zu fragen ist fair.

Lohnt es sich

Für eine Liste, die vielleicht ein paar hundert Leser erreicht, ja. Die Kosten sind eine Tabelle, zwei Routen und Cent-Beträge pro tausend Mails. Die Adressen gehören mir, auf der Seite lädt nichts von Dritten, und ich weiß genau, was mit einer Adresse zwischen Formular und Zeile passiert.

Für eine Liste im fünfstelligen Bereich mit Segmenten, Automationen und einem Team, das einen visuellen Editor will: Kauf das Tool. Dafür ist es da. Die meisten Blogs sind davon weit entfernt und zahlen die Monatsgebühr trotzdem.