Amazon SES

Amazon SES BCC Not Working

Amazon SES BCC recipients are skipped when absent from the API envelope. Add every BCC address to Destinations or BccAddresses — not just the mail header.

Updated Jul 1, 2026

The short answer

"Amazon SES BCC not working" means BCC recipients you set on an email never receive it. It is not an SES error code. The usual cause is the envelope: SES delivers to the addresses in the API's recipient parameter (Destinations for SendRawEmail, BccAddresses for SendEmail), not to a Bcc: header. Fix it by adding every BCC address to that parameter, or omit Destinations so SES reads your raw headers.

"Amazon SES BCC not working" is not an SES error code or SMTP reply. It is a symptom: a message sends successfully (SES returns a MessageId), the To/CC recipients receive it, but the people you added as BCC never do. The cause is almost always how SES decides whom to deliver to — the envelope — versus what you put in the message headers.

Why don't my SES BCC recipients receive the email?

SES delivers a message to the recipients named in the API request's recipient parameter (the SMTP envelope), not to whatever appears on a Bcc: header line.

  • SendRawEmail with a Destinations parameter: when you supply Destinations, SES uses it to build the SMTP envelope, which determines actual delivery independent of the To/CC/BCC headers in your raw MIME. This envelope-vs-header behavior is documented AWS SMTP semantics, corroborated by widely reported SDK issues such as symfony/symfony#35037 and symfony/symfony#36333 — though AWS's SendRawEmail API reference itself only defines Destinations as "a list of destinations for the message, consisting of To:, CC:, and BCC: addresses," without using the word "overrides." If a BCC address is on a Bcc: header but is missing from Destinations, SES will not deliver to it.
  • SendRawEmail without Destinations: SES reads recipients from the To/CC/BCC headers in the raw message. The catch — and the most common library bug (e.g. symfony/symfony#36333) — is that many MIME builders strip the Bcc: header when serializing the message to raw bytes, so by the time SES parses it, the BCC recipient is gone entirely.
  • SendEmail (SES API v1) / SendEmail (SES API v2, SESv2): you pass BCC addresses in the Destination object's BccAddresses array. If that array is empty, no BCC is sent regardless of any header. (SendEmail API reference)

Other reasons a BCC recipient gets nothing even when addressed correctly: your account is still in the SES sandbox (you can only send to verified addresses, BCC included); the address is on your account-level or global suppression list; or the message landed in the recipient's spam folder. (SES delivery troubleshooting)

Note on the older guidance for this page: SES does not reject a message because the same address appears in both To and BCC, and "the BCC address does not exist" is not how SES reports failures. SES only rejects the whole message synchronously if an address is syntactically invalid (not user@domain.tld); a nonexistent-but-valid mailbox produces an asynchronous bounce, not a send-time error.

How do I fix SES BCC not working?

  1. Confirm whether you call SendRawEmail or SendEmail. Check your SDK/library code or SES sending logs.
  2. For SendRawEmail: put every recipient — To, CC, and BCC — into the Destinations array. The simplest reliable pattern is to list all recipients (including BCC) in Destinations and not rely on a Bcc: header for delivery. If you instead want SES to read headers, omit Destinations and verify your library actually keeps the Bcc: header in the serialized raw message.
import boto3
client = boto3.client("ses", region_name="us-east-1")
raw = b"From: sender@example.com\r\nTo: to@example.com\r\nSubject: Hi\r\n\r\nBody"
client.send_raw_email(
Source="sender@example.com",
Destinations=["to@example.com", "bcc@example.com"], # BCC must be here; do not add a Bcc: header to raw -- Destinations alone controls delivery
RawMessage={"Data": raw},
)

Because Destinations is the envelope, bcc@example.com receives the message and stays hidden from other recipients — you do not need (and should not add) a visible Bcc: header.

  1. For SendEmail: populate Destination.BccAddresses directly.
client.send_email(
Source="sender@example.com",
Destination={
"ToAddresses": ["to@example.com"],
"BccAddresses": ["bcc@example.com"],
},
Message={"Subject": {"Data": "Hi"}, "Body": {"Text": {"Data": "Body"}}},
)
  1. Rule out account-level blocks: confirm the account is out of the sandbox, the BCC address is verified if you are still in sandbox, and the address is not on your suppression list.
  2. Verify, don't assume: a successful MessageId only means SES accepted the message — it does not mean every envelope recipient was delivered. Enable a configuration set with event publishing and watch for Delivery/Bounce events per recipient.

If you send through Courier with SES as a provider, Courier maps your recipients to the SES envelope for you — set BCC at the channel/provider override level rather than hand-building a Bcc: header.

FAQ

Common questions

No. SES has no duplicate-recipient rejection rule. It deduplicates delivery and only rejects the whole message synchronously when an address is syntactically invalid (not in user@domain.tld form). A duplicate To/BCC address is not an error.

One API, every provider

Stop debugging raw provider errors

Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.

Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.