Skip to content

feat(esp): automatic warm-up with the most engaged contacts first - #101

Merged
clbotdev merged 1 commit into
mainfrom
issue-5-warmup-scheduler
Oct 19, 2026
Merged

clbotdev merged 1 commit into
mainfrom
issue-5-warmup-scheduler

Conversation

@clbotdev

Copy link
Copy Markdown
Contributor

Part of #79. Closes #5.

What

  • Automatic warm-up per ESP.
    • warmupTargetDailyVolume on create and update (REST and MCP). Setting it starts the ramp from day 1; retargeting keeps the progress; null turns it off.
    • The ramp, WARMUP_RAMP/warmupDailyLimit/warmupDays in api-contract, is 50, 100, 200, 400, 750, 1.5k, 3k, 5k, 8k, 12k, 18k, 25k, 35k, 50k, 70k, 100k, then +40% a day, capped at the target.
    • acquireEspSendCapacity caps campaign mail at the lower of the warm-up's limit for the UTC day and the ESP's own dailySendLimit (Day-one warm-up answer: warm-up guide and self-serve daily send caps for new domains / SES accounts #67). Mail over it waits until the next day, and transactional mail is never capped.
    • The ESP response includes warmup (day, total days, today's limit, complete).
  • Most engaged first.
    • ongoing_sequences.priority (migration 0021), set at enrollment by automation/engagement.ts. It ranks recent clicks (worth 14 days more recency than an open), then recent opens, then imported open_rate/click_rate custom fields (e.g. from a beehiiv or Mailchimp export; 0.45, 45 or "45%"), then signup date with newest first.
    • getDueOngoingSequences orders by priority and then by due time; the FIFO queue keeps that order. A day capped by the warm-up, a daily limit or quotas therefore reaches the most engaged contacts first.
  • UI: an "Automatic warm-up" section in the ESP dialog with the target and a ramp preview ("Starts today; reaches 1,000 a day on day 6. Daily limits: 50, 100, …"), and "Warm-up day N of M: x / y today" in the ESP list.
  • Docs: warm-up.mdx (automatic warm-up, ramp table, send order, links to auto-pause and reputation) and settings.mdx.

The issue's "send to the top N, then send to more" is covered by the cap plus the engagement order. A broadcast to everyone goes out to the most engaged first and continues each day, without a manual "send to more" step.

Verification

  • check.sh (731 API tests incl. new warm-up, engagement-order, enrollment-priority and warm-up-cap Redis tests; contract ramp tests; web tests), check:drift, test:conformance, docs build.

  • Browser E2E (6/6):

    1. Turn on warm-up to 1,000 in the dialog; the preview shows the right ramp, and the list shows "day 1 of 6".
    2. A broadcast to 65 contacts delivers exactly 50 today. All 10 engaged contacts are among them, even though they are the oldest signups, and the other 15 are deferred to the next UTC day.
    3. The list shows "50 / 50 today".
    4. A day later the limit is 100.
    5. Turning warm-up off clears it.

    Along the way this showed that welcome-sequence mail counts toward the same daily cap, as intended: all marketing mail through the ESP shares it.

An ESP can now warm up on its own: set a target daily volume and the daily
limit for broadcast and sequence mail starts at 50 and grows each UTC day
(50, 100, 200, 400, 750, 1,500, ... then +40% a day) until it reaches the
target. The lower of the warm-up and the ESP's own daily limit applies; mail
over it waits for the next day, as with #67's limit.

Queued deliveries now carry an engagement priority, set when contacts are
enrolled: recent clicks, then recent opens, then imported open/click rates,
then newer signups. Due deliveries are processed in that order, so a capped
day goes to the most engaged contacts.

The ESP dialog previews the ramp, the ESP list shows the warm-up's day and
today's count, and REST/MCP take `warmupTargetDailyVolume` and return
`warmup`.

Closes #5
@clbotdev
clbotdev merged commit 44eb4be into main Oct 19, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Warmup scheduler

2 participants