Wie ein Test-SMTP-Server Bestell- und Registrierungsmails automatisiert und ohne Flakiness prüfbar macht
Eine Bestellbestätigung oder eine Registrierungsmail gehört zu den kritischsten, aber am häufigsten ungetesteten Pfaden eines Onlineshops, weil E-Mail-Versand außerhalb des direkten Zugriffs eines Browsertests stattfindet und asynchron, mit unbekannter Verzögerung, in einem fremden System landet. Ein Test-SMTP-Server wie Mailhog oder Mailtrap löst genau dieses Problem, indem er ausgehende E-Mails innerhalb der Testumgebung abfängt, über eine eigene API abrufbar macht und damit Inhalt, Betreff und Links einer E-Mail genauso präzise prüfbar macht wie ein DOM-Element im Browser.
Inhaltsverzeichnis
- 1. Warum E-Mail-Versand in E2E-Tests eine eigene Herausforderung darstellt
- 2. Test-SMTP-Server im Überblick: Mailhog, Mailpit und Mailtrap
- 3. Magento und Hyvä auf einen Test-SMTP-Server umstellen
- 4. E-Mails über die Mailpit-API im Test abrufen
- 5. Inhalt und Links in Bestell- und Registrierungsmails gezielt validieren
- 6. Flakiness durch asynchronen Versand vermeiden
- 7. Mehrere E-Mails im selben Test zuverlässig unterscheiden
- 8. Test-SMTP-Server als Service-Container in der CI-Pipeline
- 9. Grenzen des Ansatzes: was ein Test-SMTP-Server nicht abdeckt
- 10. Zusammenfassung
- 11. FAQ
1. Warum E-Mail-Versand in E2E-Tests eine eigene Herausforderung darstellt
Ein Browsertest kann direkt beobachten, was im DOM erscheint, sobald eine Aktion ausgeführt wurde, doch eine ausgehende E-Mail verlässt diesen beobachtbaren Bereich vollständig: Sie wird von der Anwendung an einen Mailserver übergeben, dort in eine Warteschlange eingereiht und irgendwann, mit unbekannter Verzögerung, tatsächlich zugestellt. Ohne einen gezielten Zugriff auf diese E-Mail bleibt einem Test nur die indirekte Prüfung, etwa ob im Anwendungslog ein Eintrag über den erfolgreichen Versand auftaucht, was jedoch nichts darüber aussagt, ob der tatsächliche Inhalt der E-Mail korrekt, vollständig und mit den richtigen Links versehen war.
Diese Lücke führt in vielen Projekten dazu, dass E-Mail-Inhalte überhaupt nicht automatisiert getestet werden, sondern nur manüll und unregelmässig stichprobenartig geprüft werden, obwohl gerade Bestellbestätigungen, Passwort-Reset-Mails und Registrierungsmails zu den Nachrichten gehören, bei denen ein fehlerhafter Link oder ein falsch interpolierter Platzhalter direkte, spürbare Auswirkungen auf Kundinnen und Kunden hat. Ein Test-SMTP-Server schließt diese Lücke, indem er die E-Mail innerhalb derselben Testumgebung abfängt, bevor sie überhaupt einen echten Mailserver erreicht.
2. Test-SMTP-Server im Überblick: Mailhog, Mailpit und Mailtrap
Mailhog und sein aktiver Nachfolger Mailpit sind leichtgewichtige, selbst gehostete SMTP-Server, die jede eingehende E-Mail abfangen, niemals tatsächlich zustellen und stattdessen über eine Web-Oberfläche sowie eine REST-API zugänglich machen, wodurch sie sich ideal als Container innerhalb einer lokalen Docker-Umgebung oder einer CI-Pipeline betreiben lassen, ohne jemals mit einem echten, öffentlichen Mailserver zu kommunizieren. Mailtrap verfolgt ein ähnliches Konzept, wird aber typischerweise als gehosteter Dienst genutzt und bietet zusätzlich eine Spam-Score-Analyse sowie HTML-Validierung für den E-Mail-Inhalt.
Für eine Magento- und Hyvä-Entwicklungsumgebung im Docker-Setup bietet sich Mailpit besonders an, weil es sich als zusätzlicher Service innerhalb derselben Compose-Datei betreiben lässt, komplett offline arbeitet und dadurch weder von einer externen Internetverbindung noch von Rate-Limits eines gehosteten Anbieters abhängig ist, was CI-Läufe deutlich stabiler macht.
3. Magento und Hyvä auf einen Test-SMTP-Server umstellen
Magento nutzt standardmässig PHPs eingebaute Mail-Funktion oder einen konfigurierten SMTP-Transport, weshalb sich der komplette ausgehende E-Mail-Verkehr in einer Testumgebung mit wenigen Konfigurationswerten auf den lokalen Test-SMTP-Server umleiten lässt, ohne dass an der eigentlichen Versandlogik der Anwendung etwas geändert werden muss.
# Magento auf lokalen Test-SMTP-Server (Mailpit) umstellen
bin/magento config:set system/smtp/host mailpit
bin/magento config:set system/smtp/port 1025
bin/magento config:set system/smtp/transport smtp
# In compose.dev.yaml als eigener Service:
# mailpit:
# image: axllent/mailpit
# ports:
# - "8025:8025" # Web-UI und REST-API
# - "1025:1025" # SMTP-Port
4. E-Mails über die Mailpit-API im Test abrufen
Statt eine Mailbox im Browser öffnen zu müssen, fragt ein E2E-Test die REST-API des Test-SMTP-Servers direkt ab, filtert die zuletzt eingegangene Nachricht nach Empfängeradresse und prüft anschliessend Betreff, HTML-Inhalt und enthaltene Links gezielt gegen die erwarteten Werte, genauso wie eine Assertion gegen ein DOM-Element.
Dieser API-Zugriff läuft vollständig außerhalb des Browserkontexts ab, weshalb er sich in Playwright oder Cypress problemlos als zusätzlicher HTTP-Request innerhalb desselben Testfalls einbaün lässt, direkt nachdem die auslösende Aktion, etwa das Abschliessen einer Bestellung, im Browser ausgeführt wurde.
import { test, expect } from '@playwright/test';
test('Bestellbestätigung enthält korrekte Bestellnummer und Link', async ({ page, request }) => {
await page.goto('/checkout/onepage/success');
const orderNumber = await page.locator('[data-testid="order-number"]').textContent();
const search = await request.get(
`http://mailpit:8025/api/v1/search?query=to:kunde@example.test`
);
const { messages } = await search.json();
const latest = messages[0];
const detail = await request.get(`http://mailpit:8025/api/v1/message/${latest.ID}`);
const email = await detail.json();
expect(email.Subject).toContain('Ihre Bestellung');
expect(email.HTML).toContain(orderNumber);
expect(email.HTML).toMatch(/href="https:\/\/[^"]+\/sales\/order\/view/);
});
5. Inhalt und Links in Bestell- und Registrierungsmails gezielt validieren
Über die reine Zustellungsprüfung hinaus lohnt sich ein gezielter Blick auf drei besonders fehleranfällige Bestandteile jeder transaktionalen E-Mail: korrekt interpolierte Platzhalter wie Kundenname und Bestellnummer, die vollständige und syntaktisch gültige URL jedes enthaltenen Links, sowie das Vorhandensein aller erwarteten Positionen bei einer Bestellbestätigung mit mehreren Artikeln.
Besonders bei Registrierungsmails mit einem Bestätigungslink ist eine end-to-end Prüfung wertvoll, bei der der Test den extrahierten Link tatsächlich im Browser öffnet und anschliessend verifiziert, dass das Konto danach als aktiviert gilt, statt sich allein auf die textülle Anwesenheit des Links im E-Mail-Inhalt zu verlassen, denn ein fehlerhaft signierter oder bereits abgelaufener Token würde durch eine reine Textprüfung nicht auffallen.
Enthält eine E-Mail zusätzlich einen Dateianhang, etwa eine Rechnung als PDF bei einer Bestellbestätigung, sollte der Test nicht nur das Vorhandensein des Anhangs prüfen, sondern den Anhang aus der Antwort des Test-SMTP-Servers tatsächlich extrahieren und mit derselben Parsing-Technik untersuchen, die auch für direkte Datei-Downloads eingesetzt wird, um sicherzustellen, dass der Anhang inhaltlich korrekt und nicht etwa eine leere oder beschädigte Datei ist.
Da viele E-Mail-Clients neben der HTML-Version zusätzlich eine reine Text-Alternative anzeigen, lohnt sich ein ergänzender Test, der auch den Text-Body der E-Mail auf dieselben Kerninformationen wie Bestellnummer und Gesamtbetrag prüft, da eine nur in der HTML-Version korrekt gepflegte Nachricht bei Text-only-E-Mail-Clients unvollständig oder fehlerhaft erscheinen würde.
6. Flakiness durch asynchronen Versand vermeiden
Der häufigste Grund für instabile E-Mail-Tests ist eine feste, geschätzte Wartezeit zwischen dem Auslösen der Aktion und dem Abrufen der E-Mail, etwa ein pauschales Warten von zwei Sekunden, das je nach Systemlast mal ausreicht und mal nicht, wodurch der Test in der CI-Pipeline gelegentlich grundlos fehlschlägt, obwohl die E-Mail kurz danach tatsächlich eintrifft.
Die zuverlässige Lösung ist ein Polling mit klar definiertem Timeout, das die API des Test-SMTP-Servers in kurzen Abständen wiederholt abfragt, bis entweder die erwartete Nachricht gefunden wird oder ein großzügiges, aber endliches Zeitlimit überschritten ist, wodurch der Test im Normalfall sofort nach Eintreffen der E-Mail fortfährt und nur im tatsächlichen Fehlerfall die volle Wartezeit ausschöpft.
async function waitForEmail(request, toAddress, timeoutMs = 10000) {
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const res = await request.get(`http://mailpit:8025/api/v1/search?query=to:${toAddress}`);
const { messages } = await res.json();
if (messages.length > 0) return messages[0];
await new Promise((resolve) => setTimeout(resolve, 300));
}
throw new Error(`Keine E-Mail an ${toAddress} innerhalb von ${timeoutMs}ms eingetroffen`);
}
7. Mehrere E-Mails im selben Test zuverlässig unterscheiden
Sobald ein Testszenario mehrere E-Mails auslöst, etwa eine Bestellbestätigung gefolgt von einer separaten Versandbenachrichtigung, reicht ein einfaches Abrufen der jeweils letzten Nachricht an eine Empfängeradresse nicht mehr aus, da beide Nachrichten an dieselbe Adresse gehen und sich ihre zeitliche Reihenfolge unter Testlast nicht immer verlässlich vorhersagen lässt.
In diesem Fall filtert der Test gezielt nach dem Betreff oder einem eindeutigen, in der E-Mail enthaltenen Kennzeichen, etwa der Bestellnummer, statt sich blind auf die zeitliche Reihenfolge zu verlassen, wodurch jede E-Mail unabhängig von Versandzeitpunkt und Eintreffreihenfolge eindeutig identifiziert und gezielt geprüft werden kann, selbst wenn mehrere ähnliche Nachrichten kurz hintereinander im selben Testlauf erzeugt werden.
8. Test-SMTP-Server als Service-Container in der CI-Pipeline
In einer GitLab-CI- oder GitHub-Actions-Pipeline läuft der Test-SMTP-Server als zusätzlicher Service-Container parallel zum eigentlichen Testlauf, wird über seinen internen Netzwerknamen erreichbar gemacht und benötigt dabei keinerlei persistenten Speicher, da der komplette E-Mail-Bestand ohnehin nur für die Dauer eines einzelnen Pipeline-Laufs relevant ist und danach verworfen werden kann.
Diese vollständige Isolation pro Pipeline-Lauf bedeutet gleichzeitig, dass parallele CI-Jobs sich nicht gegenseitig mit unerwarteten E-Mails im selben Postfach stören, ein Vorteil, den ein gemeinsam genutzter, gehosteter Test-Mail-Dienst ohne zusätzliche Namensraum-Trennung nicht ohne Weiteres bietet.
Um zu verhindern, dass parallel laufende Tests sich gegenseitig durch E-Mails an dieselbe, feste Testadresse stören, empfiehlt sich die Verwendung einer eindeutigen, pro Testfall generierten Empfängeradresse, etwa durch Anhängen einer Zufallszeichenfolge oder der Test-ID an einen festen lokalen Teil, wodurch jeder Test ausschliesslich seine eigenen E-Mails abruft und Testparallelisierung ohne gegenseitige Beeinflussung möglich bleibt, selbst wenn mehrere Tests denselben Registrierungs- oder Bestellvorgang gleichzeitig gegen dieselbe Testumgebung ausführen.
9. Grenzen des Ansatzes: was ein Test-SMTP-Server nicht abdeckt
Ein Test-SMTP-Server prüft zuverlässig, was die Anwendung tatsächlich versendet, macht aber keine Aussage darüber, wie ein echter, öffentlicher Mailserver diese Nachricht später behandelt, etwa ob SPF-, DKIM- und DMARC-Einträge korrekt konfiguriert sind oder ob der Inhalt von Spam-Filtern großer Mail-Anbieter zurückgewiesen wird, Aspekte, die außerhalb der eigentlichen Anwendungslogik liegen und separat, etwa mit dedizierten Zustellbarkeits-Diensten, geprüft werden müssen.
Die folgende Tabelle vergleicht die vorgestellten Ansätze für das Testen von E-Mail-Versand.
| Ansatz | Geeignet für | Nachteil |
|---|---|---|
| Mailpit/Mailhog lokal | Docker-Entwicklungsumgebung, CI-Pipeline | Keine echte Zustellbarkeits-Prüfung |
| Mailtrap gehostet | Team-weites, geteiltes Test-Postfach | Abhängigkeit von externem Dienst und Rate-Limits |
| Anwendungslog prüfen | Grober Nachweis, dass Versand ausgelöst wurde | Keine Aussage über Inhalt oder Links |
| Echte Zustellbarkeits-Dienste | SPF/DKIM/Spam-Filter-Prüfung | Nicht für jeden einzelnen Testlauf geeignet |
Mironsoft
E2E-Teststrategie, CI-Integration und stabile Testsuiten
Testsuiten, die Bugs finden statt nur rot zu blinken?
Wir prüfen bestehende E2E-Testsuiten auf Flakiness, fehlende Testisolation und ineffiziente CI-Laufzeiten und bauen daraus eine Teststrategie, die tatsächlich Vertrauen schafft statt nur Haken zu setzen.
Test-Audit
Flaky Tests, Testpyramide und Coverage-Lücken systematisch aufdecken.
CI-Optimierung
Parallele Ausführung, Retry-Strategien und schnelle Feedback-Zyklen aufbauen.
Cypress/Playwright-Setup
Robuste E2E-Suiten für Magento-Frontends von Grund auf einrichten.
10. Zusammenfassung
E-Mail-Testing: Das Wichtigste auf einen Blick
Kernidee
Ein Test-SMTP-Server fängt ausgehende E-Mails ab und macht sie über eine API prüfbar wie ein DOM-Element.
Stärke
Inhalt, Platzhalter und Links in Bestell- und Registrierungsmails lassen sich präzise automatisiert validieren.
Fallstrick
Feste Wartezeiten statt Polling mit Timeout sind die häufigste Ursache für Flakiness.
Grenze
Zustellbarkeit bei echten Mail-Anbietern und Spam-Filter-Verhalten werden separat geprüft.