mailsac

Mailsac vs Mailpit and MailHog

Mailsac vs Mailpit and MailHog

Hosted email testing for CI, compared with Mailpit and MailHog

Mailpit is a free, self-hosted SMTP catcher. It is the right tool for fast tests that never leave CI. Mailsac is a hosted service that receives the email your app really sends, through your email provider and DNS, and hands it to your tests over a REST API. Most teams should use both. Here is where each fits.

Reviewed September 2026 against Mailpit’s documentation, both projects’ GitHub repositories and Mailsac’s pricing and documentation.

Free plan: an API key, public inboxes, one private address and 1,500 Ops a month, with no expiry. Jump to the full comparison

At a glance

Where it runs

Mailsac Hosted; nothing to install

Mailpit Self-hosted: one binary or a Docker image

Cost

Mailsac Free plan; private domains from $18 a month

Mailpit Free, MIT licence

What a passing test proves

Mailsac The email was delivered through your provider to a real mailbox

Mailpit Your app handed the email to SMTP

Who can read the mail

Mailsac Your team, from anywhere, on private domains; public @mailsac.com inboxes are open to all

Mailpit Whoever can reach the machine it runs on

Maintenance

Mailsac Operated by Mailsac

Mailpit Active (v1.31.3, September 2026). MailHog: last release 2020, last commit 2022

Which should you choose?

They answer different questions. Mailpit answers “did my code produce the right email?” Mailsac answers “did the email reach a real mailbox, through the provider and domain we ship with?” The same test code can ask both.

Choose Mailpit if

  • You want every pull request to run email tests in seconds, with no external service, no secrets and no cost. Mailpit runs as a service container beside your app and accepts anything sent to port 1025.
  • Test mail must never leave your network. Everything stays on the CI runner or your laptop.
  • You want local checks on the message itself: HTML and CSS client-compatibility checks, link checks, SpamAssassin scoring and screenshots, all built in.
  • You are replacing MailHog. Mailpit is actively maintained and its own README describes MailHog as no longer maintained.

Choose Mailsac if

  • You need to prove delivery, not just sending: the staging or production app emails a real address through your provider (SendGrid, SES, Postmark, your own MTA), with the real credentials, sending domain and DNS records, and the message arrives.
  • The thing sending the email is not in your CI job: a deployed environment, a third-party service, a mobile build, or a colleague clicking through a flow by hand.
  • QA, developers and support need to open the same test inboxes from anywhere, without a VPN, with team logins and SAML single sign-on.
  • You want test addresses on a real domain, either your own or a yourteam.msdc.co subdomain, so sign-up forms and third-party services accept them.
  • You do not want to run or secure another service. Mailsac is hosted, and Enterprise plans include vendor security reviews and invoice billing.

Use both: Mailpit per pull request, Mailsac for delivery

Write one test that signs up, waits for the email and follows the link. Run it against Mailpit on every pull request, and against a Mailsac inbox on merges to main, on a schedule, or after a deploy to staging. Only the inbox backend changes.

  1. One interface, two backends. The test calls newAddress(), waitForEmail() and cleanup(). A Mailpit implementation searches GET /api/v1/search?query=to:"…" on localhost:8025; a Mailsac implementation polls GET /api/addresses/{email}/messages with a Mailsac-Key header. INBOX=mailpit picks the first; otherwise the test uses Mailsac.
  2. Pull requests. The mailpit job starts axllent/mailpit as a service container, points the app’s SMTP at it (SMTP_HOST=localhost, SMTP_PORT=1025) and sets INBOX=mailpit. No secrets, sub-second waits.
  3. Delivery checks. On pushes to main, a daily schedule or a manual run, the real-delivery job sets APP_URL to your staging URL (the STAGING_URL variable) and passes MAILSAC_API_KEY and, for private inboxes, MAILSAC_DOMAIN. Playwright signs up on the deployed app, which sends through its real provider, and the same test waits up to a minute for the message to arrive.

Staging must not email real people. If the environment under test has real customer addresses, point its SMTP at Mailsac’s Email Capture (capture.mailsac.com:5587, STARTTLS, SMTP_USER your Mailsac username, SMTP_PASS your API key). Every message is captured into the recipient’s Mailsac inbox instead of being delivered, and your test reads it with the same API. The example repository’s third job, mailsac-capture, runs the test this way on every push and pull request that has the key. Captured mail is public unless you turn on private capture or the recipient is on your custom domain.

Excerpt from .github/workflows/email-tests.yml in the example repository: the mailpit and real-delivery jobs. The mailsac-capture job is omitted here.

  # 1. Every pull request: a local SMTP catcher. Fast, free, nothing leaves CI.
  #    Proves the app sends the right email with a working link and code.
  mailpit:
    runs-on: ubuntu-latest
    services:
      mailpit:
        image: axllent/mailpit:latest
        ports:
          - 1025:1025
          - 8025:8025
    env:
      INBOX: mailpit
      SMTP_HOST: localhost
      SMTP_PORT: "1025"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report-mailpit
          path: playwright-report

  # 3. Real delivery, daily and on main: sign up on your deployed staging app, which sends
  #    through your real email provider (SES, SendGrid, Postmark...) to a Mailsac inbox.
  #    Catches expired provider credentials, DNS/SPF/DKIM problems and blocked sending domains.
  #    Needs MAILSAC_API_KEY and the variable STAGING_URL. A private Mailsac domain
  #    (MAILSAC_DOMAIN) keeps the mail from real signups out of public inboxes.
  real-delivery:
    if: github.event_name != 'pull_request'
    runs-on: ubuntu-latest
    env:
      MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }}
      MAILSAC_DOMAIN: ${{ vars.MAILSAC_DOMAIN }}
      APP_URL: ${{ vars.STAGING_URL }}
    steps:
      - name: Skip when staging is not configured
        id: configured
        run: echo "ok=${{ env.MAILSAC_API_KEY != '' && env.APP_URL != '' }}" >> "$GITHUB_OUTPUT"
      - uses: actions/checkout@v4
        if: steps.configured.outputs.ok == 'true'
      - uses: actions/setup-node@v4
        if: steps.configured.outputs.ok == 'true'
        with:
          node-version: 22
          cache: npm
      - run: npm ci
        if: steps.configured.outputs.ok == 'true'
      - run: npx playwright install --with-deps chromium
        if: steps.configured.outputs.ok == 'true'
      - run: npx playwright test
        if: steps.configured.outputs.ok == 'true'

The complete project, including the test, both inbox backends, the Email Capture job and a GitLab CI version, is at github.com/mailsac/mailsac-integration-test-examples/tree/main/playwright-signup-ci. The CI/CD email testing guide walks through it.

Mailsac vs Mailpit: side by side

MailHog is included where it differs from Mailpit. Mailpit was inspired by MailHog and uses the same default ports, so most of the Mailpit column also describes a MailHog setup, minus the newer features.

Mailsac Mailpit (and MailHog)
Running it
Where it runs Hosted service on AWS in the United States. Nothing to install Self-hosted: a single static binary or the axllent/mailpit Docker image (386, amd64 and arm64). SMTP on port 1025, web UI and API on 8025 by default
Cost Free plan: 1,500 Ops a month, public inboxes, 1 private address. Indie $18 a month (25,000 Ops, 1 custom domain); Business $89 a month (500,000 Ops, 5 users, 5 domains, SSO) Free, MIT licence. You provide the compute and keep it updated
Maintenance Operated by Mailsac Mailpit: active, v1.31.3 released September 27, 2026, 10.5k GitHub stars. MailHog: last release v1.0.1 in August 2020, last commit August 2022, 16.2k stars; Mailpit’s README says it “is no longer maintained”
What the test proves
Path the email takes Your app to your email provider, over the internet, to a Mailsac mailbox at a real domain. Provider credentials, sending domain and SPF/DKIM records are exercised on the way Your app to a local SMTP port. Provider, DNS and deliverability are not involved
Test addresses Any @mailsac.com address (public) or any address on your custom domain (private): your own domain, or a yourteam.msdc.co subdomain with no DNS changes. Nothing to create first Any recipient at any domain, for example user@example.test. Mailpit accepts everything sent to it
Where the mail goes Mailsac’s servers. Public inboxes are readable by anyone; private addresses and custom domains by your account and team Stays on the machine or CI runner running Mailpit
Wait time Seconds to tens of seconds, depending on your provider. Tests poll with a deadline, or receive a push Milliseconds
Reading mail from tests
API REST with a Mailsac-Key header: GET /api/addresses/{email}/messages (newest first, with a links array per message), GET /api/text/{email}/{id}, DELETE /api/addresses/{email}/messages/{id}. Also headers, sanitized and raw HTML, attachments REST on port 8025: GET /api/v1/search?query=to:"…" with filters such as subject:, is:unread and after:; GET /api/v1/message/{ID} returns Subject, Text, HTML and To; DELETE /api/v1/messages with a list of IDs. Link check, HTML check and SpamAssassin endpoints per message
Push instead of polling Webhooks, Slack forwarding and WebSockets for private addresses; whole-domain WebSockets on Business and up Optional webhook on new messages (--webhook-url, rate-limited to 1 a second by default)
Access from Anywhere with an API key: CI, laptops, other services. Web inbox for people Inside the network where it runs: localhost, or the CI job’s service network. Web UI with optional password file
Client libraries @mailsac/api (JavaScript/TypeScript) and the @mailsac/cypress plugin; REST from anything else REST from anything; no official client libraries listed
Beyond receiving
Message checks Links extracted per message; no rendering or spam scoring HTML and CSS client-compatibility check, link check, SpamAssassin check (needs a SpamAssassin server), screenshots, List-Unsubscribe validation
SMTP capture from other environments Email Capture on every plan: any app can send to capture.mailsac.com:5587 with your username and API key; mail is captured, never delivered Any app that can reach the Mailpit host can send to port 1025. Optional SMTP authentication, STARTTLS with your own certificate, and relay of selected messages to a real SMTP server
Retention Public inboxes: temporary. Private addresses and domains: stored-message limit per plan, 50 on Free, 1,000 on Indie, 5,000 on Business, 10,000 on Business+ 500 messages by default (--max); in memory unless you set --database
Team and buying Users per plan, SAML single sign-on on Business and up, invoice or purchase order on annual Business+ and Enterprise, security questionnaires on Enterprise Single web UI; no accounts, roles or vendor. Your own security review covers it

Reviewed September 28, 2026. Mailpit facts are from its documentation and README at the version shown; MailHog dates are from its GitHub repository. Check each project’s current documentation before you rely on a detail.

Sources: Mailpit site, README, runtime options, search filters, API and Docker. MailHog repository. Mailsac pricing, API reference, custom domains and Email Capture.

Frequently asked questions

Can Mailsac replace Mailpit?

Not for the per-pull-request job, and it should not try to. Mailpit is faster, free and needs no secrets. Mailsac replaces the part Mailpit cannot do: proving that the deployed app, with its real provider and domain, delivers mail to a real mailbox. Keep Mailpit for pull requests and add Mailsac for delivery checks.

Is MailHog still maintained?

Its GitHub repository is not archived, but the last release is v1.0.1 from August 2020 and the last commit is from August 2022. Mailpit’s README describes MailHog as no longer maintained and without security updates for a few years. If you are on MailHog, Mailpit is the usual replacement for the local job.

Do I need to change my app to use Mailsac?

No. Your app sends email the way it already does. The test uses a recipient address at mailsac.com or on your custom domain, then reads the message over the API. If a staging environment must not email real people, point its SMTP settings at Email Capture instead of the provider; that is a configuration change, not a code change.

What does the Mailsac layer cost?

Each received message, API call and push counts as one Op. A test that polls for its email typically uses 3 to 6 Ops. The free plan includes 1,500 a month with public inboxes; Indie ($18 a month) includes 25,000 Ops and a private domain; Business ($89) includes 500,000. A delivery check that runs a handful of tests on each merge fits comfortably in Indie.

Can other people read my test email on Mailsac?

Mail to @mailsac.com addresses is public: anyone can open the inbox on the website. Use those only with made-up data. Mail on a private address or a custom domain (yourteam.msdc.co or your own domain, on Indie and up) is visible only to your account and team. Captured mail follows the same rule: private when capture is set to private or the recipient is on your domain.

Can I self-host Mailpit and still share inboxes with QA?

Mailpit has a web UI, so you can host it somewhere your team can reach and protect it with its password file. You then own the hosting, TLS, access control and upgrades. Mailsac does that for you, with team logins and SAML single sign-on on Business, which is the trade-off this page is about.

Is there a Playwright or Cypress example?

Yes. The CI example repository runs one Playwright test against both Mailpit and Mailsac in GitHub Actions and GitLab CI. The Playwright tutorial covers codes, links and password resets, and the @mailsac/cypress plugin does the waiting and code extraction for Cypress.

Add a delivery check to your pipeline

Keep Mailpit on your pull requests. Create a free Mailsac account, add an API key to CI, and run the same test against a real inbox on every merge.

Comparing hosted services? Read Mailsac vs MailSlurp, Mailsac vs Mailosaur and Mailsac vs Mailtrap. New to Mailsac? See how the email testing API works.