Email testing in GitLab CI
The same per-run inbox pattern in .gitlab-ci.yml, with the key stored as a masked CI/CD variable and teardown in after_script.
How it fits together
after_script runs whether the job succeeded or failed, which makes it the right place for teardown — the GitLab equivalent of if: always().
The job
# .gitlab-ci.yml
e2e:
image: mcr.microsoft.com/playwright:v1.61.0-jammy
variables:
MAILFLAT_API: "https://mailflat.net/api/v1"
before_script:
- apt-get update && apt-get install -y jq
- |
export TEST_EMAIL=$(curl -s -X POST "$MAILFLAT_API/inboxes" \
-H "X-API-Key: $MAILFLAT_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"prefix\":\"ci-$CI_PIPELINE_ID\",\"retention_hours\":2}" | jq -r .address)
echo "TEST_EMAIL=$TEST_EMAIL" >> build.env
script:
- npm ci
- npx playwright test
after_script:
- |
curl -s -X DELETE "$MAILFLAT_API/inboxes/$TEST_EMAIL" \
-H "X-API-Key: $MAILFLAT_API_KEY" || true
artifacts:
reports:
dotenv: build.env
Worth knowing
Add MAILFLAT_API_KEY under Settings, CI/CD, Variables and tick Masked so it never appears in job logs.
after_script runs in a fresh shell, so pass the address through a dotenv artifact rather than an exported variable.
See also
Testing & CI
Give every CI run its own real inbox: the four API calls, parallel shards, teardown, and how to keep an end-to-end suite fast and honest.
curlEvery endpoint in one terminal. Useful for smoke checks, CI shell steps, and for seeing exactly what your language client sends.
API Keys & AuthAccount keys versus session tokens: which endpoints accept which credential, how to create and rotate keys, and why the wrong pair returns 401.