Alle ansehen./playwright-ci-signup-tests

Mailiy in deinem CI — Playwright-Tests gegen echte Signup-Flows

Sat May 09 2026 00:00:00 GMT+0000 (Coordinated Universal Time)· 6 min

Das Problem mit statischen Test-Postfächern

Playwright-Tests gegen echte Signup-Flows scheitern oft an einem trivialen Punkt: Du brauchst eine E-Mail-Adresse, die existiert, Mails empfängt und den Posteingang deines Teams nicht verschmutzt. Statische Test-Accounts (qa@deinedomain.com) werden mit der Zeit zur Müllhalde — Onboarding-Mails, Passwort-Resets und Welcome-Sequenzen stapeln sich, bis jemand manuell aufräumt. Parallele CI-Runs kollidieren in derselben Inbox und schnappen sich gegenseitig die Verifizierungsmails.

Die gängigen Workarounds (Mailpit, MailHog, MailCrab) sind gut für lokale Entwicklung, aber für Cloud-CI umständlich: Du musst sie als Service betreiben, irgendwie exponieren und deine App so verdrahten, dass sie statt an echtes SMTP an diese Tools sendet. Machbar, aber nicht derselbe Code-Pfad, den du ausrollst.

Die Mailiy-API in drei Calls

Die Mailiy-REST-API ist genau dafür gemacht. In einem beforeEach-Hook holst du dir per POST /v1/mailbox eine frische Adresse, optional mit ttlMinutes:

import { test } from '@playwright/test'

test.beforeEach(async ({ context }) => {
  const res = await fetch('https://api.mailiy.com/v1/mailbox', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.MAILIY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ ttlMinutes: 30 }),
  })
  const { id, address } = await res.json()
  context.mailboxId = id
  context.address = address
})

API-Keys beginnen mit ml_pk_ und werden in den Account-Settings erzeugt. Lege den Key in deinen CI-Secret-Store, nicht ins Repo.

Im Test pollst du dann GET /v1/mailbox/:id/messages, bis die Verifizierungsmail ankommt:

async function waitForMail(mailboxId: string, timeoutMs = 30_000) {
  const deadline = Date.now() + timeoutMs
  while (Date.now() < deadline) {
    const r = await fetch(`https://api.mailiy.com/v1/mailbox/${mailboxId}/messages`, {
      headers: { 'Authorization': `Bearer ${process.env.MAILIY_API_KEY}` },
    })
    const { messages } = await r.json()
    if (messages.length > 0) return messages[0]
    await new Promise(r => setTimeout(r, 1000))
  }
  throw new Error('Verifizierungsmail kam nicht rechtzeitig')
}

Ein Intervall von einer Sekunde mit 30 Sekunden Timeout reicht — das Backend antwortet in der Regel in unter einer Sekunde, weil SMTP-Ingest und API-Read gegen dieselbe Postgres-Instanz laufen.

Optional: Webhooks statt Polling

Wenn du lieber synchron arbeitest, registrierst du per POST /v1/webhooks mit { mailboxId, url } einen Push auf einen lokalen ngrok-Tunnel:

await fetch('https://api.mailiy.com/v1/webhooks', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${process.env.MAILIY_API_KEY}` },
  body: JSON.stringify({
    mailboxId: context.mailboxId,
    url: `${process.env.NGROK_URL}/inbound`,
  }),
})

Für CI ist Polling meist einfacher — du musst nichts inbound exponieren.

Teardown

Nach dem Test kannst du entweder die TTL die Arbeit machen lassen oder explizit löschen:

test.afterEach(async ({ context }) => {
  await fetch(`https://api.mailiy.com/v1/mailbox/${context.mailboxId}`, {
    method: 'DELETE',
    headers: { 'Authorization': `Bearer ${process.env.MAILIY_API_KEY}` },
  })
})

Explizites Löschen ist freundlich zu deinem Rate-Limit-Budget und macht Test-Runs hermetisch. Die TTL drüber laufen zu lassen, ist für Suiten mit geringem Volumen in Ordnung.

Rate-Limit-Budget

Dein API-Tier bestimmt sowohl die Monats-Quota als auch das Per-Minute-Limit:

Tier Calls/Monat Rate
api_free 500 10 req/min
api_lite 10.000 60 req/min
api_pro 100.000 300 req/min

Eine typische PR-Pipeline mit 50 Tests verbraucht pro Test 3–5 Calls (Create, Poll, optional Delete) — bei 100 PRs pro Tag passt das komfortabel in den Pro-Plan. Für ein kleines Team mit leichter CI-Nutzung ist auch der Free-Tarif echt brauchbar.

Wenn du mehr Per-Minute-Durchsatz brauchst als Pro liefert (300 req/min), geht Business auf 1.000 req/min, Enterprise ist unbegrenzt.

Was du dadurch bekommst

  • Keine Kollisionen mehr in geteilten Postfächern bei parallelen CI-Runs
  • Hermetische Test-Daten — jeder Test startet mit frischer Inbox
  • Echter SMTP-Pfad — du triffst deinen echten Signup-Endpunkt, nicht einen Mock
  • Sub-Sekunden-Feedback — Polling holt Nachrichten zuverlässig innerhalb von ~1s nach SMTP-Eingang

Für ein vollständiges Beispiel mit Cypress (statt Playwright), siehe die Beispiele in der API-Doku.


Jetzt ausprobieren → Wegwerf-Adresse auf der mailiy-Startseite generieren — ein Klick, in unter zwei Sekunden bereit, keine Anmeldung, kein Account.

Kostenlos. Ohne Registrierung.

Generiere in unter zwei Sekunden eine Wegwerf-E-Mail-Adresse — keine Anmeldung, keine Tracker, keine Kompromisse.

E-Mail generieren