# Mailboxes as Cattle: Ephemeral Email Infrastructure

> Source: <https://dev.to/qasim157/mailboxes-as-cattle-ephemeral-email-infrastructure-4f3k>
> Published: 2026-06-16 21:39:53+00:00

When was the last time you deleted an email account on purpose?

For most teams the answer is never, and that tells you something. We treat mailboxes the way we treated servers in 2008: hand-built, carefully named, kept alive indefinitely because recreating one is painful. They're pets. Meanwhile every other piece of our infrastructure — compute, queues, databases — became cattle: numbered, provisioned by code, destroyed without sentiment when the job ends.

Email is finally catching up. With Nylas Agent Accounts (in beta), a mailbox is created with one call and destroyed with another, and that symmetry is the whole point.

Provisioning, from the CLI:

```
nylas agent account create signup-agent@agents.yourdomain.com
```

Or via `POST /v3/connect/custom`

with `"provider": "nylas"`

— no OAuth, no refresh token, just an address on a domain you've registered. Teardown is equally unceremonious:

```
nylas agent account delete signup-agent@agents.yourdomain.com --yes
```

(The API equivalent is a `DELETE`

on the grant.) The [signup automation recipe](https://developer.nylas.com/docs/cookbook/agent-accounts/sign-up-for-a-service/) treats this as a loop: provision a fresh inbox, point a third-party signup form at it, catch the verification email through a `message.created`

webhook, follow the confirmation link, delete the grant. No human inbox involved at any step, and nothing left behind.

The middle of that loop is about twenty lines of webhook handler, and the recipe's version filters hard before acting — right grant, right sender, right URL shape:

```
const { grant_id, id: messageId, from } = event.data.object;
if (grant_id !== AGENT_GRANT_ID) return;

const sender = from[0]?.email ?? "";
if (!sender.endsWith("@saas-you-care-about.example.com")) return;

const match =
  /https:\/\/saas-you-care-about\.example\.com\/confirm\?token=[^"\s<]+/.exec(
    message.body,
  );
if (match) await fetch(match[0]);
```

Nylas fires `message.created`

within a second or two of mail arriving, so the whole signup round-trip typically finishes before a human would have found the email.

The one-time pet in this story is the *domain*, not the mailbox. You register a domain once per organization — picking a US or EU data center region — publish the MX and TXT records, and then mint as many addresses under it as your plan allows. Trial `*.nylas.email`

subdomains skip even that for prototyping. See [provisioning and domains](https://developer.nylas.com/docs/v3/agent-accounts/provisioning/) for the flow.

**Per-run test inboxes.** E2E tests that assert on real email delivery have always been awkward — shared test accounts accumulate state, and yesterday's run pollutes today's assertions. A fresh mailbox per CI run resets the world. The signup recipe's advice applies directly: if you're running a large test matrix, provision multiple grants rather than reusing one, because quotas are per account — 200 messages per account per day on the free plan.

**Per-workflow identities.** A research agent that needs a developer account on a data source, a QA bot that registers for a SaaS every run, a purchasing agent that needs a marketplace profile. Each gets an address, does its job, and gets reaped.

**Per-environment separation.** The provisioning docs describe running `agents.staging.yourcompany.com`

and `agents.yourcompany.com`

in the same application, so staging traffic never touches the production domain's reputation.

**Per-customer pools.** Sender-reputation isolation by splitting volume across `sales-a.yourcompany.com`

, `sales-b.yourcompany.com`

, and so on — a deliverability problem on one domain doesn't contaminate the rest.

Disposable doesn't mean unmanaged — arguably the opposite. Two practices from the docs are worth treating as non-negotiable.

First, **reap your herd**. The recipe is blunt: don't ship per-run agents without teardown, because inactive grants accumulate. Delete on completion *or failure* — the failure path is where orphans come from. If your CI provisions a mailbox, the cleanup step belongs in a `finally`

block, not at the happy-path end.

Second, **fence the inbox**. A disposable address that leaks into a spam list keeps receiving junk until you delete it. Pair an allowlist of expected sender domains with a `block`

rule for everything else, so the inbox only accepts mail from the service you're actually testing against. And don't trust the first message that arrives — some services send a "Welcome" email before the verification email, so match the sender *and* the expected URL pattern before your code clicks anything.

Third, **fence the herd, not the animals**. Per-account configuration defeats the point of cattle. Workspaces fix that: pass a `workspace_id`

when you create the grant — or let `auto_group`

place accounts into a workspace by matching their domain — and attach a policy there once. Every disposable mailbox inherits the same send quota, retention window, and block rules with zero per-account setup, and moving an account later is a single `PATCH`

on the grant.

One more option if humans occasionally need to peek inside a longer-lived account: set an `app_password`

at creation (18–40 printable ASCII characters, with an uppercase letter, a lowercase letter, and a digit) and connect a normal IMAP client. Nylas stores it as a bcrypt hash, so you can't retrieve it later — only reset it. Skip it for true cattle; protocol access stays disabled by default.

Here's where the metaphor honestly breaks down. A container's identity doesn't matter; an email address's identity *is* the product in some workflows. An address that customers know, that's whitelisted in their systems, that has months of threading history — that's a pet, and it should be. Reputation also accrues over time: a brand-new address sending cold outreach behaves differently from an established one.

So the pets-vs-cattle question for email isn't "which model is right" but "which mailboxes are which." My rule of thumb: if a human would notice the address changing, it's a pet. If only your code ever reads it, it's cattle — and keeping cattle alive out of habit is just unmanaged inventory.

Audit your own herd this week: list every automation-owned mailbox your team has, and ask of each one, "if this were deleted tonight, what breaks?" If the answer is "nothing," you've found your first candidate for a teardown script. How many pets are you feeding that should've been cattle?
