Skip to main content

Warming a Dedicated IP for Transactional Email Without Losing Placement

Ramp a new dedicated sending IP safely: a volume schedule driven by receiver feedback, recipient selection by engagement, and the hold rules that prevent a stalled warm-up.

Moving a transactional stream onto a new dedicated IP means sending from an address that has no history at Gmail, Yahoo or Microsoft — and an address with no history is treated with suspicion the moment it sends more than a trickle. This guide covers the ramp that builds that history without triggering the throttling and spam filing that a cold IP sending at production volume reliably produces.

Root Cause: Receivers Model Sending Patterns, Not Just Volume

A receiving provider decides how much mail to accept from an IP based on what it has seen from that IP before. A brand-new address has an empty model, so its first messages are evaluated with maximum caution: accepted in small numbers, filed conservatively, and rate-limited aggressively if the volume jumps.

The failure mode is specific. Sending 200,000 messages on day one from an unknown IP does not produce 200,000 spam placements — it produces deferrals. Receivers respond with 4xx temporary rejections, your queue retries, the retries look like pressure from an unknown sender, and the pattern reinforces the caution. Days later, when the IP finally does accept mail at volume, it does so with a reputation built entirely from that rejected traffic.

What receivers are modelling is consistency: similar volume at similar times with a low complaint rate. A ramp works because it lets the model form on small numbers where the complaint rate can be measured reliably, then extends it upward in steps small enough that no single step looks like a new sender arriving.

Deferral rate on a cold versus warmed IP A cold IP sending at full volume is deferred heavily from the first day, while a ramped IP keeps deferrals near zero as volume increases. The Cold IP Is Not Filtered — It Is Deferred Full volume on day one 4xx deferrals on most attempts The queue retries, the retries look like pressure, and the caution deepens. Reputation forms from rejected traffic. Ramped over four weeks deferrals stay near zero throughout Each step is small enough that no day looks like a new sender arriving. Reputation forms from accepted traffic.
The damage from an unwarmed IP is done by the deferral-and-retry loop, not by content filtering.

The Exact Ramp

Volume roughly doubles every two to three days, starting in the low hundreds. The exact numbers matter less than the shape and the hold rule.

Day Daily volume Note
1 50 Highest-engagement recipients only
2–3 100–200 Watch deferral rate before each increase
4–5 500 First point where Postmaster Tools has usable data
6–8 1,000–2,000 Split evenly across the day, not in one burst
9–12 5,000 Add lower-engagement recipients gradually
13–16 10,000
17–21 25,000–50,000
22–28 Full production volume Hold at each step if complaints rise

Two rules govern the schedule. Never double after a step where the complaint rate rose — repeat the previous day's volume instead until it settles. And never skip a step to catch up, which is the instinct when a migration deadline approaches and precisely the action that resets the ramp.

# warmup.py — decide today's send allowance from yesterday's outcome, rather
# than from a fixed calendar. The schedule is a plan; the feedback is the rule.
SCHEDULE = [50, 100, 200, 500, 1000, 2000, 5000, 10000, 25000, 50000, 100000]

COMPLAINT_CEILING = 0.001    # 0.10% — hold at this or above
DEFERRAL_CEILING = 0.02      # 2% of attempts deferred — hold


def next_allowance(step: int, complaint_rate: float, deferral_rate: float) -> tuple[int, int]:
    """Return (allowance, next_step). Holding repeats the current volume."""
    if step >= len(SCHEDULE) - 1:
        return SCHEDULE[-1], step          # fully warmed

    if complaint_rate >= COMPLAINT_CEILING or deferral_rate >= DEFERRAL_CEILING:
        # Receivers are pushing back. Repeat today's volume; do not advance,
        # and do not reduce — a sawtooth pattern is worse than a plateau.
        return SCHEDULE[step], step

    return SCHEDULE[step + 1], step + 1

The subtlety in that function is what it does not do: it never reduces volume. A ramp that goes up, back down and up again produces exactly the inconsistency receivers penalise. Holding flat is the correct response to pushback; retreating is not.

Choosing Who Receives the Early Volume

Which recipients you send to during the ramp matters as much as how many. The first messages should go to the addresses most likely to be opened and least likely to bounce: recent signups, active users, and accounts that have engaged in the last thirty days. That population produces a low complaint rate and a high engagement signal, which is what the receiver's model is being built from.

Transactional streams have a natural advantage here. A password reset is requested by the recipient seconds before it arrives, so engagement is close to guaranteed — starting the ramp with reset and verification traffic gives the cleanest possible early signal. Receipts and notifications follow; digests and anything approaching a bulk send come last.

Order of message types during a ramp User-requested messages join first, then confirmations and receipts, then notifications, with digests and low-engagement mail added only at the end. Add Message Types in Engagement Order week 1 — requested resets, verification codes week 2 — confirmations receipts, order updates week 3 — notifications alerts, mentions week 4 digests last Engagement during the ramp is what the receiver's model is built from, so the highest-engagement traffic should be the traffic that establishes it. A digest sent in week one is the worst possible first impression.
Requested messages have near-certain engagement, which makes them the ideal traffic for the days when the receiver model is being formed.

Variant: Warming Alongside an Existing IP

Most warm-ups happen while an existing IP is still carrying production traffic, which is safer than a cutover and adds one requirement: the split must be deterministic per recipient, not random per message. If a given address sometimes receives mail from the old IP and sometimes from the new one, neither IP builds a coherent history with the receiver, and the recipient's own provider sees an inconsistent sending identity.

Hash the recipient address to decide the pool, then increase the share of the hash space assigned to the new IP as the ramp progresses. That way every recipient consistently receives from one IP at any given stage, and the migration is a widening of the new pool rather than a shuffle.

Variant: Restarting After a Stalled Ramp

If the complaint rate has risen enough to force several consecutive holds, the ramp has stalled, and continuing to push is counterproductive. Drop back to the last volume at which the complaint rate was clean, stay there for a full week, and investigate the cause before resuming — almost always a segment added at the step where things turned, or a template introduced at the same time.

Do not restart from day one. The history you built is not lost, and re-ramping from 50 messages after a stall wastes weeks and re-introduces the inconsistency you are trying to avoid.

Pipeline Integration

The daily allowance belongs in the queueing layer rather than in the application, so a warm-up cap is enforced in exactly one place. During the ramp the worker draws messages until the allowance is exhausted, then holds the remainder for the next window rather than dropping them — the interactive lane keeps its priority, so a password reset is never the message that gets held.

Feed the previous day's metrics from Postmaster Tools and your ESP's event stream into the allowance decision automatically. A ramp advanced by a human reading a dashboard advances on the days someone remembers, which is not the same as the days the data supports.

Validation and Deployment Checklist

Debugging: Named Symptoms During a Ramp

Symptom: deferrals rise at one provider only. Cause: that provider's model is forming more slowly than the others, usually because your recipient mix skews away from it. Fix: hold the overall volume but keep sending to that provider at the current step for an extra day or two; the ramp is per receiver, so there is no benefit to advancing on the others while one is pushing back.

Symptom: complaint rate rises on the day a new message type joins. Cause: the new type has genuinely lower engagement than the traffic that preceded it. Fix: hold volume, and add the new type at a smaller share rather than in full — a digest introduced at 10% of its eventual volume produces a gradual signal instead of a step change.

Symptom: the ramp reaches full volume but placement is worse than on the old IP. Cause: usually that the old IP was on a shared pool with an established reputation that you have now left. Fix: this is expected for several weeks after a ramp completes; hold at full volume and let the history accumulate rather than concluding the migration failed.

Ramp symptoms and responses A single-provider deferral rise, a complaint spike tied to a new message type, and post-ramp placement below the old shared pool each call for a different action. Hold, Reduce the Mix, or Wait one provider defers hold that provider only Reputation is per receiver, so the others can continue. monitor per provider complaints on a new type add it at a smaller share A step change in engagement reads as a new sender. ramp the mix, not just volume worse than the old pool expected — hold and wait You left an established shared reputation behind. weeks, not days
None of these three symptoms calls for reducing volume — holding is the correct response to all of them.

Frequently Asked Questions

How long does a full warm-up take?

Three to four weeks for a transactional stream reaching a few hundred thousand messages a month. Higher volumes take longer, not because the early steps change but because the schedule needs more doublings to reach the target. The duration is driven by the number of steps, and each step needs at least a day for the receiver's model to incorporate it.

Can I warm up faster by sending to more providers at once?

No — reputation is per receiver, so sending to Gmail, Yahoo and Microsoft simultaneously runs three independent warm-ups rather than accelerating one. What you can do is monitor them separately, since they progress at different rates: Microsoft's IP-weighted model typically responds faster than Gmail's, which weighs domain reputation more heavily.

What if we simply do not have enough volume to warm an IP?

Then a dedicated IP is the wrong choice. Below roughly 50,000 messages a month to a single provider, an IP never accumulates the consistent volume that keeps a model warm, and it will perform worse than a well-maintained shared pool. Stay on shared and invest in domain reputation instead, which is portable and does not require a volume floor.

Does warming an IP also warm the domain?

Partly. The two scores are separate, but the traffic that builds one also builds the other, so a well-run ramp improves both. The important difference is that domain reputation survives a later IP change — which is why sending from a consistent subdomain throughout the ramp matters more than the IP you end on.


← Back to Email Deliverability and Reputation