The invoice stops being a surprise
Their subscription pays for features; messages are billed on top. While the volume is low it is the fairer model; the day the suite runs on every commit, nobody knows what the month will cost.
Migration
Volume included in the subscription rather than an invoice you discover at the end of the month, per-inbox quotas, and data that stays in France. Here is what switching changes in your tests, line by line.
Migrating from MailSlurp does not change the shape of your tests: both APIs wait for the message, and that is what they got right. There is simply one inbox less to create, and no code left to extract from the body.
What switching changes is the invoice: volume included in the subscription and packs valid for a year, known in advance, instead of usage billed after the fact.
Their subscription pays for features; messages are billed on top. While the volume is low it is the fairer model; the day the suite runs on every commit, nobody knows what the month will cost.
A ceiling per inbox and an alert threshold: a runaway test stops on its own quota instead of eating the whole organisation’s capacity.
Every inbox owns its subdomain, and any address ending in it is accepted from the first message. No inbox to create at the start of a test, none to delete at the end.
Body, headers, links and one-time code are extracted on reception. What your tests wrote as regular expressions is already done.
Both APIs wait for the message rather than leaving your suite to wait for it: that is what MailSlurp got right, and we did not try to do it differently. What changes comes down to two things: there is no inbox to create, and no code left to extract.
createInbox() + waitForLatestEmail() → messages.waitFor()
const mailslurp = new MailSlurp({ apiKey: API_KEY });
// One inbox per test, to create and then to clean up.
const inbox = await mailslurp.createInbox();
await signUp(inbox.emailAddress);
const email = await mailslurp.waitForLatestEmail(
inbox.id, 30_000,
);
const code = email.body.match(/\b\d{6}\b/)?.[0];import { Facteur } from '@facteur-eu/sdk';
const facteur = new Facteur({ apiKey: process.env.FACTEUR_API_KEY });
// The address already exists: nothing to create, nothing to clean up.
const address = `signup-${Date.now()}@${inbox.domain}`;
await signUp(address);
const message = await facteur.messages.waitFor({
inbox: inbox.id, sentTo: address, wait: 30_000,
});
const code = message.otp;The MailSlurp code above follows their own published example; the sources are at the foot of this page. Ours runs as written.
The API correspondence is one line per call, and the migration goes file by file, both services running side by side until the suite is green.
The address already exists: every inbox owns its subdomain and accepts any address ending in it. The createInbox() at the top of each test goes, and the cleanup at the end goes with it.
The wait keeps its shape: waitForLatestEmail(inboxId, timeout) becomes messages.waitFor({ inbox, sentTo, wait }): the same blocking call, the same timeouts, one more parameter to target the address.
The one-time code arrives in message.otp, with the body, headers and links already parsed: the regular expression that dug through the body has nothing left to do.
Nothing is transferred: test messages regenerate on the next run. Keep both accounts until everything is green.
| Facteur | MailSlurp | |
|---|---|---|
| Billing model | Volume included, then stacking packs | Subscription + usage as you go |
| Predictable invoice | Known in advance | Varies with the month’s usage |
| Volume included in the subscription | Yes, by plan | No, billed separately |
| Per-inbox quotas | Yes, with overage alerts | Not documented |
| SAML SSO | Included from the Team plan | On higher tiers |
| Hosting | France, billed in euros | Outside France, billed in dollars |
| DPA | Downloadable online | On request |
The correspondence is one line per call: createInbox() goes, waitForLatestEmail() becomes messages.waitFor(), and extracting the code becomes reading a field. The migration goes file by file, both services running side by side, and there is nothing to transfer: test messages regenerate.
Yes, as soon as your test suites run regularly in CI. Because MailSlurp bills messages on top of the subscription, monthly invoices fluctuate unexpectedly. Facteur includes generous volume directly in plans, provides 1-year stacking capacity packs, and offers unlimited inboxes from the Team plan.
A Facteur capacity pack is bought up front, valid for 12 months, stacks with others, and is never lost on a downgrade. Pay-as-you-go computed afterwards fluctuates every month. The first model guarantees complete budget predictability for your team.
MailSlurp requires calling createInbox() at the start of every test and cleaning it up after. With Facteur, each inbox owns a subdomain accepting any address on the fly. You eliminate setup/teardown boilerplate, lower execution latency, and the one-time code arrives already extracted, in the API response, with no package to install.
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.