Suppression honored during queue processing
Why it matters
Email dispatch pipelines with a queue layer (BullMQ, SQS, Celery) introduce a window between job creation and job execution. A contact who unsubscribes or receives a hard-bounce notification after a campaign job is enqueued but before the worker processes it will still receive the email if suppression is only checked at scheduling time. Under CAN-SPAM § 5, a suppression request must be honored within 10 business days — a queue delay of minutes to hours is acceptable, but a suppression check that is only performed at enqueue time can miss suppressions that arrive during that window. GDPR Art. 21 right to object has the same gap risk: an objection processed into the suppression table after the job was queued still results in a send if the worker does not re-check.
Severity rationale
Medium because the queue-time suppression gap is a timing vulnerability rather than a permanent miss — it creates a window for non-compliant sends proportional to campaign queue depth and processing lag.
Remediation
Add a suppression check inside the worker function, immediately before the ESP send call — not only at job creation:
worker.process('send-email', async (job) => {
const { to, templateId, data } = job.data
// Re-check suppression at dispatch time — catches suppressions added after job was queued:
if (await isSuppressed(to)) {
await db.sendLog.create({
data: { to, templateId, outcome: 'suppressed_at_send', job_id: job.id }
})
return // Complete the job without sending
}
await esp.send({ to, templateId, data })
await db.sendLog.create({ data: { to, templateId, outcome: 'sent', job_id: job.id } })
})
The first suppression check at enqueue time is still useful to reduce queue depth — keep both checks. The worker-level check is the safety net for the scheduling-to-dispatch window. Ensure isSuppressed queries the same global suppression table (see ab-000872), not a per-campaign exclusion list.
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 Data Quality & List Hygiene Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- external · CAN-SPAM-Sec5 — CAN-SPAM Act §5 — opt-out must be honored; queue-time lag cannot create a gap where suppressed addresses are sent to
- gdpr · Art. 21 — GDPR Article 21 — Right to object must be given effect immediately; queued sends to objecting contacts violate this right
- iso-25010:2011 · functional-correctness — Functional Correctness (functional suitability)
Taxons
History
- 2026-04-18·v1.0.0·Initial import from data-quality-list-hygiene·automated