Skip to content

Why we run our own mail servers

Most email APIs are a layer over someone else's sending service. We chose to run the mail path ourselves. Here is what that means, what it costs, and why we think it is worth it.

By Arin Prajapati, founder, 5 min read

On this page (6)

There are two common ways to build an email product. You can put an API in front of a large sending service and resell its delivery, or you can run the servers that talk SMTP to the rest of the internet. The first is faster to launch. We chose the second, and it shapes nearly everything about Mailbay, including the parts that are slower for us.

What the mail path is

“The mail path” is every hop an email takes between your code and someone else's mailbox, in both directions. In Mailbay, all of it runs on machines we operate:

Mailbay's mail path: receiving on our SMTP servers, sending through our KumoMTAReceivingSendingSender's serverconnects on port 25mx1, mx2our Rust SMTP serverChecksrecipient, SPF, DKIM, spamStored, then 250Postgres and raw .emlYour app or agentAPI, SMTP or MCPcorelimits, suppressions, MIMEKumoMTADKIM, IP pools, warmupRecipient's serverGmail, Outlook, ...delivery logsYour inboxes: API, wait, WebSocket, webhooks, IMAP
Both directions run on servers we operate. Blue is mail coming in, orange is mail going out. Delivery results flow back from KumoMTA to update status and suppressions.
  • Receiving is our own SMTP server, written in Rust. Your domain's MX records point at mx1.mailbay.dev and mx2.mailbay.dev.
  • Sending goes through KumoMTA, an open source mail transfer agent, on IP addresses we control, signed with your domain's DKIM key.
  • Nothing in between is a third party relay. There is no “powered by” provider whose limits, outages or policies sit under ours.

Why own it

Receiving is the product. Mailbay exists for agents and apps that hold conversations over email, so inbound is not a webhook bolted onto a sending API. Owning the SMTP server lets us decide things that a relay decides for you:

  • Mail for an address that does not exist is refused during the SMTP conversation, with 550 5.1.1 No such mailbox here. We never accept a message and bounce it later, which is how servers end up sending backscatter to forged senders.
  • The 250 OK that tells the sender “delivered” is only sent after the message is committed to the database. A crash at the wrong moment means the sender retries, not that mail vanishes.
  • Catch-all addresses on a private subdomain per workspace, plus addressing, and a wait call that wakes the moment the commit lands are all decisions about how the server treats a recipient. We can only make them because we own the server.

Privacy is simpler to promise. Your mail is processed by our servers and stored in our database and object storage. There is no relay provider in the middle that also sees every body. Our subprocessors page lists who does handle data.

One system to debug. When a message is late, the answer is in our logs: the SMTP transcript, KumoMTA's queue and the remote server's reply, which we store per recipient and show you as response, such as 550 5.1.1 no such user.

What it costs

We would rather say this plainly than have you find out:

  • New IPs have no reputation. Gmail, Microsoft and Yahoo trust a sending IP after weeks of steady, wanted mail from it. Until then they throttle it or file mail as spam. A relay provider has already paid that cost; we are paying it now, through the private beta.
  • Hosting is constrained. We need providers that allow outbound port 25 and let us set reverse DNS on every IP. Many cloud providers block port 25 by default and only lift it on request.
  • No fallback. If one of our IPs is blocklisted, we cannot quietly fail over to someone else's network. We need several IPs per pool, monitoring and a delisting runbook instead.
  • It is more work. Queues, retries, bounce handling, TLS on port 25, DKIM key management and feedback loops are ours to run.

How we protect the IPs

Every customer shares the reputation of the IPs they send from, so most of our sending rules exist to keep one bad sender from hurting everyone else:

  • Three IP pools. Free plan mail, paid plan mail and our own mail (sign in codes, alerts) leave from different addresses, so a bad free account cannot touch paying customers' delivery.
  • A separate domain for free inboxes. Free addresses live under mailbay.email, not mailbay.dev, so abuse of free inboxes cannot drag down the domain our own mail comes from.
  • A sandbox until you verify a domain. Without a verified domain, mail from mailbay.email addresses can only reach your own team and our test addresses.
  • A slow start. New accounts send to at most 100 recipients a day for their first 7 days.
  • Suppressions. A hard bounce or a spam complaint adds the address to your suppression list, and later sends to it fail at once with recipient_suppressed.
  • Warmup per mailbox provider. KumoMTA shapes traffic per destination. On day one each IP sends Gmail at most 20 messages an hour, and Outlook.com 10:
infra/kumomta/shaping.toml (week 1)
["gmail.com"]
enable_tls = "Required"
connection_limit = 2
max_connection_rate = "10/min"
max_deliveries_per_connection = 20
max_message_rate = "20/h"

["outlook.com"]
connection_limit = 1
max_connection_rate = "5/min"
max_deliveries_per_connection = 10
max_message_rate = "10/h"

The rates go up week by week, over about six weeks, and only when bounce, complaint and deferral rates over the previous days say they should. Mail over the rate waits in the queue; it is not dropped.

The inbound side

Receiving well is mostly about saying no early and cheaply. Our SMTP server limits connections and commands per IP, refuses unknown recipients at RCPT TO, and caps messages at 25 MB. After the data arrives it checks SPF, DKIM and DMARC, and asks rspamd for a spam verdict: a reject is refused in the SMTP session, likely spam is stored with spam: true, the rest is stored as normal mail. The results ride along on every message as auth_results, so your code or agent can decide what to trust. How those three checks work is in SPF, DKIM and DMARC explained. The same code powers our free email deliverability test, which scores any message you send it.

Where we are today

Mailbay is in private beta, and the beta is also our warmup. That is the honest reason it is invite only: we let volume grow at the pace mailbox providers are willing to trust it. If you need proven, high volume delivery tomorrow, a mature sending service is the safer choice today, and we say so on our Postmark and Resend comparisons. If you are building agents, support inboxes or apps that both send and receive, we would like you in the beta.

Arin Prajapati, founder of MailbayA software engineer in Mumbai who builds Mailbay's mail servers, API and site. More about Arin and why he built Mailbay.

Join the beta

Mailbay is in private beta and free while the beta runs: inboxes, sending, your own domains and MCP. We invite people in small batches and read every note on the form.