You’re right on decay — that’s where lists live or die. Here’s how to let AI choose both “when” and “how often” without burning trust: build a simple fatigue score, set a send-skip budget, and let a lightweight bandit allocate frequency within guardrails.
What you’ll set up
- A per-recipient fatigue score (updates weekly)
- Two-hour “quiet” and “prime” windows per recipient
- A frequency allocator (bandit) that tests cadences but respects fatigue
- Clear guardrails for deliverability and unsub risk
What you’ll need
- 90–180 days of logs: send timestamp (UTC), timezone, opens, clicks, conversions, revenue, unsubscribes, spam complaints, bounces
- Your ESP’s A/B or rules engine and the ability to upload a scheduling file
- A spreadsheet or BI tool; any AI assistant to run the prompt below
How to do it (clear steps)
- Baseline and windows: Normalize to local time; build segment heatmaps to pick 2–3 strong send windows per segment. Also compute each recipient’s top two-hour window from their last 5–10 opens. If a recipient lacks data, fall back to the segment window.
- Fatigue score (simple but powerful): Start everyone at 60. Each week:
- -5 points for every marketing email received in the last 14 days (cap -20)
- +10 for a click in the last 14 days, +5 for an open (cap +20)
- +15 for a conversion in the last 30 days
- -10 if no opens in 60 days; -20 if no opens in 90 days
- -25 if a spam complaint in last 90 days (and move to low cadence)
Map score to cadence:
- 80–100: up to 2/week
- 60–79: 1/week
- 40–59: 1/2 weeks
- 0–39: monthly or pause 30 days
- Send-skip budget: Give each recipient a weekly budget (e.g., 2 “credits”). A standard newsletter costs 1 credit; promos cost 2. If budget is used up, skip until next week. High-fatigue recipients start with 1 credit; high-engagement get 3.
- Bandit for frequency: After you lock in the send-time window, use a multi-armed bandit across 2–3 cadences (e.g., weekly vs twice-weekly) within the above limits. Reward = weekly revenue per recipient minus a penalty for unsub/complaint (e.g., subtract $5 per unsub, $20 per complaint). The bandit shifts traffic to the winning cadence while your guardrails prevent over-sending.
- Guardrails that auto-revert:
- Unsubs >0.5% for any cohort over 2 sends: step down one cadence level
- Spam complaints >0.08% or soft bounces >2%: revert to prior settings and review content/list hygiene
- Revenue per recipient drops >8% week-over-week for 2 weeks: reduce frequency by one level
- Holdout for true lift: Keep a 5–10% random holdout on your pre-test cadence to measure net impact. No optimization is complete without this.
- Scheduling file: Generate a weekly file with columns: recipient_id, next_send_date_local, local_send_hour, cadence_level, credits, reason_code (e.g., “high_engagement”, “cooldown_90d”). Upload to your ESP or rules engine.
Example (round numbers)
- List 100,000. Baseline: 3% CTR, $0.24 revenue per recipient per week, unsub 0.25%.
- Top quartile (fatigue 80–100) moves to 2/week in their prime window; middle stays at weekly; low-fatigue cohort drops to biweekly.
- After 3 weeks: top quartile +22% revenue/recipient, unsub +0.12%; middle +6%, unsub flat; low-fatigue +2%, unsub down 0.05%.
- Holdout shows net +9–12% revenue/recipient with healthy list metrics.
Copy-paste AI prompt
Act as my email optimization analyst. I will provide a CSV with: recipient_id, recipient_timezone, send_timestamp_utc, open_timestamp, click_timestamp, conversion_timestamp, conversion_value, unsubscribe_flag, spam_complaint_flag, bounce_flag. Do the following and return CSV outputs and a plain-language summary:
- Compute per-recipient fatigue score using these rules: start 60; -5 per marketing send in last 14 days (min -20); +10 click (14d), +5 open (14d) cap +20; +15 conversion (30d); -10 if no opens 60d, -20 if no opens 90d; -25 for spam complaint (90d). Clamp 0–100.
- Assign cadence: 80–100=2/week; 60–79=1/week; 40–59=1/2 weeks; 0–39=monthly or pause 30d. Include a weekly credit count (2 for high, 1 for low).
- Derive each recipient’s top two-hour local window from last 10 opens; if insufficient data, use segment window (region×product_interest×VIP) and include the chosen window.
- Simulate a 3-week bandit across cadences within guardrails, using reward = weekly revenue per recipient minus $5 per unsub and $20 per complaint. Return recommended cadence share by segment and expected lift with 80% confidence intervals.
- Output a schedule file with: recipient_id, next_send_date_local, local_send_hour, cadence_level, credits, reason_code.
Common mistakes and quick fixes
- Mistake: Optimizing for opens. Fix: Use revenue/recipient and penalize unsubs/complaints in the objective.
- Mistake: No holdout. Fix: Always reserve 5–10% control to verify net lift.
- Mistake: Pushing frequency during poor inbox placement. Fix: If bounce or complaint spikes, slow down and fix list hygiene/content first.
- Mistake: One-size-fits-all cadences. Fix: Tie cadence to fatigue bands and adjust weekly.
7-day plan
- Export 90–180 days of data; normalize to local time; add weekday.
- Build segment heatmaps; pick 2–3 prime windows per segment.
- Run the AI prompt to compute fatigue scores and initial cadence bands.
- Create the first scheduling file for 25% of the list; include a 10% holdout.
- Launch with guardrails; monitor unsub, complaints, bounces daily.
- Let the bandit reallocate for two sends; review weekly revenue/recipient.
- Scale to 60–100% if lift holds and guardrails stay green.
Keep it simple: start with fatigue bands, add send-skip budgets, then let the bandit fine-tune. That’s how you get lift fast without burning your best subscribers.
— Jeff
