---
title: Mailboxes
description: "Connect sender accounts, providers, and how they are assigned to workers."
---

A mailbox is a sender account you connect to Warmbly. Every warmup message and campaign email goes out through one you own.

## Connecting an account

Open **Accounts** and choose **Add account**.

| Provider | Method | Notes |
|----------|--------|-------|
| Gmail / Google Workspace | OAuth (`gmail`) | Recommended. No password stored. Sends and syncs over the Gmail API |
| Outlook / Microsoft 365 | OAuth (`outlook`) | Recommended. No password stored. Runs on Microsoft Graph |
| Any other server | IMAP + SMTP (`smtp_imap`) | Custom domains, self-hosted, or providers without OAuth |

**OAuth** sends you to your provider's consent screen and returns a token instead of a password. Both OAuth providers use the provider's native API, never IMAP or SMTP, so consent asks to send mail and to read and organize your mailbox. It needs no app passwords or server settings. Note that Google revokes Gmail tokens when the account's password changes, so a password change there means [re-authorizing the mailbox](#reconnecting-an-account) once.

**IMAP / SMTP** needs host, port, username, and password for each direction:

```text
SMTP   host: smtp.yourprovider.com   port: 465   username: you@yourdomain.com
IMAP   host: imap.yourprovider.com   port: 993   username: you@yourdomain.com
```

Each side also has a **security** setting, which is what decides how the connection is encrypted:

| Security | What happens | Usual ports |
| --- | --- | --- |
| SSL / TLS | Encrypted from the first byte | SMTP `465`, IMAP `993` |
| STARTTLS | Connects in the clear, then upgrades in place before anything sensitive is sent | SMTP `587` or `2525`, IMAP `143` |

The form picks the right one from the port as you type, so standard setups need no thought. Change it yourself when your server is unusual: any port from 1 to 65535 works, so a submission relay on `2525` or IMAP on a custom port is fine as long as the security setting matches what the server actually speaks. Encryption itself is not optional; Warmbly will not send credentials over an unencrypted connection.

If a mailbox fails to connect with a server-unreachable error and the host and port are definitely right, the security setting is the first thing to check. A server expecting STARTTLS looks unreachable to a client attempting implicit TLS, and vice versa.

With two-factor authentication on, generate an app password in your provider's security settings and use that.

<Callout type="warn" title="Authentication runs on connect">
  Credentials and both connections are validated when you add the account, so wrong settings fail immediately rather than silently at send time. Tokens and credentials are sealed with envelope encryption before they touch storage.
</Callout>

## Mailbox allowance

Mailboxes are unlimited on every paid plan. What keeps that honest is a fair-use allowance derived from the plan's sending volume: one mailbox for every send a day the plan includes.

| Plan | Sends per day | Mailboxes |
| --- | --- | --- |
| Free workspace | none | `10` |
| Starter | `150` | `150` |
| Grow | `3,000` | `3,000` |
| Business | `15,000` | `15,000` |
| Enterprise | custom | as many as the volume needs |

That is deliberately far more than safe sending ever needs: at the recommended `30` to `50` sends a day per mailbox, a Business workspace fills its volume with a few hundred mailboxes and still has room for tens of thousands. The allowance exists so that it is never the reason to run a mailbox hotter. A plan whose daily sends are uncapped holds unlimited mailboxes, and a self-hosted instance without billing never counts.

The connect dialog shows the allowance up front: a quiet count while there is room, a warning near the cap, and a clear full state that leads to the request flow instead of letting you type credentials that would be refused. When a connect is refused the answer is the same dialog, not an error toast.

**Getting more.** Two paths, both in the dialog:

- **Move to a bigger plan.** The dialog names the next plan and how many mailboxes it holds; the change is prorated and takes effect immediately.
- **Request an increase.** Keep your plan and ask for a higher allowance with a sentence on what you are sending. An operator reviews it, usually within a business day, and the new allowance applies to the workspace straight away. The dialog shows the open request while it is pending and lets you withdraw it. History lives under **Settings > Limits**.

Nothing is ever removed for being over the allowance. A workspace that moves to a smaller plan keeps every mailbox sending and warming; it simply cannot add more until it is back under, or the allowance is raised.

There is no daily cap on how many mailboxes you connect: a Business workspace can connect thousands in one afternoon, and the [bulk import](#connecting-many-mailboxes-at-once) exists for exactly that.

## Connecting many mailboxes at once

Pick **Bulk import from CSV** in the connect dialog to connect any number of SMTP and IMAP mailboxes from one file. Gmail and Outlook mailboxes sign in one at a time, because each needs its own consent.

**The file.** One mailbox per row. `email`, `smtp_host` and `imap_host` are required, plus a password; everything else has a default.

| Column | Default |
| --- | --- |
| `email` | required |
| `name` | derived from the address (`alex.rivera@` becomes Alex Rivera) |
| `smtp_host`, `imap_host` | required |
| `smtp_port`, `imap_port` | `587` and `993` |
| `smtp_user`, `imap_user` | the address, or a shared `username` column |
| `smtp_password`, `imap_password` | a shared `password` column |
| `smtp_security`, `imap_security` | inferred from the port (`465` and `993` are `tls`, `587` and `143` are `starttls`) |

The dialog offers a template with these headers, and accepts the common spellings (`smtp_server`, `app_password`, `login`, and so on).

**What happens.** The file is read in your browser and checked before anything is sent: rows missing something the connect needs are listed with the reason and left out of the run. The preview also says how many rows fit your allowance; if the file is larger, the first rows that fit are connected and the rest are reported as failed so you can request more and re-upload only those.

The run then streams the rows to the server in small batches. Every credential is verified against its own server before it is saved, the same as a single connect, so a large file takes a few seconds per mailbox; the dialog shows live progress and the mailbox list behind it fills in as they land, for everyone in the workspace. You can stop after the batch in flight. Closing the tab loses nothing that was already connected.

**When it is done** you see how many connected, how many were already here, and how many did not connect, with a reason per row. **Retry failed** runs those rows again without leaving the dialog, passwords still in memory. **Download failed rows** gives you those rows as you uploaded them plus an `error` column, with the password columns left out so no credential lands in a Downloads folder; add them back before uploading the fixed file. Re-uploading is always safe: a mailbox that is already connected is skipped, never doubled.

The same endpoint is available to the API as `POST /emails/onboarding/smtp-imap/bulk`, up to `50` rows per call, answered per row.

## Reconnecting an account

When the provider stops accepting a mailbox's stored credential (a password change, a revoked grant, an expired app password), the mailbox is taken out of sending and syncing and its drawer shows the reason under **Needs attention**, with the fix right on the error:

- **Gmail and Outlook**: a **Re-authorize** button re-runs the provider consent in a popup, preselecting the mailbox's own address. The consent must be for that same address; signing in with a different account is refused instead of quietly connecting the wrong mailbox.
- **SMTP / IMAP**: an **Update credentials** button opens a form for the new password (or new host and port). The replacement is validated against your server before it is saved, the same as at connect time.

A successful reconnect stores the new credential, clears the authentication error, reactivates the mailbox on its existing worker, and it resumes syncing from where it stopped. Nothing else changes: settings, history, warmup progress, and campaign membership all stay.

Reconnecting never counts against the mailbox allowance, so a workspace at its cap can still fix a broken mailbox. A mailbox whose sign-in is held by Warmbly Cloud is reconnected from your cloud workspace instead; the button says so if you try locally.

## What gets synced

Connecting a mailbox does two things: it imports the mailbox's recent history, and from then on it follows new mail as it arrives. Both are the same on every provider.

**The import** brings in the last `90` days, newest first, up to `5,000` messages per mailbox (the defaults; a self-hosted instance can change both under Instance settings). It reads the inbox, sent mail and archive (plus your own folders on Gmail and IMAP), and skips trash, drafts, spam and Gmail's "All Mail". You can watch it in the mailbox drawer's **Sync** card: a progress bar with a running count while it works, then "Up to date" with what was imported. Because it runs newest first, the mail you would look for is there within the first minute; a large mailbox finishes over the next while at a steady pace.

**Live sync** then follows every folder the provider exposes, including junk (so placement problems are visible) and sent mail (so a conversation shows both sides). Read state, flags, deletions and moves are mirrored too.

<Callout type="info" title="Fair use, not a hard cap">
  There is a budget on how much new mail one mailbox stores per day (`2,000` by default) and how much a whole workspace stores per day (`25,000`), plus a short burst limit so a mailing-list storm cannot swamp the workers. Mail over a budget is not dropped: it waits on the server with the sync cursor held, and comes in when the window rolls. Replies to your own outreach have their own budget and are never held behind ordinary inbound mail. The drawer says "Waiting on the sync budget until ..." while this is happening, and the mailbox checks back less often until then.
</Callout>

Only two patterns deactivate a mailbox's sync, and both mean something is wrong upstream: a flood (thousands of new messages in a single hour, more than any real inbox produces) or exceeding the daily budget on three of the last seven days. The mailbox then shows the reason under **Needs attention**; fix what is delivering that volume into it, or ask your administrator to raise the budget, and reactivate it.

## Sending controls

Set these on the mailbox's **Settings** tab. They apply to the next scheduled send, not retroactively.

| Control | Default | Range |
|---------|---------|-------|
| Daily campaign cap | `50`/day | `0` to `5000` |
| Minimum gap between sends | `600s` (10 minutes) | A hard floor, with jitter added on top |

The default of `50` is deliberately conservative. `30` to `50`/day is the normal safe band; a fresh mailbox should start at `10` to `20` and ramp. Raise the cap only for a mailbox with proven reputation and low complaint and bounce rates.

The range goes up to `5000` so a high-capacity mailbox (a warmed Google Workspace account allows `2000`/day, Microsoft 365 more) is not artificially blocked, and the dashboard shows a warning on anything above `100`. A high cap only raises the ceiling: the campaign's own daily limit, the ramp, sending behaviour, and your workspace's daily send limit all still apply, and the smallest one wins. The minimum gap is a throughput bound of its own: at the default `600s` a mailbox tops out around `144` sends in a `24`-hour window, so a cap above that only takes effect together with a shorter gap.

<Callout type="warn" title="Do not jump a new mailbox to a high cap">
  A new mailbox has no reputation. Sudden high volume from a cold inbox is one of the fastest ways to land in spam. Scaling cold outreach means adding mailboxes, not cranking one mailbox's cap.
</Callout>

### Keeping a copy of sent mail

SMTP mailboxes get a **Keep a copy of sent mail** toggle, on by default. SMTP submission puts nothing in your own account, so without it a message Warmbly sends exists only in the recipient's inbox: it shows up in neither your mail client nor the unibox thread. With it on, Warmbly files each message in the mailbox's Sent folder as it goes out, flagged read and dated when it was sent.

Turn it off when your provider already saves its own copy of anything submitted over SMTP, which Gmail, Fastmail and Zoho do, or the folder ends up with two of every message. Gmail and Outlook mailboxes connected with OAuth never show the toggle: their APIs file the copy themselves. Warmup mail is never filed, since it would bury your real sent mail.

The same tab sets the **display name**, **reply-to** (empty uses the mailbox address), **signature** in plain text and HTML, and **tags** for grouping. A new display name is on the From header of the next message the mailbox sends, campaign, reply or warmup alike; nothing needs to be reconnected.

The HTML signature is placed in a block of its own one line below the body, so it arrives without the stack of blank lines above it that Apple Mail and Outlook used to show. Put any extra spacing you want inside the signature itself. The plain-text signature follows the body after a single blank line.

### Custom tracking domain

Open pixels and click links go out on a shared tracking host by default, which means their reputation is the sum of everyone else using it. Pointing a subdomain of the domain you send from at that host puts them on your own name instead.

Type the subdomain into **Custom tracking domain** in the mailbox's Settings tab. Warmbly shows the exact `CNAME` to add, with the value taken from the host this Warmbly install serves tracking on (on a self-hosted install, that is whatever the operator set `TRACKING_DOMAIN` to). Add the record at your DNS provider, then press **Save & verify**.

Verification resolves the record live and reports what it finds:

| What it says | What it means |
| --- | --- |
| **Verified** | The subdomain resolves to the tracking host. New sends use it. |
| No DNS record yet | The name does not exist. The record has not been added, or has not propagated; usually minutes, up to an hour. |
| Points at something else | The record exists but its value is another host. The message names what it found so you can compare it with what you typed. |
| Nothing to point at | This install has no tracking host configured. Nothing can verify until an operator sets `TRACKING_DOMAIN`. |

A provider that flattens `CNAME` records (ALIAS records, apex flattening, proxied records) still verifies: Warmbly compares the addresses when there is no `CNAME` to read.

Press **Check again** any time to re-resolve without changing the value. Warmbly also re-checks every custom tracking domain on its own, hourly, so a record that finishes propagating after you saved starts being used without you doing anything, and one that later stops pointing at the tracking host stops being used instead of quietly breaking every link.

Until it verifies, tracking falls back to the shared host, so an unverified domain never breaks sending: links keep working, they just are not on your name yet. Links already sent keep working after a change; new sends pick up the new domain.

## Warmup

New mailboxes should warm up before carrying campaign volume. Defaults are `10`/day starting volume, `+1`/day ramp, and a `40`/day ceiling.

Start, pause, resume, or stop from the mailbox's **Warmup** tab, or for several mailboxes at once from the Accounts selection bar. **Pausing keeps your ramp progress; stopping resets it**, so a restart begins at the base volume again.

Keep warmup running after campaigns begin rather than switching it off once a mailbox looks ready. See [Warmup](/guides/warmup/).

<Callout type="info" title="Warmup is a paid feature">
  The model still supports separate free and premium pools, but access is gated to paid workspaces today.
</Callout>

## Pausing and disconnecting

A mailbox can be set inactive (`PATCH /emails/{id}` with `status`) when you want it to stop without losing its settings, its history, or its place in the fleet.

Switching it off takes effect immediately: the machine syncing it is told to drop it, so it stops importing mail and stops being picked for campaign sends and warmup within seconds rather than at that machine's next restart. Warmup pool membership is dropped, and any warmup chain it had winds down on its next step. A campaign email already handed over is answered as a failure and the step is retried later on a mailbox that is still active, so nobody receives it twice and no lead is stranded.

It keeps its worker assignment while off, so switching it back on puts it back on the same machine, sending from the same IP, and it resumes syncing from where it stopped instead of re-importing.

**Disconnecting** removes the mailbox for good, from the Accounts selection bar. The machine syncing it is told to drop it before the record is removed, because afterwards there is nothing left to tell. If that instruction cannot be delivered, the disconnect fails with a `503` and nothing is removed, so retry it in a moment rather than assuming it worked.

Everything belonging to that mailbox goes with it: its imported mail in the unibox, its warmup history and pool membership, its credentials, its sender links, and any send still scheduled for it. A campaign that was using it keeps running on its remaining senders. Export the workspace first if you want a copy. Disable the mailbox instead when you only want it to stop.

## Worker assignment

You never pick a worker. Warmbly assigns each mailbox to a sending worker automatically and can move it later. Workers are the machines that send and sync, so spreading mailboxes across them spreads sending across network identities and IPs.

| Workspace | Placement |
|-----------|-----------|
| Free / trial | Shared free-tier workers |
| Paid | Shared premium workers |
| Plans including dedicated workers | A dedicated worker bound to the workspace, allocated on demand, falling back to shared premium and retrying later |

Within a tier, Warmbly picks the least-loaded healthy worker with capacity rather than packing onto the first one. Each mailbox contributes a load weight, so a worker's planned volume tracks the sum of its mailboxes' budgets.

**Risk is segregated.** A degraded, risky, or quarantined mailbox is never placed on a clean worker beside trusted inboxes, so one struggling mailbox cannot drag down the reputation others depend on.

Mailboxes migrate automatically when a trial upgrades, a subscription ends, a workspace moves to or from a dedicated worker, or a risk band changes. No action needed.

## Resting a tired mailbox

Cold sending used to run at full volume until a mailbox crossed a hard health band, with nothing in between. A mailbox showing early fatigue either kept going or was quarantined.

A mailbox now has a cold-rotation state, separate from its health:

| State | Meaning |
|-------|---------|
| `active` | In cold rotation. The default, and where every mailbox starts |
| `resting` | Out of cold rotation to recover. Warmup keeps running, so its reputation stays alive |
| `reserve` | Held back by you. Never entered or left automatically |

A mailbox rests when its warmup health reaches `throttled` or worse, and returns on its own once it is healthy again **and** has held steady for three days. One good hour does not put it back at full cold volume.

Resting only makes sense while the mailbox is in a warmup pool, because pool health is the signal it recovers on. If a resting mailbox leaves its pool (the workspace loses warmup when a trial ends or a plan changes), there is no health signal to wait for, so the mailbox returns on its own three days after its last rest stamp rather than staying out indefinitely. Pausing warmup on the mailbox does not remove it from the pool, so its health keeps being tracked and the normal three healthy days still apply.

### Putting a resting mailbox back yourself

You do not have to wait. A resting mailbox's notice in the drawer has a **Put back into campaigns** button. It lands in `active` unless its warmup health is still `throttled` or worse, in which case it stays resting and the drawer says so: a mailbox that warmup can see is struggling should not send cold mail, and there is no override for that short of the health recovering.

API keys get the same exit through `POST /emails/:id/release`, which works on a resting mailbox as well as a held one.

It does not rest on the `watch` band. That band is deliberately the one that changes nothing you can feel, and leaving cold rotation is very much something you feel.

### Holding a mailbox yourself

To keep a mailbox out of campaigns on your own terms (a domain you are moving, an inbox you want to keep for replies only, a sender you are about to retire), open its drawer and turn on **Hold from campaigns** on the Overview tab. The mailbox goes into `reserve`: campaigns stop picking it, warmup carries on as before, and nothing automatic ever releases it. Turn the hold off to put it back; if its warmup health is still poor at that point, it rests until it recovers rather than returning straight to full volume.

The same hold is available to API keys as `POST /emails/:id/hold` and `POST /emails/:id/release`. Releasing a mailbox that is `resting` rather than held works the same way and is the manual exit from a rest.

<Callout type="info" title="Separate from where a mailbox runs">
This is not the same as the risk band that decides which sending worker and IP host a mailbox. A resting mailbox is usually still on a clean worker; it is simply not being offered campaign sends. The mailbox drawer says which state it is in and why.
</Callout>

## Health

The Accounts list groups mailboxes as **Healthy** (sending normally), **Warming** (ramping through warmup), or **Needs attention** (paused, failing, or not sending), each row showing a live state and score. A drop between refreshes notifies you rather than waiting to be noticed.

The detail drawer runs a live `SPF`, `DKIM`, and `DMARC` check on your sending domain. Confirm it is green before sending; major providers require alignment for bulk and cold mail. A domain that stays Failing eventually stops cold sending and warmup from every mailbox on it, so fix the records and press **Re-check** to clear it straight away. See [Deliverability](/guides/deliverability/) for the grace period and exactly what is stopped.

Underneath, health moves through `healthy`, `watch`, `throttled`, `quarantined`, and `blocked`. These feed warmup pool selection, which only picks healthy mailboxes as partners, so an unhealthy one can be lowered in volume, removed from the pool, or blocked entirely. A blocked mailbox shows the reason and any appeal option on the Warmup tab, and must requalify on a fresh probation sample rather than waiting out the clock.

Health is judged only on what happened while the mailbox was in the pool: signals recorded before it joined are never counted against it.

<Callout type="info" title="Health protects the pool">
  These controls act earlier than the point where providers start penalizing senders. Low complaint rate and low spam placement matter more than maximum throughput.
</Callout>

## Related guides

<Cards>
  <Card title="Deliverability" href="/guides/deliverability/" />
  <Card title="Personalization & Expressions" href="/guides/expressions/" />
</Cards>
