Four numbers per mailbox#
Everything in this guide reduces to four values held against each connected mailbox. Once they exist, rotation, ramping, graceful degradation and automatic pausing all fall out of them — and, more usefully, an operator can read a screen and say exactly what any mailbox is permitted to do today.
- Daily cap
- The ceiling on sends in one day. Defaults to
50in SalesShift and is overridable per mailbox. - Weight
- Relative share of the pool. A mailbox at 2.0 absorbs twice the volume of one at 1.0.
- Ramp
- A start date, an initial allowance and a daily increment, for a mailbox with no history.
- Health score
- A 0–100 summary of recent behaviour, which scales the mailbox's effective share.
None of these is exotic, and that is deliberate. A sending policy nobody can reconstruct is a sending policy nobody trusts — and the first time placement gets worse, the question asked is always why did that message go out from that mailbox. That question should have an arithmetic answer.
The rotation rule#
The naive implementation cycles through mailboxes in order. It fails the moment they differ: a mailbox halfway through its ramp receives the same share as an established one, hits its ceiling early, and the rest of the day piles onto whoever is left.
The better rule is least normalised usage: pick the mailbox that has used the smallest fraction of what it is allowed today.
usage = sent_today / (effective_cap × weight × health_multiplier) choose = the mailbox with the LOWEST usage
Weighted distribution falls out of that for free, and it interleaves smoothly rather than in bursts — a mailbox with twice the allocation is picked twice as often, not twice in a row. A mailbox that is behind catches up; one that is ramping or unhealthy takes proportionally less without being switched off.
One implementation detail is worth insisting on: the selector should be a pure function of the pool, the day's counters and the current time. No database session, no clock read inside it, no randomness. That is what makes every rotation rule testable without sending anything, and what makes two workers given the same state agree. SalesShift implements it exactly this way.
What rotation does not do is make volume safe. A bad list spread across six mailboxes damages six reputations instead of one. See the deliverability guide for the causes that rotation cannot help with.
The ramp#
Receiving providers score a sender partly on trend. A mailbox that goes from nothing to hundreds of messages in a day is, statistically, far more likely to be a compromised account than a new sales hire — and it is treated accordingly. A ramp is how you avoid looking like one.
cap(day) = min( daily_cap, ramp_initial + ramp_increment × day ) SalesShift defaults: ramp_initial = 10 ramp_increment = 5 daily_cap = 50 day 0 → 10 day 4 → 30 day 8 → 50 (capped) day 2 → 20 day 6 → 40 day 9 → 50
Growth stops at the cap — the ramp raises a floor, it is not a second ceiling — so a mailbox with a lower cap simply reaches it sooner. A mailbox with no ramp start date is treated as established and gets its full cap from the first send, which is the correct behaviour for an address that has been in ordinary use for years.
The volume during a ramp has to be real mail to recipients you chose. Engagement from people with a reason to reply is the signal providers are looking for, and it is the only kind that survives contact with the filters that matter.
Health, and what it does to share#
A health score summarises one mailbox’s recent behaviour so a pool can be compared at a glance and volume can move away from the mailboxes in trouble. Its only real virtue is being reconstructible, so here is the whole formula SalesShift uses, over a rolling 30-day window:
score = 90 base
− 40 × min(1, complaint_rate / 0.30%) provider hard limit
− 35 × min(1, bounce_rate / 5%) list-quality signal
− 15 × min(1, failure_rate / 10%) our transport, not them
+ 10 × min(1, engagement / 5%) engagement is placement
engagement = reply_rate + 0.2 × open_rate
clamped to [0, 100]; under 20 sends → "insufficient data", not a numberThe weights are the argument. A complaint costs more than a bounce because the receiving side treats it as a report of abuse rather than a bad address. A transport failure costs least because the recipient never saw it. Opens are discounted to a fifth of a reply because open pixels are fired by image proxies for mail no human read.
A clean mailbox with no engagement scores 90 rather than 100: the last ten points are earned by recipients actually responding, because engagement is what providers score placement on. And below a modest sample the answer is insufficient data rather than a number — one bounce in three sends is a 33% rate and means nothing, while zero is a real score meaning this mailbox is on fire.
The score then feeds the rotation as a multiplier with a floor, so a struggling mailbox keeps a reduced share instead of dropping out entirely. That matters: a hard cliff moves all the volume onto whichever mailbox has not been measured yet, which is the worst possible destination for it.
When a mailbox is pulled out#
Auto-pause is a circuit breaker. It costs volume today to avoid the domain-level damage that takes weeks to undo. Two conditions are required, and the second one is the one people forget:
pause when complaint_rate ≥ 0.30% AND complaints ≥ 2
or bounce_rate ≥ 5% AND bounces ≥ 5
resume: never automatic — a person has to do itThe absolute floors exist because a rate on a small denominator will trigger any threshold you set. One complaint can be a mis-click on a campaign nobody else objected to, and pausing a working mailbox over it is a self-inflicted outage. Two is a pattern.
Resuming has to be a human decision. The rate is computed over a window, so time alone eventually drops the offending events out of the sample and a self-clearing pause resumes into the same list with the same copy — re-running exactly the conditions that caused it. Requiring a person forces the only useful question, which is what changed.
- Look at the cohort, not the mailbox — a bounce spike almost always traces to one import.
- Suppress what needs suppressing before resuming, or the next pause is already scheduled.
- Resume with reduced volume, so the next window's evidence is rebuilt slowly.
Why a ramp, not an exchange network#
The common alternative to a ramp is a pool that trades messages between strangers’ mailboxes, opening and replying to each other, to manufacture engagement for a new address. It is fast, and it is worth understanding what it actually does.
The traffic is not real. The patterns — reciprocal exchanges among a fixed set of domains, engagement with no corresponding human behaviour — are recognisable to the receiving side, and the whole technique depends on them not being recognised. More concretely, joining one ties your domain’s standing to every other participant in the pool, including the ones sending things you would not send.
SalesShift ramps against real recipients you chose, and that is the whole mechanism. It is slower than borrowing engagement from strangers. It is also the version whose reputation is entirely your own, built from mail that people actually had a reason to answer.
Planning a pool#
Work from the volume you actually need, not from the number of mailboxes a plan permits. The arithmetic is short: sustainable volume per mailbox is bounded by the cap you are willing to defend — tens per day for cold outbound — so divide your required daily volume by that number and you have the identity count.
Then add the time. A new mailbox needs a few weeks of ramp before it contributes its full share, so a pool has to be planned before a campaign rather than during one. You cannot ramp your way out of a deadline.
Finally, be honest about whether more volume is the answer at all. Every additional sending identity is another reputation to build and watch. If the reply rate is the problem, a larger pool multiplies the sending and not the results — which is the argument for choosing recipients from public signals instead.