# Volume limits documented per ESP and IP

- **Pattern:** `ab-001986` (`operational-resilience-email.capacity-scaling.volume-limits-documented`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001986
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001986)

## Why it matters

Every ESP plan has hard sending limits — SES sandbox defaults to 1 send per second and 200 per day; SendGrid's free tier caps at 100 sends per second. Exceeding these limits produces 429 errors that fail jobs and degrade IP reputation if retried without backoff. CWE-770 (allocation without limits) applies when queue concurrency is uncapped relative to the ESP tier. The Deliverability Engineering Audit's IP reputation category depends on sends staying within known limits — this check verifies that those limits are actually documented and enforced in code, not just hoped to be safe.

## Severity rationale

High because sending above ESP tier limits produces throttling errors that increase bounce rate, consume retry budget, and can trigger account suspension on plans with anti-abuse enforcement.

## Remediation

Document ESP limits and wire them to the rate limiter configuration in a dedicated file (e.g., `src/config/email-limits.ts`):

```ts
// src/config/email-limits.ts
export const ESP_LIMITS = {
  sendgrid: { perSecond: 100, perDay: 1_000_000 },
  ses: { perSecond: 14, perDay: 50_000 }  // SES sandbox defaults
} as const

// BullMQ rate limiter:
const limiter = { max: 100, duration: 1000 } // 100/second
```

Include the source plan tier and date in a comment — limits change when plans change. The queue limiter value must not exceed the documented per-second limit for the configured ESP.

## Detection

- **ID:** `volume-limits-documented`
- **Severity:** `high`
- **What to look for:** Enumerate all configured ESPs and for each, count the number of documented rate limits (per-second, per-day, per-month, per-IP warm-up cap). List all ESP limit values found in code comments, constants files, README, or rate limiter configuration. Sending blind to limits is a common cause of deliverability collapse in the Deliverability Engineering Audit's IP reputation category.
- **Pass criteria:** Sending limits for each configured ESP are documented in the codebase or adjacent documentation with at least 2 limit values (e.g., per-second and per-day). The queue rate limiter configuration is set at or below these limits. Before evaluating, quote the exact rate limiter values from the code or config.
- **Fail criteria:** No documentation of ESP sending limits exists. The queue worker fires at full capacity with no configured rate ceiling. Or limits are documented but the rate limiter exceeds them.
- **Skip (N/A) when:** The project sends no email — confirmed by the absence of any ESP SDK in `package.json`.
- **Detail on fail:** `"No ESP volume limits documented — queue concurrency is uncapped relative to ESP tier limits"` or `"SendGrid rate limit is 100/second on the current plan but the queue limiter allows 500/minute — 3x over limit"`
- **Remediation:** Document limits and configure the rate limiter accordingly in a config file (e.g., `src/config/email-limits.ts`):

  ```ts
  // src/config/email-limits.ts
  export const ESP_LIMITS = {
    sendgrid: { perSecond: 100, perDay: 1_000_000 },
    ses: { perSecond: 14, perDay: 50_000 }  // SES sandbox defaults
  } as const

  // BullMQ rate limiter:
  const limiter = { max: 100, duration: 1000 } // 100/second
  ```

  Include the source plan tier and date in a comment so limits can be rechecked when the plan changes.

## External references

- cwe CWE-770
- iso-25010 performance-efficiency.resource-utilization

Taxons: cost-efficiency, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001986
