recipient_suppressed
HTTP 422 retryable: false REST and MCP
At least one address on this send is suppressed, so the message was refused before it reached the mail provider.
Why it happens
Before a live send commits, every unique recipient across to, cc and bcc is hashed and checked against the active suppressions table. A suppression matches at one of two scopes: the workspace that is sending, or the provider account behind it. The provider-account scope is the one that catches people out, because a hard bounce or a spam complaint recorded through one workspace protects every workspace on that account from sending to the same address again. The lookup is on a SHA-256 of the address, so the suppression list does not need to hold the address in the clear to enforce it.
Every condition below was read in the implementation at the file and line given. They are the branches that raise this code, not a summary of what the name suggests.
- An active suppression row matches the SHA-256 of any unique recipient, at workspace scope or at provider-account scope. Checked on the live send path only.
packages/domain/src/services.ts:4516
How to fix it
- Remove the address from the recipient list. Nothing about this send will succeed while it is included.
- Find out why it was suppressed. A hard bounce and a spam complaint are both permanent signals and neither is safe to override.
- Send to the remaining recipients as a separate request. One suppressed address refuses the whole send, so splitting is the only way through.
- Do not retry. This is marked retryable: false and the suppression will still be there.
Why it works this way
One suppressed recipient refuses the entire message rather than being silently dropped from the list. A partial send that reports success would leave the caller believing a person received something they did not, and that is a worse failure than an explicit refusal.
Messages you will see
The message field is written for a human reading a log and is not a contract
value. Branch on code instead. These are the exact strings this code is sent
with today, listed so that a search for one of them lands here.
Where it appears
These are the documented surfaces that raise it. The REST base is https://api.emailforagents.ai/v1, and the remote MCP endpoint is https://mcp.emailforagents.ai/mcp.
POST /projects/{project_id}/inboxes/{inbox_id}/messagesMCP tool: send_message
The response
Read request_id off the body or the x-request-id header before
doing anything else. It is the only handle on one specific attempt, and for a 503 it is
the only handle at all, because the underlying detail stays server-side.
HTTP/1.1 422
content-type: application/json
x-request-id: req_...
{
"error": {
"code": "recipient_suppressed",
"message": "A recipient is on the suppression list.",
"request_id": "req_...",
"retryable": false
}
}
Verified against packages/domain/src/services.ts:4516. The status comes from ERROR_STATUS in packages/contracts/src/errors.ts, which is the one
place a code is mapped to a status.