Skip to content

Commit 0b7bffd

Browse files
committed
Migrate more email routing docs to email service
1 parent f434b00 commit 0b7bffd

File tree

9 files changed

+266
-64
lines changed

9 files changed

+266
-64
lines changed

src/content/docs/email-routing/index.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ Create custom email addresses for your domain and route incoming emails to your
2222

2323
</Description>
2424

25+
:::note[Email Routing is now part of Email Service]
26+
Email Routing is now integrated into [Cloudflare Email Service](/email-service/), a complete email product suite. Email Service provides all the routing capabilities you already use, plus the ability to send emails from Workers or external servers using a REST API.
27+
28+
For new projects, refer to the [Email Service documentation](/email-service/). Existing Email Routing configurations continue to work without changes.
29+
:::
30+
2531
<Plan id="email.email_routing.properties.availability.summary" />
2632

2733
<Render file="email-routing-definition" product="email-routing" />

src/content/docs/email-service/api/send-emails/rest-api.mdx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,22 +149,34 @@ A successful response returns the delivery status for each recipient:
149149

150150
## Error handling
151151

152-
The REST API returns standard Cloudflare API error responses. A failed request returns an `errors` array with numeric error codes:
152+
The REST API returns standard Cloudflare API error responses. A failed request returns an `errors` array with numeric error codes and machine-readable messages:
153153

154154
```json
155155
{
156156
"success": false,
157157
"errors": [
158158
{
159-
"code": 1000,
160-
"message": "Sender domain not verified"
159+
"code": 10001,
160+
"message": "email.sending.error.invalid_request_schema"
161161
}
162162
],
163163
"messages": [],
164164
"result": null
165165
}
166166
```
167167

168+
Common REST API error codes:
169+
170+
| HTTP Status | Code | Message | Description |
171+
| ----------- | ---- | ------- | ----------- |
172+
| 400 | 10001 | `email.sending.error.invalid_request_schema` | Invalid request format |
173+
| 400 | 10200 | `email.sending.error.email.invalid` | Invalid email content |
174+
| 400 | 10201 | `email.sending.error.email.no_content_length` | Missing content length |
175+
| 400 | 10202 | `email.sending.error.email.too_big` | Email exceeds size limit |
176+
| 403 | 10203 | `email.sending.error.email.sending_disabled` | Sending disabled for this zone/account |
177+
| 429 | 10004 | `email.sending.error.throttled` | Rate limit exceeded |
178+
| 500 | 10002 | `email.sending.error.internal_server` | Internal server error |
179+
168180
:::note[Workers binding vs REST API errors]
169181
The REST API returns standard Cloudflare API numeric error codes, while the [Workers binding](/email-service/api/send-emails/workers-api/) throws errors with string codes (for example, `E_SENDER_NOT_VERIFIED`). Refer to the [Workers API error codes table](/email-service/api/send-emails/workers-api/#error-codes) for the string error codes.
170182
:::

src/content/docs/email-service/concepts/email-lifecycle.mdx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ flowchart LR
5252

5353
7. **Final status and metrics:** Based on the server response, the system assigns emails one of these final statuses:
5454
- **Delivered**: The email was successfully accepted by the recipient server
55-
- **Bounced**: The email permanently failed delivery (hard bounce) or exceeded the maximum retry attempts (soft bounce)
56-
---
55+
- **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/).
5756

5857
Understanding the email lifecycle helps you build robust email applications that handle all possible outcomes and provide excellent user experiences through proper status tracking and error handling.

src/content/docs/email-service/configuration/domains.mdx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ export default {
338338
from: "contact@company.com",
339339
to: "client@example.com",
340340
subject: "Corporate Communication",
341+
text: "Thank you for your business.",
341342
});
342343
}
343344

@@ -346,6 +347,7 @@ export default {
346347
from: "updates@product.company.com",
347348
to: "user@example.com",
348349
subject: "Product Update",
350+
text: "We have a new product update for you.",
349351
});
350352
}
351353
},
@@ -369,6 +371,39 @@ Removing a domain will:
369371
- Require reconfiguration if re-added
370372
:::
371373

374+
### DNS record management
375+
376+
When you remove a domain from Email Service, you have two options for handling the DNS records:
377+
378+
**Option 1: Remove all records**
379+
380+
This removes all Email Service DNS records from your domain:
381+
382+
- All SPF, DKIM, and MX records for Email Service are deleted
383+
- Your domain will no longer receive or send emails through Email Service
384+
- If you want to use Email Service again in the future, you will need to onboard the domain and add all records from scratch
385+
386+
**Option 2: Keep records**
387+
388+
This keeps the DNS records in place but disables Email Service:
389+
390+
- DNS records remain in your domain configuration
391+
- Email Service stops processing emails for the domain
392+
- You can re-enable Email Service by onboarding the domain again
393+
- DNS records that were automatically added will remain locked to prevent accidental deletion
394+
395+
To modify locked records after removal:
396+
397+
1. Go to your domain's **DNS** > **Records**.
398+
2. Find the locked Email Service records.
399+
3. Select the record and choose **Edit**.
400+
4. Toggle **Unlock record** to enable editing.
401+
5. Make your changes and save.
402+
403+
:::note
404+
Keeping records is useful if you plan to re-enable Email Service later. Removing records is recommended if you are migrating to a different email provider.
405+
:::
406+
372407
### Transfer domain ownership
373408

374409
1. Domain must remain in the same Cloudflare account.

src/content/docs/email-service/configuration/email-routing-addresses.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ Your email rule is now disabled. It will not forward emails to a destination add
6666
3. In **Custom addresses**, identify the email rule you want to edit, and select **Edit**.
6767
4. Make the appropriate changes to this custom address.
6868

69+
### Delete a custom address
70+
71+
1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and select your account and domain.
72+
2. Go to **Email** > **Email Routing** > **Routes**.
73+
3. In **Custom addresses**, identify the email rule you want to delete.
74+
4. Select **Delete** and confirm the action.
75+
76+
:::warning
77+
Deleting a custom address will permanently remove the routing rule. Emails sent to this address will no longer be routed. If you want to temporarily stop routing without deleting the rule, refer to [Disable an email rule](#disable-an-email-rule).
78+
:::
79+
6980
## Catch-all address
7081

7182
When you enable this feature, Email Routing will catch variations of email addresses to make them valid for the specified domain. For example, if you created an email rule for `info@example.com` and a sender accidentally types `ifno@example.com`, the email will still be correctly handled if you have **Catch-all addresses** enabled.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
title: Configure MTA-STS
3+
pcx_content_type: how-to
4+
sidebar:
5+
order: 4
6+
---
7+
8+
import { DashButton } from "~/components";
9+
10+
MTA Strict Transport Security ([MTA-STS](https://datatracker.ietf.org/doc/html/rfc8461)) was introduced by email service providers including Microsoft, Google and Yahoo as a solution to protect against downgrade and man-in-the-middle attacks in SMTP sessions, as well as solving the lack of security-first communication standards in email.
11+
12+
Suppose that `example.com` is your domain and uses Email Service. Here is how you can enable MTA-STS for it.
13+
14+
1. In the Cloudflare dashboard, go to the **Records** page.
15+
16+
<DashButton url="/?to=/:account/:zone/dns/records" />
17+
18+
2. Create a new CNAME record with the name `_mta-sts` that points to Cloudflare’s record `_mta-sts.mx.cloudflare.net`. Make sure to disable the proxy mode.
19+
20+
![MTA-STS CNAME record](~/assets/images/email-routing/mta-sts-record.png)
21+
22+
3. Confirm that the record was created:
23+
24+
```sh
25+
dig txt _mta-sts.example.com
26+
```
27+
28+
```sh output
29+
_mta-sts.example.com. 300 IN CNAME _mta-sts.mx.cloudflare.net.
30+
_mta-sts.mx.cloudflare.net. 300 IN TXT "v=STSv1; id=20230615T153000;"
31+
```
32+
33+
This tells the other end client that is trying to connect to us that we support MTA-STS.
34+
35+
Next you need an HTTPS endpoint at `mta-sts.example.com` to serve your policy file. This file defines the mail servers in the domain that use MTA-STS. The reason why HTTPS is used here instead of DNS is because not everyone uses DNSSEC yet, so we want to avoid another MITM attack vector.
36+
37+
To do this you need to deploy a Worker that allows email clients to pull Cloudflare’s Email Service policy file using the “well-known” URI convention.
38+
39+
4. Go to your **Account** > **Workers & Pages** and select **Create**. Pick the default "Hello World" option button, and replace the sample worker code with the following:
40+
41+
```js
42+
export default {
43+
async fetch(request, env, ctx) {
44+
return await fetch(
45+
"https://mta-sts.mx.cloudflare.net/.well-known/mta-sts.txt",
46+
);
47+
},
48+
};
49+
```
50+
51+
This Worker proxies `https://mta-sts.mx.cloudflare.net/.well-known/mta-sts.txt` to your own domain.
52+
53+
5. After deploying it, go to the Worker configuration, then **Settings** > **Domains & Routes** > **+Add**. Type the subdomain `mta-sts.example.com`.
54+
55+
![MTA-STS Worker Custom Domain](~/assets/images/email-routing/mta-sts-domain.png)
56+
57+
You can then confirm that your policy file is working with the following:
58+
59+
```sh
60+
curl https://mta-sts.example.com/.well-known/mta-sts.txt
61+
```
62+
63+
```sh output
64+
version: STSv1
65+
mode: enforce
66+
mx: *.mx.cloudflare.net
67+
max_age: 86400
68+
```
69+
70+
This says that you domain `example.com` enforces MTA-STS. Capable email clients will only deliver email to this domain over a secure connection to the specified MX servers. If no secure connection can be established the email will not be delivered.
71+
72+
Email Service also supports MTA-STS upstream, which greatly improves security when forwarding your emails to service providers like Gmail, Microsoft, and others.
73+
74+
---
75+
76+
For more information about domain security and email authentication, refer to [Email authentication](/email-service/concepts/email-authentication/).

src/content/docs/email-service/examples/email-sending/signup-flow.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ async function handleSignup(request: Request, env: Env): Promise<Response> {
7373

7474
// Generate verification token (expires in 1 hour)
7575
const verificationToken = crypto.randomUUID();
76-
await env.VERIFICATION_TOKENS.put(verificationToken, userId, {
76+
await env.VERIFICATION_TOKENS.put(verificationToken, email, {
7777
expirationTtl: 3600,
7878
});
7979

@@ -124,13 +124,13 @@ async function handleVerification(
124124
}
125125

126126
// Verify token
127-
const userId = await env.VERIFICATION_TOKENS.get(token);
128-
if (!userId) {
127+
const userEmail = await env.VERIFICATION_TOKENS.get(token);
128+
if (!userEmail) {
129129
return new Response("Invalid or expired token", { status: 400 });
130130
}
131131

132132
// Get and update user
133-
const userData = await env.USERS.get(`user:${userId}`);
133+
const userData = await env.USERS.get(userEmail);
134134
if (!userData) {
135135
return new Response("User not found", { status: 404 });
136136
}

src/content/docs/email-service/observability/logs.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ For outbound emails sent through Email Service:
1818

1919
- **Sent**: Email successfully accepted and queued for delivery
2020
- **Delivered**: Email successfully delivered to recipient's mail server
21-
- **Bounced**: Email bounced (hard or soft bounce)
21+
- **Delivery failed**: Email bounced (hard or soft bounce). This corresponds to the `deliveryFailed` status in the [GraphQL Analytics API](/email-service/observability/metrics-analytics/).
2222
- **Failed**: Email failed to send due to configuration or authentication issues
2323

2424
### Email routing logs
@@ -86,7 +86,7 @@ Based on the information shown in email details, you can:
8686

8787
Use the Activity Log filters to find specific emails:
8888

89-
- **By status**: Filter by delivery status (for example: sent, bounced, delivered)
89+
- **By status**: Filter by delivery status (for example: sent, delivered, delivery failed)
9090
- **By timeframe**: View logs for specific date ranges
9191
- **By sender/recipient**: Search for specific email addresses
9292
- **By authentication**: Filter by SPF/DKIM/DMARC results

0 commit comments

Comments
 (0)