Mailwurf

CI

Run email tests in GitHub Actions and other pipelines.

CI needs one thing from Mailwurf: an API key. The app under test needs a mail provider that really sends.

GitHub Actions

Create a key named after the pipeline, for example GitHub Actions, and store it as the repository secret MAILWURF_API_KEY.

.github/workflows/e2e.yml
name: e2e

on: pull_request

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test
        env:
          MAILWURF_API_KEY: ${{ secrets.MAILWURF_API_KEY }}
          APP_URL: ${{ vars.APP_URL }}

Pull requests from forks do not receive repository secrets. Those runs get 401 from Mailwurf.

The app must send real mail

Mailwurf receives mail over the internet, like any mailbox. The app under test has to deliver to the inbox address:

  • Deployed preview or staging app: nothing to change; it already uses its provider.
  • App started inside the CI job: give the job the provider credentials the app needs (for example a Resend or SES key for a test domain).
  • Provider sandbox modes often deliver only to verified recipients. Use a mode that sends to any address, or the mail never arrives.
  • Local mail catchers such as a fake SMTP server swallow the mail before it leaves CI. Turn them off for these tests.

Keys and parallel jobs

  • Use one key per pipeline. Revoke it in the dashboard to cut off a leaked key without touching other environments.
  • Give keys an expiry for short-lived environments.
  • Each key can hold four waits open at once. For more parallel workers, split shards across several keys.
strategy:
  matrix:
    shard: [1, 2, 3, 4]
steps:
  - run: npx playwright test --shard=${{ matrix.shard }}/4 --workers=4
    env:
      MAILWURF_API_KEY: ${{ secrets[format('MAILWURF_API_KEY_{0}', matrix.shard)] }}

On this page