@kurtbruns/kestrel 1.7.0 → 1.9.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 +13 -8
- package/CHANGELOG.md +72 -2
- package/README.md +2 -2
- package/cli/dev-api.mjs +7 -1
- package/cli/dev.mjs +46 -1
- package/cli/init.mjs +6 -1
- package/dist/public/dashboard/app.js +218 -223
- package/dist/public/dashboard/app.js.map +4 -4
- package/dist/public/dashboard/index.html +6 -6
- package/dist/public/dashboard/styles.css +173 -180
- package/dist/worker/index.js +4793 -3097
- package/docs/README.md +2 -2
- package/docs/get-started/02-deploy.md +23 -8
- package/docs/get-started/03-access.md +2 -2
- package/docs/{guides/02-ses.md → get-started/04-ses.md} +75 -52
- package/docs/get-started/05-verify.md +8 -10
- package/docs/get-started/06-go-live.md +22 -6
- package/docs/guides/07-upgrade.md +2 -0
- package/docs/reference/01-configuration.md +22 -16
- package/docs/reference/02-sending-domain-dns.md +19 -19
- package/docs/reference/03-import-format.md +103 -0
- package/migrations/0004_keyed_pending_to_resolve.sql +27 -0
- package/migrations/0005_imports.sql +74 -0
- package/migrations/0006_deliveries_fewer_indexes.sql +19 -0
- package/package.json +1 -1
- package/template/claude/CLAUDE.md +3 -1
- package/template/package.json +1 -0
- package/template/wrangler.jsonc +6 -3
- package/docs/get-started/04-resend.md +0 -136
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
# Connect an email provider
|
|
2
|
-
|
|
3
|
-
Kestrel sends your posts through an email provider. The provider only delivers the mail: Kestrel keeps your list, each subscriber's consent, and the record of every send. This page connects Resend. To use Amazon SES instead, follow [Use Amazon SES instead of Resend](../guides/02-ses.md) in place of this page.
|
|
4
|
-
|
|
5
|
-
In this guide, you verify your sending hostname with Resend and add a DMARC record. Then you give the app an API key and a webhook for bounces and complaints, switch it to Resend, and deploy.
|
|
6
|
-
|
|
7
|
-
## 1. Verify your sending hostname
|
|
8
|
-
|
|
9
|
-
Resend sends only from a domain whose DNS proves you own it. These records also let inboxes trust your mail.
|
|
10
|
-
|
|
11
|
-
1. In Resend, go to [Domains](https://resend.com/domains), select **Add Domain**, and enter `send.example.com`.
|
|
12
|
-
|
|
13
|
-
1. Select **Sign in to Cloudflare**, and allow Resend to edit your DNS. Resend adds its records to your zone for you.
|
|
14
|
-
|
|
15
|
-
To add them by hand instead, copy each record from Resend into your zone's DNS records in Cloudflare. Because your sending hostname is itself a subdomain, some names look doubled, such as `send.send`. That's expected.
|
|
16
|
-
|
|
17
|
-
1. Leave receiving turned off. Kestrel doesn't receive mail.
|
|
18
|
-
|
|
19
|
-
1. Wait until Resend shows the domain as **Verified**.
|
|
20
|
-
|
|
21
|
-
## 2. Add a DMARC record
|
|
22
|
-
|
|
23
|
-
DMARC tells inboxes what to do with mail that fails its checks, and sends you reports about it. Resend doesn't add this record, so you add it yourself. It starts in monitor mode, which reports without blocking anything.
|
|
24
|
-
|
|
25
|
-
1. In the Cloudflare dashboard, open your domain's DNS records, and add a record:
|
|
26
|
-
|
|
27
|
-
- **Type:** `TXT`
|
|
28
|
-
- **Name:** `_dmarc.send`
|
|
29
|
-
- **Content:** `v=DMARC1; p=none; rua=mailto:dmarc@example.com`
|
|
30
|
-
|
|
31
|
-
1. Replace `dmarc@example.com` with an address that receives mail. Reports arrive there as attachments.
|
|
32
|
-
|
|
33
|
-
[Sending-domain DNS](../reference/02-sending-domain-dns.md#dmarc-publish-a-policy-and-collect-reports) explains each record, and when to tighten DMARC.
|
|
34
|
-
|
|
35
|
-
## 3. Create an API key
|
|
36
|
-
|
|
37
|
-
The app sends through this key. A key that can only send, from only your sending hostname, limits the harm if it ever leaks.
|
|
38
|
-
|
|
39
|
-
1. In Resend, go to [API Keys](https://resend.com/api-keys), and select **Create API Key**.
|
|
40
|
-
|
|
41
|
-
1. Fill in the key:
|
|
42
|
-
|
|
43
|
-
- **Name:** `kestrel-production`
|
|
44
|
-
- **Permission:** Sending access
|
|
45
|
-
- **Domain:** `send.example.com`
|
|
46
|
-
|
|
47
|
-
1. Copy the key. Resend shows it only once.
|
|
48
|
-
|
|
49
|
-
1. Store it as a secret, and paste the key at the prompt:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
npx wrangler secret put RESEND_API_KEY --env production
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## 4. Add the webhook
|
|
56
|
-
|
|
57
|
-
The webhook tells the app when an address bounces or complains, and the app stops mailing it. Without it, you keep mailing those addresses, and your mail starts landing in spam.
|
|
58
|
-
|
|
59
|
-
1. In Resend, go to [Webhooks](https://resend.com/webhooks), and select **Add Webhook**.
|
|
60
|
-
|
|
61
|
-
1. Enter the endpoint URL:
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
https://newsletter.example.com/webhooks/resend
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
1. Select these three events, and create the webhook:
|
|
68
|
-
|
|
69
|
-
- `email.delivered`
|
|
70
|
-
- `email.bounced`
|
|
71
|
-
- `email.complained`
|
|
72
|
-
|
|
73
|
-
1. On the webhook's page, copy its signing secret. It starts with `whsec_`.
|
|
74
|
-
|
|
75
|
-
1. Store it as a secret. The app checks every event against it:
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
npx wrangler secret put RESEND_WEBHOOK_SECRET --env production
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## 5. Set the provider and deploy
|
|
82
|
-
|
|
83
|
-
Until now the app has run with no email provider connected, refusing to send. Setting `PROVIDER` connects Resend. Store both secrets before you set it. With `PROVIDER` set to `resend` and a secret missing, every request answers `500` and names the missing secret.
|
|
84
|
-
|
|
85
|
-
1. In `wrangler.jsonc`, in the `production` block's `vars`, add `PROVIDER` set to `resend`:
|
|
86
|
-
|
|
87
|
-
```jsonc
|
|
88
|
-
"PROVIDER": "resend",
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
1. Commit the change, and push it:
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
git commit -am "Send through Resend"
|
|
95
|
-
git push
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
1. Deploy:
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
npx wrangler deploy --env production
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Check it
|
|
105
|
-
|
|
106
|
-
1. The app answers on your hostname:
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
curl https://newsletter.example.com/health
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
```
|
|
113
|
-
{"status":"ok","service":"kestrel"}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
1. The webhook is public, and refuses a request without Resend's signature:
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
curl -s -o /dev/null -w "%{http_code}\n" -X POST https://newsletter.example.com/webhooks/resend
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
400
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Any other answer, such as a redirect to your Cloudflare login, means Access covers the webhook. Remove that path from your Access application.
|
|
127
|
-
|
|
128
|
-
1. In the editor, **Settings → Email sender** shows Resend as the email provider, and your From address, where it said **No email provider connected** before.
|
|
129
|
-
|
|
130
|
-
1. In a browser, `https://newsletter.example.com/subscribe` shows the subscribe form, where it said signups aren't open yet.
|
|
131
|
-
|
|
132
|
-
The test sends in the next step prove the rest.
|
|
133
|
-
|
|
134
|
-
Resend's free plan sends up to 100 emails a day and 3,000 a month, test emails included. A list of more than about a hundred subscribers needs a paid plan, listed on [Resend's pricing](https://resend.com/pricing) page. For a large list, [Amazon SES](../guides/02-ses.md) may cost less.
|
|
135
|
-
|
|
136
|
-
Next, [verify it works](05-verify.md).
|