Zum Inhalt springen
Blog · 28. Mai 2026

Brevo DOI: Wenn der Bestätigungs-Button im Newsletter ins Leere führt

Brevo bestätigt erfolgreichen Versand der DOI-Mail, aber der HTML-Button hat einen leeren Link. Der dokumentierte Bug in der API-Reference und die Lösung.

Laptop auf dunklem Walnussholz-Schreibtisch zeigt einen B2B-Newsletter-Mockup mit dem Bestätigungs-Button „Anmeldung bestätigen". Eine Messing-Lupe liegt davor, rechts daneben ein gedruckter HTML-Quelltext mit einem orange markierten leeren href-Attribut.

Ein Newsletter-Formular im Footer einer Astro-Site, Brevo als Versanddienstleister, Double-Opt-In nach DSGVO-Standard. Der API-Endpoint POST /v3/contacts/doubleOptinConfirmation antwortet mit HTTP 204 — alles in Ordnung. Die Bestätigungsmail kommt beim Empfänger an, sauberer HTML-Body, prominenter Button „Anmeldung bestätigen”. Ein Klick auf den Button.

Nichts passiert.

Der Browser bleibt auf der Mail-Anwendung stehen. Im Quelltext steht: <a href="" target="_blank">…</a> — der href ist leer. Das Verwirrende: der Plaintext-Teil derselben Mail enthält einen funktionierenden Link auf sibcontacts.com/confirm/.... Empfänger mit Plaintext-Clients (selten, aber existent) würden den Bug nie bemerken.

Hier ist die Diagnose, die uns gestern in einem B2B-Mandat zwei Stunden gekostet hat — und die Lösung, die in Brevo’s offizieller API-Reference nicht steht.

Hypothese 1 — Falscher Template-Typ

Brevo unterscheidet intern zwischen „Regular Templates” (Newsletter, Transaktional, Automation) und „DOI Templates”. Letztere lassen sich nur über den Forms-Wizard im Bereich Kontakte → Anmeldeformulare anlegen — nicht über Campaigns → Templates. Wer das nicht weiß, legt ein Regular Template an, gibt die Template-ID an die API und bekommt eine harte Fehlermeldung: {"code":"invalid_parameter","message":"An active DOI template does not exist"}.

Auch über die API ist der DOI-Typ nicht setzbar. POST /v3/smtp/templates und PUT /v3/smtp/templates/{id} akzeptieren ein Feld doiTemplate: true ohne Fehler (HTTP 201/204), ignorieren es aber stillschweigend. Das Template bleibt Regular. Hypothese verworfen, sobald das Template über den Forms-Wizard korrekt als DOI angelegt war — der Endpoint nahm es an, die Mail wurde versendet, der Link blieb trotzdem leer.

Hypothese 2 — HTML-Sanitizer entfernt ungültige hrefs

Naheliegende Vermutung: Brevo’s Sanitizer prüft jeden <a href="…"> auf URL-Gültigkeit, sieht {{ params.DOUBLE_OPT_IN }} als ungültige URL und ersetzt sie durch einen leeren String — bevor die Template-Engine den Platzhalter überhaupt verarbeiten kann. Klassische Pipeline-Reihenfolge-Falle.

Widerlegt durch Vergleich. Andere <a>-Tags im selben Template (Logo-Link, Footer-Links) wurden korrekt durch Brevo’s Click-Tracker gewrappt (gjiicic.r.bh.d.sendibt3.com/tr/cl/...). Der Sanitizer arbeitet also — er greift nur beim DOI-Button nicht.

Hypothese 3 — Brevo’s Visual-Editor verändert das HTML

Brevo nutzt Froala als WYSIWYG-Editor. Beim Speichern setzt Froala in jedes Element fr-original-style- und fr-original-class-Metadaten. Vermutung: er erwartet auch ein fr-original-href und ersetzt fehlende Werte durch leer.

Widerlegt durch Test. HTML komplett im Brevo-UI-Code-Editor eingegeben (nicht über den Visual-Editor), Brevo persistierte es ohne fr-*-Attribute, das Problem trat weiter auf. Froala war es nicht.

Hypothese 4 — Variablen-Name in der Template-Sprache

Letzter Verdacht: die Template-Engine kennt den Platzhalter {{ params.DOUBLE_OPT_IN }} nicht. Ein Test-Template mit sechs Platzhalter-Varianten parallel — params.DOUBLE_OPT_IN, DOUBLE_OPT_IN, doubleoptinlink, OPT_IN_URL, contact.DOUBLE_OPT_IN, params.OPT_IN_URL — hätte den Treffer in der zugestellten Mail offenbart. Bevor wir das fahren mussten, brachte die zweite Doku-Quelle die Antwort.

Brevo’s deutschsprachiges Hilfe-Center (nicht die API-Reference) nennt eine andere Variable: {{ doubleoptin }} — kleingeschrieben, ohne params.-Präfix. Genau die, die in der API-Reference nicht erwähnt wird.

Aufgeschlagenes Notizbuch mit handschriftlichem Flowchart: Problem „Link funktioniert nicht" führt über vier durchgestrichene Hypothesen — falsche URL, falsche Methode, Server-Problem, Rechte/Rollen — zur orange umkringelten Lösung „Leeres href-Attribut". Daneben ein gedruckter HTML-Quelltext und eine Messing-Lupe.

Die Lösung

<!-- Falsch (laut API-Reference) -->
<a href="{{ params.DOUBLE_OPT_IN }}">Anmeldung bestätigen</a>
<!-- Richtig (laut Hilfe-Center) -->
<a href="{{ doubleoptin }}">Anmeldung bestätigen</a>

Template-Tag optin setzen, Test-DOI fahren, Link funktioniert. Sauber.

Der API-Call selbst bleibt unverändert:

curl -X POST https://api.brevo.com/v3/contacts/doubleOptinConfirmation \
  -H "api-key: $BREVO_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "email": "user@example.com",
    "includeListIds": [18],
    "templateId": 156,
    "redirectionUrl": "https://example.com/newsletter-bestaetigt/"
  }'

Warum das überhaupt durchrutscht

Brevo’s offizielle API-Reference dokumentiert {{ params.DOUBLE_OPT_IN }} als den Pflicht-Platzhalter. Diese Doku ist veraltet. Die korrekte Variable seit der Brevo-Template-Engine-Umstellung steht im Hilfe-Center-Artikel zur DOI-Personalisierung{{ doubleoptin }}. Wer den falschen Platzhalter nutzt, bekommt HTTP 204, die Mail wird versendet, der HTML-Link bleibt leer. Im Plaintext-Teil generiert Brevo den DOI-Link separat aus einem internen Default-Template, daher fällt der Fehler oft erst auf, wenn ein Empfänger ihn meldet.

Zwei Doku-Quellen desselben Anbieters mit widersprüchlichen Angaben, eine davon falsch — das ist nicht Brevo-spezifisch. Wir sehen das regelmäßig bei Drittsystemen, deren Marketing-Doku schneller aktualisiert wird als die technische Reference, oder umgekehrt.

Drei Lehren für vergleichbare Setups

Erstens: API-Doku ist nicht immer die letzte Wahrheit. Bei Brevo widersprechen sich API-Reference und Hilfe-Center. Die Hilfe-Center-Variante war die korrekte. Bei Bugs in Drittsystemen lohnt sich der Blick in die nicht-technische Doku des Anbieters — also Help-Center, Community-Threads, Status-Pages.

Zweitens: HTTP 2xx ist kein Beweis dafür, dass die Sache funktioniert. Brevo bestätigte erfolgreichen Versand mit HTTP 204, der Empfänger bekam einen unbenutzbaren Button. Newsletter- und Transactional-Setups gehören End-to-End getestet, nicht nur auf API-Response-Codes geprüft.

Drittens: Plaintext und HTML auseinanderhalten. Brevo füllt beim DOI den Plaintext-Teil aus einem eigenen Default-Template. Wer nur HTML-Clients zum Testen verwendet, sieht den Bug; wer in einem reinen Plaintext-Client testet, übersieht ihn. Bestätigungs-Mails in mindestens zwei Clients öffnen, einer davon mit erzwungenem Plaintext-Modus.

Wer das gerade selbst sucht

Wenn Sie an einem Newsletter-Funnel arbeiten und der DOI-Klick ins Leere führt, ist die Wahrscheinlichkeit hoch, dass es genau dieser Platzhalter ist. Ersetzen Sie {{ params.DOUBLE_OPT_IN }} durch {{ doubleoptin }}, ein Test-DOI durchlaufen lassen, fertig.

Falls Sie unsicher sind, ob Ihr Newsletter-Setup sauber durchläuft — von der API-Antwort über die Template-Engine bis zur Empfänger-Inbox: wir prüfen das in einem 20-Minuten-Klartext-Call, ohne Verpflichtung. Direkt mit Julian Raab, kein Junior dazwischen. Termin vereinbaren →