@kurtbruns/kestrel 1.17.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dev.vars.example +24 -2
- package/CHANGELOG.md +73 -1
- package/bin/kestrel.mjs +1 -1
- package/cli/dev.mjs +3 -3
- package/cli/init.mjs +98 -4
- package/dist/public/dashboard/app.js +327 -327
- package/dist/public/dashboard/app.js.map +4 -4
- package/dist/public/dashboard/index.html +6 -3
- package/dist/public/dashboard/styles.css +133 -21
- package/dist/worker/index.js +5940 -4434
- package/docs/README.md +5 -3
- package/docs/get-started/02-deploy.md +25 -21
- package/docs/get-started/03-access.md +20 -8
- package/docs/get-started/04-aws-account.md +68 -0
- package/docs/get-started/05-ses.md +326 -0
- package/docs/get-started/06-production-access.md +67 -0
- package/docs/get-started/{05-verify.md → 07-verify.md} +16 -26
- package/docs/get-started/{06-go-live.md → 08-go-live.md} +4 -2
- package/docs/guides/01-allow-claude.md +2 -2
- package/docs/guides/02-automate.md +1 -1
- package/docs/guides/03-notifications.md +12 -12
- package/docs/guides/07-upgrade.md +4 -4
- package/docs/guides/09-as-your-list-grows.md +8 -18
- package/docs/publishing/02-sending-rules.md +2 -2
- package/docs/publishing/03-name-your-publication.md +2 -0
- package/docs/publishing/04-write-a-post.md +1 -1
- package/docs/publishing/06-troubleshooting.md +37 -9
- package/docs/publishing/08-connect-claude.md +1 -1
- package/docs/publishing/09-share-your-subscribe-link.md +3 -1
- package/docs/publishing/10-check-your-setup.md +15 -9
- package/docs/publishing/README.md +8 -3
- package/docs/reference/01-configuration.md +18 -16
- package/docs/reference/02-sending-domain-dns.md +4 -4
- package/migrations/0015_provider_account.sql +18 -0
- package/migrations/0016_held_receipts.sql +26 -0
- package/migrations/0017_provider_account_rejected.sql +24 -0
- package/migrations/0018_notify_addresses.sql +13 -0
- package/migrations/0019_sending.sql +67 -0
- package/migrations/0020_notifications_not_sending.sql +40 -0
- package/package.json +1 -1
- package/packages/kestrel/lib/api.mjs +28 -3
- package/packages/kestrel/lib/oauth.mjs +5 -3
- package/template/claude/CLAUDE.md +5 -3
- package/template/wrangler.jsonc +6 -6
- package/docs/get-started/04-ses.md +0 -310
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
# Connect Amazon SES
|
|
2
|
-
|
|
3
|
-
This page connects the app to Amazon Simple Email Service (Amazon SES), which delivers the newsletter's email. A new SES account starts in a sandbox, where it can send only to addresses you've verified, until AWS reviews it. This page requests that review early, so you can test in the sandbox while you wait.
|
|
4
|
-
|
|
5
|
-
In this guide, you verify your sending hostname, set a custom MAIL FROM domain, add a DMARC record, and request production access. You then route bounces and complaints to the app, give it an AWS key, and deploy it with SES connected. Last, you forward readers' replies to the publisher's inbox.
|
|
6
|
-
|
|
7
|
-
## Before you begin
|
|
8
|
-
|
|
9
|
-
- An [AWS account](https://portal.aws.amazon.com/billing/signup), if you haven't created one already.
|
|
10
|
-
- The publisher's inbox, for readers' replies.
|
|
11
|
-
|
|
12
|
-
## 1. Verify your sending hostname
|
|
13
|
-
|
|
14
|
-
SES sends only from an identity you've verified. Verifying the whole hostname lets any address on it send, and sets up DKIM, which lets inboxes trust your mail.
|
|
15
|
-
|
|
16
|
-
1. Open the [SES console](https://console.aws.amazon.com/ses/), and choose a region near you in the menu at the top right. SES keeps identities, quotas, and the sandbox separately in each region, so do every step on this page in this one. A few newer regions must be [enabled for your account](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-regions.html) first.
|
|
17
|
-
|
|
18
|
-
1. Note the region's code, such as `eu-west-1`. The menu shows only its name, such as Europe (Ireland), and [Amazon SES endpoints](https://docs.aws.amazon.com/general/latest/gr/ses.html) lists each code beside its name. Later steps use this code.
|
|
19
|
-
|
|
20
|
-
1. Under **Configuration**, choose **Identities**, then **Create identity**.
|
|
21
|
-
|
|
22
|
-
1. Select **Domain**, and enter `send.example.com`. Keep the default DKIM settings, **Easy DKIM** with a 2048-bit key, and choose **Create identity**.
|
|
23
|
-
|
|
24
|
-
1. On the identity's **Authentication** tab, expand **Publish DNS records**. It lists three CNAME records.
|
|
25
|
-
|
|
26
|
-
1. In the Cloudflare dashboard, add each record to your domain's DNS records, exactly as SES lists it, with its proxy status set to **DNS only**. Cloudflare adds your domain to the name, so each name ends in `._domainkey.send`.
|
|
27
|
-
|
|
28
|
-
1. Wait until SES shows **DKIM configuration** as **Successful** and **Identity status** as **Verified**.
|
|
29
|
-
|
|
30
|
-
## 2. Set a custom MAIL FROM domain
|
|
31
|
-
|
|
32
|
-
By default, SES sends with its own return path, so Gmail shows your mail as "mailed-by `amazonses.com`", and only DKIM ties it to your domain. A custom MAIL FROM domain puts your hostname there too, so SPF also passes for your domain. Your mail then still passes DMARC, the check section 3 sets up, if DKIM ever fails. It also meets Gmail's bulk-sender rule to set up SPF for your domain.
|
|
33
|
-
|
|
34
|
-
1. In SES, open the `send.example.com` identity. Under **Custom MAIL FROM domain**, choose **Edit**.
|
|
35
|
-
|
|
36
|
-
1. Select **Use a custom MAIL FROM domain**, and enter `bounce.send.example.com`. For **Behavior on MX failure**, keep **Use default MAIL FROM domain**. Choose **Save changes**.
|
|
37
|
-
|
|
38
|
-
1. In Cloudflare, add the two records SES lists, with your region's code in place of `us-east-1`:
|
|
39
|
-
|
|
40
|
-
- **Type:** `MX`, **Name:** `bounce.send`, **Mail server:** `feedback-smtp.us-east-1.amazonses.com`, **Priority:** `10`
|
|
41
|
-
- **Type:** `TXT`, **Name:** `bounce.send`, **Content:** `v=spf1 include:amazonses.com ~all`
|
|
42
|
-
|
|
43
|
-
1. Wait until SES shows the MAIL FROM domain's status as successful.
|
|
44
|
-
|
|
45
|
-
## 3. Add a DMARC record
|
|
46
|
-
|
|
47
|
-
DMARC tells inboxes what to do with mail that fails its checks, and sends you reports about it. SES doesn't add this record, so you add it yourself. It starts in monitor mode, which reports without blocking anything.
|
|
48
|
-
|
|
49
|
-
1. In the Cloudflare dashboard, open your domain's DNS records, and add a record:
|
|
50
|
-
|
|
51
|
-
- **Type:** `TXT`
|
|
52
|
-
- **Name:** `_dmarc.send`
|
|
53
|
-
- **Content:** `v=DMARC1; p=none; rua=mailto:dmarc@example.com`
|
|
54
|
-
|
|
55
|
-
1. Replace `dmarc@example.com` with an address that receives mail. Reports arrive there as attachments.
|
|
56
|
-
|
|
57
|
-
[Sending-domain DNS](../reference/02-sending-domain-dns.md#dmarc-publish-a-policy-and-collect-reports) explains each record, and when to tighten DMARC.
|
|
58
|
-
|
|
59
|
-
## 4. Request production access
|
|
60
|
-
|
|
61
|
-
A new SES account starts in the sandbox: it sends only to addresses you've verified, up to 200 emails a day and one a second. Ask AWS to lift those limits now, and test while you wait.
|
|
62
|
-
|
|
63
|
-
1. Name the publication, since AWS may visit its website to review the request. In the editor, open **Settings → Publication identity**, and enter the name and tagline, or ask the publisher for them.
|
|
64
|
-
|
|
65
|
-
1. In SES, open the **Account dashboard**, select **View Get set up page**, and then **Request production access**.
|
|
66
|
-
|
|
67
|
-
1. Fill in the request:
|
|
68
|
-
|
|
69
|
-
- **Mail type:** Marketing
|
|
70
|
-
- **Website URL:** `https://newsletter.example.com/`
|
|
71
|
-
|
|
72
|
-
Leave the other fields as they are.
|
|
73
|
-
|
|
74
|
-
1. Check the acknowledgement, and select **Submit request**. AWS Support answers by email, and may ask how you collect addresses and handle bounces.
|
|
75
|
-
|
|
76
|
-
1. Verify two addresses you own, such as a personal address and a work address, so the sandbox lets you mail them. Your test emails go to these. For each, under **Identities**, choose **Create identity**, select **Email address**, and follow the link in the email AWS sends.
|
|
77
|
-
|
|
78
|
-
If AWS asks for more detail, or denies the request, reply in the support case, or open a new request from the **Account dashboard**. Say how Kestrel handles the list:
|
|
79
|
-
|
|
80
|
-
- Signups use double opt-in: each subscriber confirms by email before joining the list.
|
|
81
|
-
- Every post offers one-click unsubscribe.
|
|
82
|
-
- Bounces and complaints reach the app, and it stops mailing those addresses automatically.
|
|
83
|
-
- How many subscribers the newsletter expects, and how often it sends.
|
|
84
|
-
|
|
85
|
-
In the meantime, continue with the rest of this guide.
|
|
86
|
-
|
|
87
|
-
## 5. Send bounces and complaints to the app
|
|
88
|
-
|
|
89
|
-
SES reports bounces and complaints through Amazon Simple Notification Service (SNS), which delivers them to the app. The app then stops mailing an address that bounced or complained. A configuration set says which events SES reports, and an SNS topic carries them.
|
|
90
|
-
|
|
91
|
-
1. In SES, under **Configuration**, choose **Configuration sets**, then **Create set**. Name it `kestrel-mail`, and choose **Create set**.
|
|
92
|
-
|
|
93
|
-
1. On the set's **Event destinations** tab, choose **Add destination**. Select **Hard bounces**, **Complaints**, **Deliveries**, and **Rendering failures**, and choose **Next**. The app logs a rendering failure, an email SES couldn't build, as an error.
|
|
94
|
-
|
|
95
|
-
1. For **Destination type**, select **Amazon SNS**. Name it `kestrel-sns`, and keep **Event publishing** enabled. Choose **Next**.
|
|
96
|
-
|
|
97
|
-
1. For **SNS topic**, choose **Create SNS topic**. Make it a **Standard** topic named `kestrel-events`. Choose **Next**, then **Add destination**.
|
|
98
|
-
|
|
99
|
-
1. Make the set your hostname's default, so SES reports on every email sent from it. Open the `send.example.com` identity, and choose the **Configuration set** tab. Under **Default configuration set**, choose **Edit**, select `kestrel-mail`, and save.
|
|
100
|
-
|
|
101
|
-
1. Open the topic in the [SNS console](https://console.aws.amazon.com/sns/), and find its ARN. It looks like `arn:aws:sns:us-east-1:111122223333:kestrel-events`, where `us-east-1` is your region's code and `111122223333` is your account ID.
|
|
102
|
-
|
|
103
|
-
1. Let SES publish to the topic. Choose **Edit**, expand **Access policy**, and add this statement to the `Statement` list:
|
|
104
|
-
|
|
105
|
-
```json
|
|
106
|
-
{
|
|
107
|
-
"Effect": "Allow",
|
|
108
|
-
"Principal": { "Service": "ses.amazonaws.com" },
|
|
109
|
-
"Action": "sns:Publish",
|
|
110
|
-
"Resource": "REPLACE_WITH_TOPIC_ARN",
|
|
111
|
-
"Condition": {
|
|
112
|
-
"StringEquals": {
|
|
113
|
-
"AWS:SourceAccount": "REPLACE_WITH_ACCOUNT_ID",
|
|
114
|
-
"AWS:SourceArn": "arn:aws:ses:us-east-1:REPLACE_WITH_ACCOUNT_ID:configuration-set/kestrel-mail"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Replace the topic ARN, both copies of the account ID, and `us-east-1` with the values from your ARN. Choose **Save changes**.
|
|
121
|
-
|
|
122
|
-
1. Store the topic's ARN in the app. In your instance's repository, run this, and paste the ARN at the prompt. The app accepts events only from this topic:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
npx wrangler secret put SNS_TOPIC_ARN --env production
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
1. Store the configuration set's name, `kestrel-mail`. It's optional but recommended: the app names the set on every email, so SES reports on each one even without the hostname's default. Type it exactly as the set is named in this region, since SES refuses every email that names a set it can't find:
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
npx wrangler secret put SES_CONFIGURATION_SET --env production
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## 6. Create the app's AWS key
|
|
135
|
-
|
|
136
|
-
The app sends through an AWS Identity and Access Management (IAM) user whose key can only send email. That limits the harm if the key ever leaks.
|
|
137
|
-
|
|
138
|
-
1. In the [IAM console](https://console.aws.amazon.com/iam/), go to **Users**, and choose **Create user**. Name it `kestrel-sender`, and leave console access off.
|
|
139
|
-
|
|
140
|
-
1. When asked for permissions, choose **Attach policies directly**, then **Create policy**. The policy editor opens in a new browser tab.
|
|
141
|
-
|
|
142
|
-
1. In the new tab, choose the **JSON** editor, and replace its contents with this policy:
|
|
143
|
-
|
|
144
|
-
```json
|
|
145
|
-
{
|
|
146
|
-
"Version": "2012-10-17",
|
|
147
|
-
"Statement": [
|
|
148
|
-
{
|
|
149
|
-
"Effect": "Allow",
|
|
150
|
-
"Action": ["ses:SendEmail", "ses:SendBulkEmail"],
|
|
151
|
-
"Resource": "*"
|
|
152
|
-
}
|
|
153
|
-
]
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Choose **Next**, name the policy `kestrel-send-email`, and choose **Create policy**. You can close this tab.
|
|
158
|
-
|
|
159
|
-
1. Go back to the first tab, where you're creating the user. Refresh the policy list, search for `kestrel-send-email`, and select it.
|
|
160
|
-
|
|
161
|
-
1. Choose **Next**, then **Create user**.
|
|
162
|
-
|
|
163
|
-
1. Open the user, and on the **Security credentials** tab, choose **Create access key**. For the use case, choose **Application running outside AWS**.
|
|
164
|
-
|
|
165
|
-
1. Keep the page open: AWS shows the secret access key only once. Store the access key ID in the app, and paste it at the prompt:
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
npx wrangler secret put AWS_ACCESS_KEY_ID --env production
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
1. Store the secret access key:
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
npx wrangler secret put AWS_SECRET_ACCESS_KEY --env production
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## 7. Set the provider and deploy
|
|
178
|
-
|
|
179
|
-
Until now the app has run with no email provider connected, refusing to send. Setting `PROVIDER` to `ses` connects SES, with the secrets you stored in sections 5 and 6. If a required one is missing, the app refuses to run until you store it, and `/health` names it.
|
|
180
|
-
|
|
181
|
-
1. In `wrangler.jsonc`, edit the `production` block's `vars`. Change `PROVIDER` to `ses` (it's `""` on a new instance; add it if your block has none), and add `SES_MAX_SEND_RATE`. Change `AWS_REGION` to your region's code from section 1. Your other values stay as they are. The block ends up like this:
|
|
182
|
-
|
|
183
|
-
```jsonc
|
|
184
|
-
"vars": {
|
|
185
|
-
"PROVIDER": "ses", // ← set to ses
|
|
186
|
-
"APP_ORIGIN": "https://newsletter.example.com",
|
|
187
|
-
"ARCHIVE_BASE_PATH": "/archive",
|
|
188
|
-
"SENDING_DOMAIN": "send.example.com",
|
|
189
|
-
"FROM_ADDRESS": "Newsletter <newsletter@send.example.com>",
|
|
190
|
-
"AWS_REGION": "us-east-1", // ← change: your region's code
|
|
191
|
-
"SES_MAX_SEND_RATE": "1" // ← new: your maximum send rate; 1 in the sandbox
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
On Workers Paid, also add `"SUBREQUEST_BUDGET": "10000"`, the plan's limit, so each minute sends more. Leave it out on Workers Free, which suits a list of up to about 1,000 subscribers. [As your list grows](../guides/09-as-your-list-grows.md) says why.
|
|
196
|
-
|
|
197
|
-
When AWS grants production access, set `SES_MAX_SEND_RATE` to the maximum send rate on the **Account dashboard**, and deploy again. The app keeps to that rate, so SES doesn't throttle your send.
|
|
198
|
-
|
|
199
|
-
1. Commit the change, and push it:
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
git commit -am "Send through Amazon SES"
|
|
203
|
-
git push
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
1. Deploy:
|
|
207
|
-
|
|
208
|
-
```bash
|
|
209
|
-
npx wrangler deploy --env production
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## 8. Subscribe the app to the topic
|
|
213
|
-
|
|
214
|
-
SNS delivers events only to a subscriber that has confirmed. The app confirms on its own, once it checks that the request came from your topic.
|
|
215
|
-
|
|
216
|
-
1. In the SNS console, open your topic, and choose **Create subscription**.
|
|
217
|
-
|
|
218
|
-
1. Set **Protocol** to **HTTPS**, and enter the endpoint:
|
|
219
|
-
|
|
220
|
-
```
|
|
221
|
-
https://newsletter.example.com/webhooks/ses
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
1. Leave raw message delivery off, and choose **Create subscription**.
|
|
225
|
-
|
|
226
|
-
1. Reload the subscription. Its status changes to **Confirmed**, with nothing for you to click.
|
|
227
|
-
|
|
228
|
-
If it stays **Pending confirmation**, check that your Access application covers only `/dashboard` and `/api`, that `SNS_TOPIC_ARN` matches the topic's ARN, and that section 7's deploy finished. A mismatched ARN shows in the app's logs as a `webhook.refused` error naming both. Then request confirmation again from the topic's subscriptions. SNS doesn't let you delete a pending subscription, and removes it on its own after 48 hours.
|
|
229
|
-
|
|
230
|
-
1. Give SNS longer to retry. By default it retries a failed delivery 3 times over about a minute, then discards the event, so a bounce that arrives mid-deploy is lost. Open the topic, choose **Edit**, and expand **Delivery retry policy (HTTP/S)**. Turn off the default policy, set these values, and choose **Save changes**:
|
|
231
|
-
|
|
232
|
-
| Field | Value |
|
|
233
|
-
| --- | --- |
|
|
234
|
-
| Number of retries | `13` |
|
|
235
|
-
| Retries without delay | `0` |
|
|
236
|
-
| Minimum delay | `20` |
|
|
237
|
-
| Minimum delay retries | `2` |
|
|
238
|
-
| Maximum delay | `300` |
|
|
239
|
-
| Maximum delay retries | `6` |
|
|
240
|
-
| Retry-backoff function | Exponential |
|
|
241
|
-
|
|
242
|
-
SNS then keeps trying for about 40 minutes. It allows an hour at most.
|
|
243
|
-
|
|
244
|
-
1. **(Optional)** Keep what SNS still can't deliver. On the subscription, choose **Edit**, and set a **Redrive policy (dead-letter queue)** to an SQS queue of your own. SNS then moves an event there instead of discarding it. [Amazon SNS dead-letter queues](https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html) covers the queue and its permissions.
|
|
245
|
-
|
|
246
|
-
## 9. Receive replies at your From address
|
|
247
|
-
|
|
248
|
-
Replies to a post go to your From address, `newsletter@send.example.com`, which has no inbox yet, so they bounce. This section forwards that address to the publisher's inbox with Cloudflare Email Routing. Forwarding only receives mail, so it doesn't change how SES sends.
|
|
249
|
-
|
|
250
|
-
1. Check that your From address has no inbox yet. This prints nothing:
|
|
251
|
-
|
|
252
|
-
```bash
|
|
253
|
-
dig +short MX send.example.com
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
If it lists mail servers, `send.example.com` already receives mail elsewhere, and Email Routing would replace those servers. Check that your mail host has a mailbox for `newsletter@send.example.com`, and skip to [Check it](#check-it).
|
|
257
|
-
|
|
258
|
-
1. In the [Cloudflare dashboard](https://dash.cloudflare.com/), go to **Compute → Email Service → Email Routing**.
|
|
259
|
-
|
|
260
|
-
1. Add `send.example.com` to Email Routing: select `example.com`, then **Settings**, and add `send` under **Subdomains**.
|
|
261
|
-
|
|
262
|
-
1. Cloudflare adds MX, SPF, and DKIM records for `send.example.com`, and locks them. Wait until they show as added.
|
|
263
|
-
|
|
264
|
-
1. Under **Destination Addresses**, add the publisher's inbox. Open the email Cloudflare sends to it, and select **Verify email address**. If it isn't your inbox, ask the publisher to do this step.
|
|
265
|
-
|
|
266
|
-
1. Under **Routing Rules**, select **Create routing rule**. For **Email pattern**, enter `newsletter`, the part of your From address before the `@`, and select `send.example.com`. Set **Action** to **Send to an email**, select the publisher's inbox as the **Destination**, and save.
|
|
267
|
-
|
|
268
|
-
1. **(Optional)** Give your DMARC reports an inbox too. If the address in your DMARC record doesn't receive mail, add a rule that forwards `dmarc` the same way. Then change the record's `rua` to `mailto:dmarc@send.example.com`.
|
|
269
|
-
|
|
270
|
-
Out-of-office and other automatic replies reach the publisher's inbox too. Bounces don't: they go to SES, which reports them to the app. The publisher answers from their own inbox, not from `newsletter@send.example.com`. To answer from the newsletter's address instead, give it a mailbox at a mail host such as [Fastmail](https://www.fastmail.help/hc/en-us/articles/360060591133) or [Google Workspace](https://support.google.com/a/answer/140034), in place of forwarding.
|
|
271
|
-
|
|
272
|
-
## Check it
|
|
273
|
-
|
|
274
|
-
1. The app answers on your hostname:
|
|
275
|
-
|
|
276
|
-
```bash
|
|
277
|
-
curl https://newsletter.example.com/health
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
```
|
|
281
|
-
{"status":"ok","service":"kestrel"}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
1. The webhook is public, and refuses a request that isn't from SNS:
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
curl -s -o /dev/null -w "%{http_code}\n" -X POST https://newsletter.example.com/webhooks/ses
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
```
|
|
291
|
-
400
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
Any other answer, such as a redirect to your Cloudflare login, means Access covers the webhook. Remove that path from your Access application.
|
|
295
|
-
|
|
296
|
-
1. The SNS subscription shows **Confirmed**.
|
|
297
|
-
|
|
298
|
-
1. Your From address receives mail. This lists Cloudflare's three `route` mail servers, or your own mail host's if you skipped section 9's forwarding:
|
|
299
|
-
|
|
300
|
-
```bash
|
|
301
|
-
dig +short MX send.example.com
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
1. In the editor, **Settings → Email sender** shows Amazon SES and your From address, where it said **No email provider connected** before.
|
|
305
|
-
|
|
306
|
-
1. In a browser, `https://newsletter.example.com/subscribe` shows the subscribe form, where it said signups aren't open yet.
|
|
307
|
-
|
|
308
|
-
The test emails in the next step prove the rest, including a reply. In the sandbox, they go only to the addresses you verified in section 4, and to the SES test addresses that page lists. SES charges for each email it sends, test emails included, as [Amazon SES pricing](https://aws.amazon.com/ses/pricing/) lists.
|
|
309
|
-
|
|
310
|
-
Next, [verify it works](05-verify.md).
|