Skip to main content
Each entry follows symptom → cause → fix. Error codes link to the full catalog in Error Codes.

Send returns 422 recipient_suppressed

Cause: One of to/cc/bcc is on your workspace suppression list (hard bounce, complaint, unsubscribe, or manual entry). The check runs before quota is claimed, so nothing was billed. Fix:
  1. Find the row: GET /v1/suppressions and match the address; details.source shows who added it.
  2. If the address is legitimately reachable again (e.g. mailbox restored), remove it: DELETE /v1/suppressions/{id}.
  3. Retry the send. Never re-add complaint addresses without explicit renewed consent.

Send returns 402 — limit_reached vs spend_cap_reached

Cause: Both mean a ceiling stopped the send, but different ones. limit_reached is the monthly/daily allowance or an explicit workspace cap; spend_cap_reached is the spend-protection pause threshold. Fix:
  • limit_reached → enable overage, raise the workspace cap, or upgrade the plan.
  • spend_cap_reached → go to Billing → Spend protection and raise or remove the cap.
  • Daily caps reset at midnight UTC; monthly allowance rolls over at the cycle start.

Send returns 403 sending_not_approved

Cause: Workspace sending is paused — pending manual review, or a reputation tripwire fired (spam-complaint or hard-bounce thresholds). The response may include reason, action, and trippedAt. Fix: Read reason first, clean the cause (stale lists, missing unsubscribe handling), then request sending approval in the console or contact support. Conversational replies stay unaffected only for the bulk tripwire (sending_paused_bulk_review) — a full pause blocks everything.

Message failed — where to look

Cause: Provider rejection, bad recipient, or downstream outage after the send was accepted. Fix:
  1. Read the message row (GET /v1/messages/{id}): status plus errorMessage carry the provider’s reason. A bounce also emits an email.bounced webhook with diagnostic.
  2. Check GET /v1/webhooks/deliveries for the matching event to see whether your endpoint acknowledged it.
  3. Transient provider failures surface as email_delivery_failed (502) with quota refunded — safe to retry. Permanent recipient failures suppress the address instead.

Domain stuck in pending

Cause: DNS records have not propagated, or a record value is wrong. Verification requires the ownership token and the SES MX record; SPF/DKIM/DMARC do not gate it but hurt deliverability when missing. Fix:
  1. Re-run POST /v1/domains/{id}/verify and read verificationReport.records — each entry shows expected vs found with a matched flag, pinpointing the broken record.
  2. Common culprits: TXT value missing the gork-verification= prefix, MX pointing at the wrong region host (must be inbound-smtp.ap-southeast-2.amazonaws.com, priority 10), or resolvers still serving cached negatives — wait out the TTL and retry.
  3. POST /v1/inboxes with the domain keeps returning domain_not_verified (400) until status flips to verified.

Webhook not arriving

Cause: Usually one of: endpoint not subscribed to the event, a terminal 4xx rejection, or a slow handler exceeding the 10-second timeout. Fix:
  1. Confirm subscription: GET /v1/webhookssubscribedEvents must include the event (or "*").
  2. Inspect GET /v1/webhooks/deliveries: a 4xx responseStatus means your endpoint rejected it — no retry will come, fix the handler. A timeout error means the handler took over 10 seconds — acknowledge fast and defer work.
  3. Only rotate the secret (POST /v1/webhooks/{id}/rotate-secret) when verification fails, not when deliveries are missing — rotation breaks a working verifier until both sides are updated.

Sandbox cannot send to multiple recipients

Cause: Free-tier sandbox is 1-on-1 only. More than one to, or any cc/bcc, fails with sandbox_bulk_not_allowed (403). Fix: Send individual messages, or upgrade to a paid plan for bulk sending.

409 address_in_cooldown when creating an inbox

Cause: The address was recently deactivated and sits in a 90-day security quarantine against account takeover. Same-workspace reactivation restores the inbox instead of erroring — only a different workspace claiming it hits this. Fix: Pick another username, or wait — the response includes cooldownDaysRemaining. There is no manual override.

Scheduled message stuck

Cause: A scheduled message only dispatches at its sendAt; if the plan changed, cancel it and start over. Fix:
  1. Cancel: DELETE /v1/messages/{id}/schedule{ "status": "cancelled" }. The row is retained for audit and can never dispatch afterwards.
  2. If cancel returns not_scheduled (409), the message already left scheduled state — read its status instead of retrying the cancel.
  3. Resend fresh via POST /v1/messages/send. Scheduled sends cannot carry attachments (attachments_not_schedulable) — send those immediately instead.