Why test emails in CI?
Email is often the last thing tested and the first thing that breaks. A refactored template, a changed variable name, a migrated mailing service — any of these can silently break critical emails like order confirmations, invitations, or security alerts. Your CI should catch these regressions.
With MailHog, your CI pipeline points its SMTP configuration at our hosted server. When tests trigger email sends, the emails are captured and queryable via our REST API. Your test assertions verify that the right emails were sent, to the right recipients, with the right content.
GitHub Actions example
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
env:
SMTP_HOST: smtp.mailhog.site
SMTP_PORT: 2525
SMTP_USER: ${{ secrets.MAILHOG_SMTP_USER }}
SMTP_PASS: ${{ secrets.MAILHOG_SMTP_PASS }}
MAILHOG_API_KEY: ${{ secrets.MAILHOG_API_KEY }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm test # includes email assertion testsWhat to assert on
Email was sent
Verify the expected email exists in the inbox after triggering the action.
Correct recipient
Assert on the To, CC, and BCC fields to verify delivery targeting.
Subject & body
Check that the subject line and body content match expected templates.
Attachments
Verify that PDFs, CSVs, or images are attached and have correct content types.
Best practices for CI email testing
- Use a dedicated CI inbox — separate from dev and staging inboxes
- Clean up emails before each test run using the API's delete endpoint
- Add a small delay (500ms) between sending and querying — SMTP delivery isn't instant
- Store SMTP credentials in CI secrets, never in code
- Run email tests after unit tests — they're slower and should gate on unit success
Related use cases
Add email testing to your CI
API access available on Hobby tier and above. Set up in under 5 minutes.
Start free →