Email Testing in CI/CD: Complete Guide
Most teams test their API endpoints, UI components, and database queries in CI/CD — but skip email testing. This guide shows you how to add email verification to your pipeline without the usual pain.
Why teams skip email testing in CI/CD
Section titled “Why teams skip email testing in CI/CD”Email testing in pipelines has historically been painful:
- Infrastructure overhead — running MailHog or a fake SMTP server in every CI run
- Flaky timing — emails take variable time to arrive, leading to
sleep(5000)hacks - Shared state — multiple test runs reading from the same inbox cause race conditions
- No assertions — can’t programmatically check email content, subject, or OTP codes
The solution: cloud email testing API
Section titled “The solution: cloud email testing API”Inboxical eliminates all of these problems:
- No infrastructure — cloud API, no SMTP server to manage
- Reliable timing — long-polling waits for emails instead of guessing
- Isolated inboxes — each test creates its own inbox
- Rich assertions — check subject, body, from, headers, and extract OTPs
Setting up email testing in GitHub Actions
Section titled “Setting up email testing in GitHub Actions”1. Store your API key
Section titled “1. Store your API key”Add INBOXICAL_API_KEY as a repository secret in GitHub Settings > Secrets.
2. Update your workflow
Section titled “2. Update your workflow”name: E2E Testson: [push, pull_request]
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20
- run: npm ci - run: npx playwright install --with-deps
- name: Run E2E tests run: npx playwright test env: INBOXICAL_API_KEY: ${{ secrets.INBOXICAL_API_KEY }}3. Write email tests
Section titled “3. Write email tests”import { test, expect } from '@playwright/test'import { inboxical } from '@inboxical/playwright'
test('password reset sends email', async ({ page }) => { const inbox = await inboxical.createInbox()
await page.goto('/forgot-password') await page.fill('[name=email]', inbox.emailAddress) await page.click('[type=submit]')
const messages = await inboxical.waitForMessages(inbox.id) expect(messages[0].subject).toContain('Reset your password')
// Extract the reset link from the email const resetUrl = messages[0].body.match(/https:\/\/[^\s]+reset[^\s]+/)?.[0] expect(resetUrl).toBeTruthy()})Other CI/CD platforms
Section titled “Other CI/CD platforms”GitLab CI
Section titled “GitLab CI”e2e-tests: stage: test image: mcr.microsoft.com/playwright:v1.40.0-jammy script: - npm ci - npx playwright test variables: INBOXICAL_API_KEY: $INBOXICAL_API_KEYCircleCI
Section titled “CircleCI”jobs: e2e: docker: - image: mcr.microsoft.com/playwright:v1.40.0-jammy steps: - checkout - run: npm ci - run: command: npx playwright test environment: INBOXICAL_API_KEY: ${INBOXICAL_API_KEY}Any CI with REST API
Section titled “Any CI with REST API”If you’re not using Node.js, the REST API works from any language:
# Create an inboxINBOX=$(curl -s -X POST https://api.inboxical.com/v1/inboxes \ -H "Authorization: Bearer $INBOXICAL_API_KEY" | jq -r '.id')
# ... trigger your email flow ...
# Wait for messages (long-polls for up to 30s)MESSAGES=$(curl -s "https://api.inboxical.com/v1/inboxes/$INBOX/messages?wait=true" \ -H "Authorization: Bearer $INBOXICAL_API_KEY")
# Assertecho $MESSAGES | jq -e '.[0].subject == "Welcome!"'Best practices
Section titled “Best practices”- One inbox per test — never share inboxes between tests
- Use long-polling — pass
wait=trueor use SDK methods instead ofsleep() - Clean up — delete inboxes after tests (or let them auto-expire)
- Test the critical paths — registration, password reset, OTP, and transactional emails
- Keep API keys secret — use CI/CD secret management, never commit keys
What to test
Section titled “What to test”| Flow | What to assert |
|---|---|
| Registration | Welcome email arrives, correct subject and sender |
| Password reset | Reset link is valid and unique |
| OTP/2FA | Code is correct length, works when entered |
| Transactional | Order confirmation has correct details |
| Notifications | Alert emails trigger on the right events |
Next steps
Section titled “Next steps”- Quickstart — get your API key and first inbox in 5 minutes
- GitHub Actions guide — detailed CI setup
- REST API reference — full API documentation