Skip to main content

Treat Inboxes Like Microservices, Not Mailboxes

· 6 min read
Co-founder, mailbot

Most developers think of an inbox as a place where email collects. A container. Something you open, scroll through, and close. That mental model works for humans. It breaks completely for software.

When you're building automated systems that send and receive email, an inbox isn't a container. It's a boundary. A unit of isolation. A primitive that defines who can send, who can receive, what domain the messages come from, and how many messages can go out per day.

The moment you start thinking of inboxes this way, your architecture changes.

The Shared Inbox Problem

Here's how most teams start. They create one email address for their application. Maybe it's notifications@company.com or support@company.com. Every workflow in the system shares that address. Onboarding emails, password resets, support replies, invoice notifications, marketing drips. All from the same sender. All landing in the same place.

This works until it doesn't. And it stops working faster than most teams expect.

A customer marks one of your marketing emails as spam. That complaint doesn't just affect marketing. It affects the reputation of the entire sending address. Now your password reset emails are landing in spam folders too. Your support agent's automated replies are getting filtered. Your onboarding flow is broken. One workflow's reputation problem has cascaded into every other workflow because they all share the same identity.

This is the email equivalent of running your entire backend as a single monolithic process. It works at small scale. It becomes a liability the moment anything goes wrong.

Inboxes as Isolation Boundaries

The fix is the same pattern that solved the monolith problem in backend architecture: decomposition. Instead of one inbox shared across your entire system, you create a dedicated inbox for each workflow that needs its own email identity.

In mailbot, creating an inbox is a single API call.

import { MailBot } from '@yopiesuryadi/mailbot-sdk';
const mailbot = new MailBot({ apiKey: 'mb_your_api_key' });

const onboarding = await mailbot.inboxes.create({
username: 'onboarding',
domain: 'yourdomain.com',
display_name: 'Welcome Team',
daily_send_limit: 500,
permissions: ['send'],
});

const support = await mailbot.inboxes.create({
username: 'support',
domain: 'yourdomain.com',
display_name: 'Support',
daily_send_limit: 1000,
permissions: ['send', 'receive', 'search'],
});

Two inboxes. Two isolated identities. The onboarding inbox can only send (no inbound). The support inbox can send, receive, and search. Each has its own daily send limit. If onboarding hits its limit or gets a complaint, support is unaffected. Their reputations are independent. Their rate limits are independent. Their event streams are independent.

This is what "programmable inbox" means. Not an inbox you can read with code. An inbox you define with code.

What Each Inbox Actually Controls

Every inbox in mailbot is a self-contained unit with its own configuration:

Address. Each inbox gets a unique email address on your verified domain. onboarding@yourdomain.com and support@yourdomain.com are separate senders with separate identities. mailbot handles SPF, DKIM, and DMARC for the domain, so every inbox on that domain inherits proper authentication.

Permissions. You control what each inbox is allowed to do. An inbox with ['send'] permissions can only send outbound email. It cannot receive. An inbox with ['send', 'receive', 'search'] is a full two-way communication channel. This is enforced at the API level. If code tries to send from an inbox that only has receive permissions, the request fails.

Send limits. Each inbox has its own daily send limit, configurable from 1 to 10,000. This isn't a global account limit split across inboxes. Each inbox tracks its own count independently. Your transactional inbox can send 5,000 emails per day while your notification inbox is capped at 200.

Thread isolation. Messages and threads are scoped per inbox. When you list threads for the support inbox, you only see support conversations. When you query the onboarding inbox, you only see onboarding messages. There's no cross-contamination.

Status control. Each inbox can be independently set to active, disabled, or suspended. Disable the marketing inbox without touching support. Suspend a compromised inbox without affecting any other workflow.

The Microservice Analogy

This pattern maps directly to how developers think about services.

A microservice has a clear boundary. It owns its data. It has its own scaling rules. It can fail independently without taking down the rest of the system. It communicates through well-defined interfaces.

A programmable inbox has the same properties. It owns its messages and threads. It has its own rate limits. It can be disabled independently. It communicates through a well-defined API. The only difference is the transport layer. Instead of HTTP or gRPC, the interface is email.

This isn't a metaphor. It's an architectural pattern. When you decompose your email infrastructure into purpose-built inboxes, you get the same benefits that microservice decomposition gives you for compute: fault isolation, independent scaling, clear ownership, and operational clarity.

What This Looks Like in Practice

A typical production setup might have five or six inboxes:

from mailbot import MailBot
mailbot = MailBot(api_key="mb_your_api_key")

# Each inbox serves one purpose
inboxes = {
"onboarding": {"permissions": ["send"], "limit": 500},
"support": {"permissions": ["send", "receive", "search"], "limit": 1000},
"notifications": {"permissions": ["send"], "limit": 5000},
"billing": {"permissions": ["send", "receive"], "limit": 200},
"testing": {"permissions": ["send", "receive", "search"], "limit": 50},
}

for name, config in inboxes.items():
mailbot.inboxes.create(
username=name,
domain="yourdomain.com",
permissions=config["permissions"],
daily_send_limit=config["limit"],
)

Each inbox maps to a responsibility. Onboarding sends welcome sequences. Support handles two-way customer conversations. Notifications sends system alerts. Billing handles invoice emails and payment confirmations. Testing is a low-volume sandbox for development.

When you open mailbot's console, you see each inbox separately. Its message count, thread count, send volume, and engagement metrics are all scoped to that specific inbox. You don't have to mentally filter through a combined stream of unrelated messages. Each inbox tells its own story.

Shared Domain, Separate Identities

One thing developers worry about is DNS complexity. If each inbox needs its own domain, the overhead becomes unmanageable.

mailbot solves this with domain-level verification. You verify your domain once. SPF, DKIM, and DMARC records are set at the domain level. Every inbox on that domain automatically inherits those authentication records. You can have twenty inboxes on yourdomain.com and maintain a single set of DNS entries.

For development and testing, mailbot provides a shared domain so you can create inboxes without configuring DNS at all. Move to your own domain when you're ready for production.

The Principle

When every workflow shares one inbox, a problem in one workflow becomes a problem in every workflow. When each workflow owns its inbox, problems are contained. Debugging is scoped. Reputation is isolated. Rate limits are independent.

The shift from "one inbox for everything" to "one inbox per concern" is the same shift the industry made from monoliths to microservices. It's not about having more inboxes. It's about having the right boundaries.

mailbot makes those boundaries a first-class primitive. Not something you simulate with filters and forwarding rules. Something you define in code, enforce at the API level, and operate with full visibility.