The mail comes from somewhere other than your code
An identity provider, an SMS gateway, a partner: as soon as a message leaves a machine you do not control, it needs a public address. A Mailpit on the CI network does not give it one without work.
Migration
Mailpit is free and excellent on a developer’s machine. This page is not trying to talk you out of it: it describes what happens when the same tests have to run in continuous integration, across a team, and receive mail from outside.
Mailpit is free, open source, starts with one command and lets no data leave your machine: on a developer’s workstation, keep it. Migration becomes the question in continuous integration, when pipelines have to share inboxes, read back yesterday, and receive mail from outside.
The switch translates no SDK: Mailpit is queried over HTTP. It removes the service running beside your tests, and the code left to extract from message bodies.
An identity provider, an SMS gateway, a partner: as soon as a message leaves a machine you do not control, it needs a public address. A Mailpit on the CI network does not give it one without work.
Each run starts its container, receives its messages and takes them away when it stops. Sharing an inbox between two pipelines, or reading back what arrived yesterday, means building a service: the one you were avoiding.
Free is not the same as costless: the machine, its monitoring, its upgrades, and the person fetched the day it falls over while the pipeline waits.
One-time-code journeys often go by SMS. Mailpit only does email; here the text message lands in the same inbox and is read with the same call.
There is no SDK to translate here: Mailpit is installed and queried over HTTP. What changes is not the shape of the call: there is no longer a service to run beside your tests, and no code left to extract from the body.
docker compose + GET /api/v1/messages → messages.waitFor()
services:
mailpit:
image: axllent/mailpit
ports: ['1025:1025', '8025:8025']
# then, in the test, once the service is ready:
# const r = await fetch('http://localhost:8025/api/v1/messages');
# const { messages } = await r.json();
# const code = messages[0].Snippet.match(/\b\d{6}\b/)?.[0];import { Facteur } from '@facteur-eu/sdk';
const facteur = new Facteur({ apiKey: process.env.FACTEUR_API_KEY });
// No service to start, no port to wait for.
const message = await facteur.messages.waitFor({
inbox: INBOX_ID,
sentTo: address,
wait: 30_000,
});
const code = message.otp;The Mailpit API paths are those of its published specification; the sources are at the foot of this page. Worth repeating: Mailpit is free, and for local development it remains the better choice.
There is no SDK to translate: the switch removes a service from the pipeline rather than rewriting tests.
The inbox is hosted and its addresses are public: it receives mail from anywhere, including services you do not control: an identity provider, an SMS gateway.
The container, its ports and its readiness wait leave the pipeline. There is nothing left to start before the tests, and nothing to watch during them.
Reading /api/v1/messages and sorting the array become messages.waitFor(), which blocks until the right message arrives and hands back the code already extracted.
Many teams keep Mailpit on the development machine and migrate only continuous integration: the two uses take nothing from each other.
| Facteur | Mailpit | |
|---|---|---|
| Software cost | Subscription | Free, MIT licence |
| To operate | Nothing, a hosted service | A server, its monitoring, its upgrades |
| Sharing across pipelines | Yes, shared and partitioned inboxes | Build it yourself |
| Receiving from outside | Yes, public addresses | Local network only, unless exposed by hand |
| Retention and history | 3 to 60 days by plan | Whatever you configure, on your disk |
| Accounts, roles, SSO | Yes | No |
| SMS | Yes | No, email only |
Mailpit costs nothing to install. What it costs is elsewhere: the machine that runs it, its monitoring, its upgrades, and the time of whoever looks after it the day it falls over while the pipeline waits.
Mailpit is great locally but struggles in CI/CD: no public addresses accessible by third parties (OAuth, Stripe, SMS OTP), no inbox sharing across multiple pipelines, and no team management or SSO. Facteur eliminates server maintenance overhead and provides unified email + SMS testing hosted in France.
Little, since there is no SDK: the call to /api/v1/messages becomes messages.waitFor(), the code extraction goes, and the container leaves the compose file. The most visible part of the switch is what leaves the pipeline, not what gets written.
Yes! You can keep Mailpit locally for quick offline iterations, while using Facteur in your CI/CD pipelines where stability, history, inbox sharing, and real email/SMS reception are required.
Mailpit is its de facto successor; the MailHog repository is no longer actively maintained. If you are still on MailHog, this page applies in the same way, migration included.
Other comparisons: Mailisk · Mailtrap · MailSlurp · Mailosaur
The free plan asks for no card. If you are switching tools, the steps fit on one page and can be tried on a single test.