554 Recipient count exceeds 50 (Amazon SES)
The error, as SES returns it at the end of DATA:
554 Transaction failed: Recipient count exceeds 50If you relay through Mailway, this is already handled
Section titled “If you relay through Mailway, this is already handled”Above a provider’s recipient cap, Mailway rewrites the message so SES accepts it and delivers to everyone. You don’t need to split the send yourself. Skip to what changes for your recipients, because one thing does.
If you send through the HTTP API instead, you never see this
error: the API rejects more than 50 recipients up front with a 422, before
anything is queued.
What SES actually counts
Section titled “What SES actually counts”This is the part that costs people an afternoon. SES does not count the
SMTP envelope. It counts the union of the envelope and the To/Cc/Bcc
header addresses, and it evaluates that count after the DATA
terminator — so every RCPT TO can be accepted with 250 Ok and the
message can still be rejected wholesale a moment later.
Probed against live SES in eu-central-1:
Envelope (RCPT TO) |
To: header |
Result |
|---|---|---|
| 1 | 51 addresses | 554 exceeds 50 |
| 2 | undisclosed-recipients:; (0) |
250 Ok, delivered |
| 51 | undisclosed-recipients:; (0) |
554 exceeds 50 |
Row 1 proves the header alone trips the cap — the envelope held one address. Row 3 proves the envelope still counts too — the header was empty. Both are counted, together.
The consequence is the trap: splitting the envelope alone fixes nothing.
Send 52 recipients as two chunks of 26 RCPT TO while DATA still carries all
52 addresses in To:, and both chunks fail exactly as the unsplit message did.
This also contradicts the intuition most people bring from AWS’s own
“send to multiple recipients” material, which describes the v2 API and its
explicit Destinations argument, where header and envelope are decoupled. On
the SMTP and SendRawEmail path SES re-derives the count from the message
itself. AWS’s troubleshooting documentation is the one that matches observed
behaviour: a recipient is any address on the To:, CC:, or BCC: lines.
What Mailway does about it
Section titled “What Mailway does about it”Above the cap, and only above it, Mailway:
- Removes every
To/Cc/Bccheader from the raw message, including folded continuation lines, and appends one empty group:To: undisclosed-recipients:;. Header count becomes 0. - Chunks the SMTP envelope into groups of at most the provider’s cap and dials once per chunk.
Union per chunk is then 0 + (≤ cap), which SES accepts. This is classic BCC
fan-out.
Two details worth knowing:
- The body is untouched. The rewrite operates on the header block only and
preserves the original line endings, so the body — and therefore the DKIM
body hash — is byte-identical. A sender signature that covered
To/Cc/Bccis invalidated, which is acceptable because SES re-signs the modified headers with your domain’s own DKIM and DMARC aligns on that signature. - It is the only message mutation in the pipeline. Mailway otherwise relays byte-for-byte. This one exception exists because SES cannot accept the message as sent, and it fires only when the recipient count exceeds the cap. At or below the cap, nothing is rewritten and the envelope is never even computed.
The cap is a per-provider property, not an SES special case. Both SES transports declare 50; providers that impose no such limit take the ordinary single-dial path untouched.
What changes for your recipients
Section titled “What changes for your recipients”Because the send becomes a BCC:
- Recipients no longer see each other. Each one sees only the sender and
undisclosed-recipients:;. - Reply-all reaches the sender only, not the group.
That is the visible cost of SES accepting the message at all, and it’s the industry-standard handling of large recipient sets. If mutual visibility matters for a particular send, keep it under the cap.
Your own records are unaffected. The console mail list, the message detail,
and share links read the stored recipient set from the database, not the
transmitted headers — so you still see everyone who received it, even though
the wire headers say undisclosed-recipients:;.
How we know
Section titled “How we know”The first fix Mailway shipped for this was wrong, and the way it failed is why the table above exists.
A company-wide announcement — roughly 52 addresses, all in To: — was
rejected wholesale, retried five times, and dead-lettered. The obvious reading
was ordinary envelope fan-out, so the first patch split the envelope into
chunks of 50 and kept the message byte-identical across them.
It deployed, and the same 554 kept firing. The transcript held the proof:
chunk one sent exactly 50 RCPT TO, every one answered 250 Ok, and SES
rejected only after DATA. If SES counted the envelope, 50 ≤ 50 would have
passed. The failure pointed straight at the headers, and the three probes above
confirmed it.
Related
Section titled “Related”- SMTP relay — the relay’s fidelity guarantees and this exception
- Limits & quotas — recipient caps per path
- Troubleshooting — the full symptom index
Cookie consent
We run ads. Knowing whether they work needs your OK for one cookie each from Google and Reddit, used only to tie a signup back to the ad that brought it. Analytics here is cookieless either way, and declining changes nothing else.
Change your mind any time with "Cookie choices" in the footer. Details in the privacy policy.