Failed send recovery plan documented
Why it matters
When a send batch fails partway through — worker crash, ESP timeout, deployment restart — the question is: which contacts got the email and which did not? Without a status field on send records that tracks queued, sent, and failed per contact, the only way to reconstruct send state is to cross-reference logs with timestamps, which is slow and error-prone under incident pressure. CWE-391 covers the missing audit trail. ISO 25010 reliability.recoverability requires that recovery from a partial failure is a defined, executable procedure — not an ad-hoc investigation.
Severity rationale
High because without per-contact send status and a documented recovery procedure, a partial batch failure forces manual log reconstruction and risks either re-sending to already-reached contacts or missing contacts entirely.
Remediation
Add a status column to send records and document the recovery query. The schema should support filtering by campaign and status:
// Schema: email_sends table
// status: 'queued' | 'sent' | 'failed' | 'bounced'
// sent_at: timestamp, nullable
// Recovery query: contacts who were queued but never sent
const unsent = await db.emailSend.findMany({
where: { campaign_id: campaignId, status: 'queued', sent_at: null }
})
// Re-enqueue these contacts only
Document this query and the re-queue steps in docs/runbooks/failed-campaign-recovery.md. A data model with no status field makes this check fail regardless of documentation quality.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Operational Resilience (Email) Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- iso-25010:2011 · reliability.recoverability — Reliability / Recoverability — documented procedure to recover failed send batches without duplicates
- cwe · CWE-391 — Unchecked Error Condition — failed sends with no per-contact status field are unrecoverable
Taxons
History
- 2026-04-18·v1.0.0·Initial import from operational-resilience-email·automated