MailKite
Start free
All posts
Gabe 12 min read

Why we built free programmable email for developers

The path most of us walk is SES, then SendGrid, then Resend — each one fixes the last one's pain, and each one meters the thing a serial shipper does most: another domain, another project, another teammate. So we built MailKite (which we build) to meter only one thing — email volume — with unlimited domains, mailboxes, and teammates, and 3,000 messages a month free. Set it up once, reuse it on every project you launch, pay only when one takes off.

The reason isn’t that the other tools are bad. They’re good — we reached for every one of them before we built ours. The reason is that their pricing is metered on the axis that hurts the way developers work now: you don’t ship one app and scale it, you ship ten market tests a year and hope one lands. Every one wants its own domain, its own sending identity, sometimes its own teammate. Here’s the same pipeline priced two ways — by what you build, or by what you send.

Metered by what you build Amazon SESsandbox + per-region setup tax SendGridfree plan retired · teammates gated Resend1 domain free → 10 → 1,000 Each new project is a new domain, maybe a new seat, sometimes a new setup — and the meter moves before you send a single email. Metered by what you send MailKite unlimited domains · unlimited mailboxes · unlimited teammates 3,000 messages/mo free, then metered per 1,000 — the meter only moves when a project takes off
The same email, priced on two different axes. Competitors meter the counts a serial shipper runs up — domains, seats, setup. MailKite meters only volume.

Here’s the punchline in code. One API key, three products on three domains, no plan change between them — because domains aren’t the billed axis:

// one-key.mjs — runs as pasted on Node 18+ (npm install mailkite)
import { MailKite } from "mailkite";

const mk = new MailKite(process.env.MAILKITE_API_KEY); // one key, every project

// three different products, three domains you own, one free account.
// no "add a domain" upsell, no per-seat plan — the only meter is volume.
await mk.send({ from: "hello@side-project-a.dev", to: user.email, subject: "Welcome",  html });
await mk.send({ from: "team@startup-b.io",        to: user.email, subject: "Your code", html });
await mk.send({ from: "noreply@weekend-test-c.app", to: user.email, subject: "Ping",   html });

The full send-and-receive version — including the inbound webhook, so replies come back to each project — is in the runnable demo repo, demo-programmable-email; open it in StackBlitz and send from three domains in your browser tab. The rest of this post is the honest version of the diagram: where each tool we left genuinely wins, and why the billing axis was the thing we couldn’t fix from the outside.

The walk most of us take: SES, then SendGrid, then Resend

Almost every developer I know arrives at the same three stops, in the same order, for the same reasons.

  • You start on SES because it's ten cents per thousand emails and it's already in your AWS bill. Then you hit the sandbox: a new account can only mail verified addresses, capped at 200 messages per 24 hours at one per second, and that status is per region. Production access is a manual review with no SLA, and a rejection tells you "for security reasons" it can't say why. It bites the week you launch.
  • So you move to SendGrid for a real API and a dashboard. Except Twilio retired SendGrid's free Email API plan on May 27, 2025 — new accounts get a 60-day trial, then it's $19.95/mo to keep sending. And the Essentials plan includes exactly one teammate; collaborators and subusers live further up the ladder.
  • So you move to Resend — and honestly, it's the nicest developer experience of the three. Clean API, React email, great docs. Then you ship your second project. The free tier is one domain. Pro ($20/mo) is ten. Scale ($90/mo) is a thousand. The DX is lovely; the axis is domains.

None of that is a knock. SES really is the cheapest way to push volume. SendGrid really did have to make money. Resend really is a joy to write against. The problem is structural, and it’s the same problem three times: the meter is attached to a count that a developer shipping many small things runs up fast — domains, seats, setup — long before any single project sends enough email to matter.

Free-tier contractions are why anyone switchesNobody migrates email for fun. They migrate the month a free tier disappears (SendGrid, May 2025) or a per-domain wall lands in front of their second staging environment. The permanence of a free tier is itself a feature — so we wrote ours down and meant it.

The way developers actually work now

Ten years ago you built one product and grew it. Now the median indie hacker or small team runs a portfolio: a weekend build, a paid experiment, a client’s MVP, three landing pages testing a wedge. Agentic tooling made this worse (better?) — you can scaffold a deployable app in an afternoon, so people do, constantly. Every one of those needs to send a welcome email, a magic link, a receipt. Every one wants to send from its own domain so the mail isn’t from noreply@some-vendor.com.

On a per-domain or per-seat model, that portfolio is expensive before it earns a cent. On a volume model, it’s free until something works.

one free accountone API key side projecta.devfree startupb.iopaid — it took off client MVPc.appfree landing testfree Four domains, four projects, one account. On a per-domain plan you'd be paying for all four. You pay for the one that took off, not for the three you tried.
A portfolio on one free account. Every project gets its own domain and its own inbox; only the one that crosses 3,000 messages a month starts paying.

What MailKite meters, and what it doesn’t

We picked the one axis that actually costs us money and left everything else alone. Domains, addresses, and teammates are near-zero marginal cost, so they’re unlimited on every plan including Free. Volume is the real cost, so volume is the meter.

What it costs on MailKite
DomainsUnlimited, every plan. No per-domain fee, ever.
Mailboxes / addressesUnlimited per domain. One inbox per agent, customer, or thread if you want.
TeammatesUnlimited. Collaborators on your account aren’t a seat you buy.
Inbound + outboundOne shared quota. Received and sent mail count once each, together.
The meterEmail volume. 3,000 messages/mo free, then metered per 1,000 — no hard cut.

The Free plan is 3,000 messages a month across inbound and outbound. That’s roughly a hundred a day — comfortably more than a portfolio of pre-traction projects sends combined, and when one of them crosses the line, you soft-pause with notice, not a surprise bill or a silent ban. Cross it on a paid plan and overage is metered at the plan’s per-1,000 rate; nothing stops mid-send. The pricing page has the exact numbers and the “what we count and why” breakdown.

Where I won’t overclaim

Two honest caveats, because a post with only upsides is an ad. First: at real volume, SES is cheaper per email than we are, and I won’t pretend otherwise — if you’re pushing millions of transactional messages a month and you have AWS muscle in-house, its unit economics are hard to walk away from. Our bet is that most developers shipping most projects are nowhere near that line, and for them the setup tax and the per-region sandbox cost more than the ten cents ever saved. Second: Resend’s developer experience is genuinely excellent, and if you truly only ever run one product on one domain, its free tier fits you and you may never feel the wall. MailKite’s pitch is specifically for the person running many things: the set-it-up-once account you reuse on every launch, where adding the eleventh domain or the second teammate doesn’t change your bill. We built it because we were that person, paying per-domain for a graveyard of experiments.

FAQ

Is MailKite really free for multiple domains? Yes. Every plan, including Free, has unlimited domains with no per-domain fee. The Free plan’s only limit is volume — 3,000 messages a month across inbound and outbound. Spin up a domain per project and you pay nothing until one project’s email volume crosses the line.

How is this different from Resend’s free tier? Resend’s free tier is one domain, 3,000 emails a month, capped at 100 a day; more domains come with paid plans (10 on Pro at $20/mo, 1,000 on Scale at $90/mo). MailKite’s free tier is unlimited domains and unlimited mailboxes with a 3,000 messages/month quota that covers both inbound and outbound, and no daily cap. If you run one product forever, Resend’s tier is fine; the difference shows up on your second and tenth project.

Does MailKite charge per teammate or per seat? No. Collaborators on your account aren’t a billed seat. The only thing metered is email volume. (Hosted webmail mailboxes, when you want a full mailbox with a login and storage, are a separate per-seat add-on — that’s a human with a 10 GB inbox, not a developer with dashboard access.)

What happens when a project takes off and crosses 3,000 messages? On Free, delivery soft-pauses with notice and a one-click upgrade — mail is never lost. On a paid plan, overage is metered at the plan’s per-1,000 rate with no hard cutoff. You pay for the project that grew, not for the ones that didn’t.

Is the free tier permanent, or is this a trial? It’s a plan, not a trial. There’s no 60-day clock and no card required to start. We wrote “unlimited domains, no per-domain fees, ever” on the pricing page precisely because free-tier contractions are the thing that makes developers distrust email vendors, and we didn’t want to be the next one.


If you’re paying per domain for a portfolio of experiments, or you just watched a free tier evaporate, there’s a simpler shape: one account, unlimited domains, metered only when something works. Clone demo-programmable-email (or run it in your browser), then point a domain at MailKite and send from your next three projects on one free key.

Related: email you set up once and reuse for every project, the Amazon SES alternative for developers, and our pricing, and what we count and why.

Discuss this post: Hacker News Share on X

Related posts