Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/content/docs/email-service/api/send-emails/smtp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ Thanks for signing up.
221 mx.cloudflare.net Cloudflare Email ESMTP Service closing transmission channel
```

The `250 2.0.0 Ok` response after the message body includes the assigned Message-ID. Use it to correlate the submission with delivery logs in the dashboard.
A `250 2.0.0 Ok` response after the message body normally includes the assigned Message-ID. Use it to correlate the submission with delivery logs in the dashboard.

When **Drop suppressed recipients** is on and all recipients are suppressed, SMTP may return `250 2.0.0 Ok` without a Message-ID and deliver nothing. Refer to [Suppressed recipients](#suppressed-recipients).

## Examples

Expand Down Expand Up @@ -134,6 +136,20 @@ Cloudflare's SMTP server returns standard [RFC 5321](https://datatracker.ietf.or
| `552 5.3.4` | Message exceeds the 5 MiB `SIZE` limit. |
| `554` | Transaction failed — content rejected by policy. |

## Suppressed recipients

SMTP accepts a syntactically valid recipient with `250 2.1.5 Ok` during `RCPT TO`. Email Service checks the [suppression list](/email-service/concepts/suppressions/) for the account after receiving the message body.

Behavior depends on the per-sending-domain [**Drop suppressed recipients** setting](/email-service/configuration/domains/#drop-suppressed-recipients). The setting is off by default.

When the setting is off, any suppressed recipient causes SMTP to reject the entire message. When the setting is on, Email Service removes suppressed recipients and continues processing the remaining recipients.

If all recipients are suppressed while dropping is on, SMTP may return `250 2.0.0 Ok` without a Message-ID. It delivers nothing in this case.

Use [Email sending logs](/email-service/observability/logs/) to confirm delivery. Suppressed recipients appear with a **Rejected** result.

Suppression produces a `message.rejected` event in [Email Sending event subscriptions](/email-service/platform/event-subscriptions/) with `rejection.reason` set to `suppressed`.

## Troubleshooting

### `535 5.7.8 Authentication failed`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ The following error codes may be returned when sending emails:
| `E_TOO_MANY_ATTACHMENTS` | Too many attachments in `attachments` array | `attachments` array exceeds 32 entries |
| `E_SENDER_NOT_VERIFIED` | Sender domain not verified | Attempting to send from unverified domain |
| `E_RECIPIENT_NOT_ALLOWED` | Recipient not in allowed list | Recipient address not in `allowed_destination_addresses` |
| `E_RECIPIENT_SUPPRESSED` | Recipient is on suppression list | Email address has bounced or reported your emails as spam |
| `E_RECIPIENT_SUPPRESSED` | Suppressed recipient while dropping is off | At least one recipient is suppressed and **Drop suppressed recipients** is off |
| `E_SENDER_DOMAIN_NOT_AVAILABLE` | Domain not available for sending | Domain not onboarded to Email Service |
| `E_CONTENT_TOO_LARGE` | Email content exceeds size limit | Total message size exceeds the maximum |
| `E_DELIVERY_FAILED` | Could not deliver the email | SMTP delivery failure, recipient server rejection |
Expand All @@ -205,6 +205,8 @@ The following error codes may be returned when sending emails:
| `E_HEADERS_TOO_LARGE` | Headers payload too large | Total custom headers exceed 16 KB limit |
| `E_HEADERS_TOO_MANY` | Too many headers | More than 20 allowlisted (non-X) custom headers |

**Drop suppressed recipients** is off by default. When you [turn on the setting](/email-service/configuration/domains/#drop-suppressed-recipients), Email Service removes suppressed recipients and processes the remaining recipients.

## Legacy `EmailMessage` API

The `EmailMessage` API remains supported for backward compatibility. Use it when you already have a raw [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322) MIME message to send. For new code, prefer the structured [`send()` method](#send-method) above.
Expand Down
13 changes: 7 additions & 6 deletions src/content/docs/email-service/concepts/deliverability.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ Bounces occur when emails cannot be delivered to recipients. There are two types

Hard bounces are permanent delivery failures that occur when:

- Email address doesn't exist (`user@domain.com` → No such user)
- Domain does not exist (`user@nonexistentdomain.com`)
- Recipient server permanently blocks your domain
- Content rejected as spam by recipient filters
- The recipient address does not exist.
- The recipient domain does not exist.
- The receiving server permanently rejects the recipient.

**Hard bounces are never retried** because the failure is permanent. Emails that hard bounce will generate a bounce notification to the sender address and can be monitored through [analytics](/email-service/observability/metrics-analytics/).

Hard bounced addresses are automatically added to your [suppression list](/email-service/concepts/suppressions/) to protect your sender reputation.
Email Service adds eligible recipient-side hard bounces to your [suppression list](/email-service/concepts/suppressions/). Suppressions have no expiration when the mailbox or domain does not exist.

They also have no expiration when the recipient remains unavailable across repeated delivery attempts. Other eligible hard-bounce suppressions last seven days.

### Soft bounces

Expand All @@ -38,7 +39,7 @@ Soft bounces are temporary failures that may succeed if retried:
- Email server temporarily down
- Rate limiting or greylisting

Cloudflare automatically retries soft bounces with exponential backoff over an extended period.
Cloudflare automatically retries soft bounces with exponential backoff. Eligible recipient-side failures create a 24-hour suppression.

## Reputation management

Expand Down
16 changes: 5 additions & 11 deletions src/content/docs/email-service/concepts/email-lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,27 @@ flowchart LR
### Stage details

1. **Request received:** The system validates the email format, sender authorization, and message structure. Invalid requests are rejected immediately and do not proceed to the next stage.

2. **Rate limit check:** The system checks sending [limits](/email-service/platform/limits/) per account, domain, and recipient to prevent abuse. Requests that exceed these limits are temporarily rejected and must be retried later.

3. **Authentication and reputation**: The system performs email authentication checks and evaluates sender reputation:
- **SPF (Sender Policy Framework)**: Verifies that the sending IP address is authorized to send emails for the domain by checking DNS TXT records. This prevents domain spoofing and improves deliverability.
- **DKIM (DomainKeys Identified Mail)**: Validates the email's cryptographic signature to ensure message integrity and authenticate the sender domain. This builds trust with recipient servers.
- **DMARC (Domain-based Message Authentication)**: Applies domain owner policies for handling emails that fail SPF or DKIM checks, helping prevent phishing and brand impersonation while providing feedback reports.

These authentication mechanisms work together to establish sender legitimacy and protect against email fraud. Senders with low reputation scores may experience throttling or delayed processing.

4. **Suppression list check:** The system checks the recipient against your account's suppression list, which includes bounces, complaints, and unsubscribes. Recipients found on this list are blocked from receiving the email.
4. **Suppression list check:** The system checks each recipient against the Email Sending [suppression list](/email-service/concepts/suppressions/) for your account. Suppressed recipients do not reach the delivery stage or count toward your quota.

The per-sending-domain [**Drop suppressed recipients** setting](/email-service/configuration/domains/#drop-suppressed-recipients) is off by default. When off, the REST API returns `400`, the Workers binding throws `E_RECIPIENT_SUPPRESSED`, and SMTP rejects the message if any recipient is suppressed.

When on, Email Service removes suppressed recipients and processes the remaining recipients. Email Service does not process unsubscribe links, so add unsubscribed recipients manually.

5. **Delivery attempt:** The system connects to the recipient's mail server and attempts message delivery via SMTP. When delivery fails, the system applies different retry logic based on the failure type:
- **Soft bounces (4xx responses)**: The system retries delivery using exponential backoff timing
- **Hard bounces (5xx responses)**: The system marks the email as permanently failed with no retry attempts

6. **Server response handling:** The system processes SMTP response codes from the recipient server to determine the final email status:
- **2xx codes**: The email was delivered successfully
- **4xx codes**: Temporary failure occurred and the email will be retried
- **5xx codes**: Permanent failure occurred and the email cannot be delivered

7. **Final status and metrics:** Based on the server response, the system assigns emails one of these final statuses:
- **Delivered**: The email was successfully accepted by the recipient server
- **Delivery failed**: The email permanently failed delivery (hard bounce) or exceeded the maximum retry attempts (soft bounce). This status appears as `deliveryFailed` when querying the [GraphQL Analytics API](/email-service/observability/metrics-analytics/).
Expand Down Expand Up @@ -82,18 +82,12 @@ flowchart LR
### Stage details

1. **SMTP receipt:** A sending server connects to a Cloudflare MX server and submits the message over SMTP. Messages larger than the [inbound message size limit](/email-service/platform/limits/) are rejected at this stage.

2. **Authentication check:** The system performs [SPF, DKIM, DMARC, and ARC](/email-service/concepts/email-authentication/) checks on the incoming message. Mail that fails authentication according to the sender's DMARC policy is rejected. Mail from IP addresses on a Realtime Block List is also rejected at this stage. Refer to [Postmaster information](/email-service/reference/postmaster/) for details.

3. **Rule match:** The system matches the recipient address against your configured [routing rules](/email-service/configuration/email-routing-addresses/). If [subaddressing](/email-service/configuration/email-routing-addresses/#subaddressing) is enabled, sub-addressed recipients fall back to the base routing rule. If no rule matches and the [catch-all rule](/email-service/configuration/email-routing-addresses/#catch-all-rule) is enabled, the catch-all rule applies.

4. **Action:** The system applies the matched rule's action:
- **Send to an email**: The message is forwarded to the verified destination address (stage 5).
- **Send to a Worker**: The message is passed to your [Worker](/email-service/api/route-emails/email-handler/). The Worker can call `forward()`, `reply()`, or `setReject()`.
- **Drop**: The message is silently discarded. No further processing occurs.

5. **ARC sign and SRS rewrite:** For forwarded messages, the system adds an ARC seal preserving the original authentication results and rewrites the envelope sender using the [Sender Rewriting Scheme](/email-service/reference/postmaster/#sender-rewriting). This allows SPF to pass at the destination server.

6. **Outbound delivery:** The system connects to the destination mail server and delivers the message. Soft bounces are retried with exponential backoff. Hard bounces are returned to the original sender in-session as upstream SMTP errors. Refer to [Postmaster: SMTP errors](/email-service/reference/postmaster/#smtp-errors).

7. **Final status and metrics:** The final outcome is recorded and available through the [Activity log](/email-service/observability/logs/) and the [GraphQL Analytics API](/email-service/observability/metrics-analytics/).
Loading