§7 · IP warmup
IP warmup — the 6-week schedule.
A fresh sending IP starts at zero reputation. Mailbox providers throttle high volumes from new IPs by design — it's the primary defence against snowshoe spammers spinning up cloud instances and blasting. Warmup is the practice of gradually increasing send volume over 4–6 weeks while staying inside per-day and per-hour throttle limits, building reputation organically.
You only do this once per IP. Most teams never do it because Amazon SES, SendGrid, and Mailgun's shared IPs come pre-warmed. The cases where warmup matters: dedicated IP on SES (typically > 1M sends/month justifies one), self-hosted Postal MTA on a fresh cloud instance, migration from one ESP to another with a domain change.
The schedule
| Day |
Daily volume |
Audience cohort |
Watch metric |
| 1 | 50 | Most-engaged 5% | Open rate > 30% |
| 2 | 100 | Most-engaged 5% | Bounce < 2% |
| 3–4 | 200–500 | Top 10% engagement | Inbox placement (provider tools) |
| 5–7 | 1K–2K | Top 25% | Complaint < 0.1% |
| 8–14 | 5K → 20K | Top 50% | SES reputation dashboard green |
| 15–21 | 25K → 100K | Top 75% | Postmaster Tools spam < 0.1% |
| 22–42 | Full daily volume | Full list (excluding inactive 6mo+) | Open rate stable, bounce low |
Schedule based on the SparkPost / Postmark / SES published warmup recommendations consolidated to a single week-by-week table. Ramp slower than this if you see complaint rate trending upward; ramp faster only if you have provider-confirmed reputation green-light at every step.
Warmup tracking in AcelleMail
AcelleMail's SendingServer model has first-class warmup state. warmup_enabled, warmup_strategy_id, and warmup_started_at live on the sending_servers table; isWarmupEnabled() at app/Model/SendingServer.php:333 gates send-time decisions. The companion SendingServerWarmupLog table records every send during the warmup window with date, status, and a serialized meta payload — see app/Model/SendingServerWarmupLog.php.
The pattern: assign a WarmupStrategy (a row defining the per-day volume curve) to a sending server, flip warmup_enabled = true, set warmup_started_at = now(). The send pipeline's SendingServerWarmupUsage tracks today's count and refuses to dispatch beyond the strategy's daily ceiling. When the strategy's day-N ceiling exceeds your full daily volume, the server graduates and warmup mode auto-disables.
The DynamicRateTracker and InMemoryRateTracker classes (app/Library/) handle per-minute / per-hour rate limiting at the SMTP layer — even outside warmup, AcelleMail enforces the relay's published rate caps so a queue surge doesn't trip provider-side throttling.