Soft-bounce threshold alerts
runSoftBounceSweep in src/lib/soft-bounce-sweep.ts. Runs every 15
minutes (part of the */15 * * * * cron).
Why
A single temporary failure (event=failed, severity=temporary) is
usually a transient SMTP hiccup. But ≥3 to the same recipient in 24h
signals a real problem (full mailbox, forwarding loop, domain block).
We want to surface that early.
Query shape
SELECT recipient, COUNT(*) AS count, (subquery for most-recent reason) AS last_reason FROM mailgun_events WHERE event = 'failed' AND severity = 'temporary' AND received_at >= ? AND recipient IS NOT NULL GROUP BY recipient HAVING COUNT(*) >= 3What it sends
For each offending recipient:
SMS to +19524518482 (Bill):
Soft-bounce threshold hit: {recipient} 3 temp failures in last 24h. Last reason: {reason}
Dedup
Uses alert_log (migration 0025):
INSERT INTO alert_log (alert_key, detail) VALUES ('soft-bounce:{recipient}', 'count=X, reason=Y')Before sending, checks if a row with alert_key=soft-bounce:{recipient}
exists in the last 24h. If yes → skip. One alert per recipient per
24h max.
Source
src/lib/soft-bounce-sweep.tsmigrations/0025_alert_log.sql- Tests:
test/lib/soft-bounce-sweep.test.ts(6 cases)