Bounce rate, complaint rate, and open rate are the three signals ESPs use to determine whether your sending domain is trustworthy. When these metrics are not stored persistently and surfaced in a dashboard, deliverability collapse happens silently — Gmail and Yahoo start routing to spam, complaint rates climb past the 0.1% threshold, and you have no historical trend to show when you contact ESP support. CWE-391 (insufficient logging) at the operational layer means you cannot distinguish a transient spike from a structural reputation problem. Without queryable trend data, you are flying blind into potential domain blacklisting.
Critical because unmonitored bounce and complaint rates can trigger ESP account suspension and domain blacklisting before any operator notices the problem.
Create a persistent metrics table and write a query or dashboard panel that shows trend lines per signal. In your webhook handler (e.g., src/app/api/webhooks/email/route.ts), persist each event with enough context to aggregate later:
// On bounce webhook
await db.emailMetrics.create({
data: {
event: 'bounce',
campaign_id: payload.campaignId,
recipient_domain: domain,
recorded_at: new Date()
}
})
Query that table daily to produce bounce rate (bounces / sends) and complaint rate (complaints / sends) trend lines. Stdout logging does not qualify as persistent storage — the data must survive a process restart.
ID: operational-resilience-email.monitoring-alerting.deliverability-metrics-dashboarded
Severity: critical
What to look for: Enumerate all 3 required deliverability signals — bounce rate, complaint rate, and open rate. For each, determine whether it is (a) stored persistently in a queryable form, and (b) surfaced in a dashboard, report query, or metrics platform. Count the number of signals that meet both criteria. A metric logged to stdout only does not count as persistent storage. Report: X of 3 signals are dashboarded.
Pass criteria: All 3 deliverability signals (bounce rate, complaint rate, open rate) are stored in a queryable form (database table, time-series store, or metrics platform) and at least 1 dashboard, reporting query, or aggregation view surfaces trend data over time. Do NOT pass when only 1 or 2 of the 3 signals are tracked — all 3 are required. Report the count even on pass: "3 of 3 signals dashboarded: bounce via [location], complaint via [location], open via [location]."
Fail criteria: Webhook handlers log events to stdout only, or events are discarded after immediate processing with no persistent trend storage. Or fewer than 3 of the required metrics (bounce, complaint, open) are tracked in a queryable store.
Skip (N/A) when: The project does not send email and has no email infrastructure — confirmed by the absence of any ESP SDK, SMTP library, or email-related dependencies in package.json.
Detail on fail: Describe what is tracked and what is missing. Example: "Bounce webhooks write to stdout only — no persistent storage of bounce rate trends" or "Open rate is not tracked; complaint rate is logged but not queryable"
Cross-reference: The Deliverability Engineering Audit's DNS and reputation monitoring category verifies that the raw signals (SPF, DKIM, DMARC) exist — this check verifies the operational layer that makes those signals visible to operators.
Remediation: Create a metrics table or emit named metrics for each deliverability signal. At minimum, in your webhook handler file (e.g., src/app/api/webhooks/email/route.ts):
// On bounce webhook
await db.emailMetrics.create({
data: {
event: 'bounce',
campaign_id: payload.campaignId,
recipient_domain: domain,
recorded_at: new Date()
}
})
Then write a query or dashboard panel that aggregates by day/week to show trend lines.