sently 0.8.0 → 0.9.1
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/AGENTS.md +33 -0
- package/CHANGELOG.md +82 -41
- package/README.md +89 -960
- package/dist/adapters/bun.js +1 -1
- package/dist/adapters/cf.js +2 -2
- package/dist/adapters/cf.js.map +2 -2
- package/dist/adapters/deno.js +1 -1
- package/dist/adapters/node.js +1 -1
- package/dist/auth/oauth2.js +2 -2
- package/dist/auth/oauth2.js.map +1 -1
- package/dist/chunk-0gqy32pe.js +4 -0
- package/dist/{chunk-n5dan5bz.js.map → chunk-0gqy32pe.js.map} +2 -2
- package/dist/{chunk-z62q7kqr.js → chunk-0qxws3kj.js} +2 -2
- package/dist/{chunk-z62q7kqr.js.map → chunk-0qxws3kj.js.map} +1 -1
- package/dist/chunk-29z7fkzy.js +4 -0
- package/dist/{chunk-wsymfbkn.js.map → chunk-29z7fkzy.js.map} +2 -2
- package/dist/chunk-5915vbcj.js +4 -0
- package/dist/chunk-5915vbcj.js.map +10 -0
- package/dist/{chunk-nbmq8ejv.js → chunk-6npp3x3c.js} +2 -2
- package/dist/{chunk-nbmq8ejv.js.map → chunk-6npp3x3c.js.map} +1 -1
- package/dist/chunk-7gy2q9sh.js +4 -0
- package/dist/chunk-7gy2q9sh.js.map +10 -0
- package/dist/{chunk-zst8an2p.js → chunk-8dty8c4p.js} +2 -2
- package/dist/{chunk-zst8an2p.js.map → chunk-8dty8c4p.js.map} +2 -2
- package/dist/{chunk-f3dz43cy.js → chunk-8njyga62.js} +2 -2
- package/dist/{chunk-f3dz43cy.js.map → chunk-8njyga62.js.map} +1 -1
- package/dist/chunk-93vqxxj2.js +4 -0
- package/dist/{chunk-qh90yr6d.js.map → chunk-93vqxxj2.js.map} +2 -2
- package/dist/chunk-b602dhck.js +4 -0
- package/dist/{chunk-wbvhaqcp.js.map → chunk-b602dhck.js.map} +2 -2
- package/dist/{chunk-9zkv5azm.js → chunk-gp4fwrs8.js} +2 -2
- package/dist/{chunk-9zkv5azm.js.map → chunk-gp4fwrs8.js.map} +1 -1
- package/dist/chunk-n0qeyzqm.js +13 -0
- package/dist/{chunk-8phpsns1.js.map → chunk-n0qeyzqm.js.map} +2 -2
- package/dist/chunk-qtkd5bak.js +4 -0
- package/dist/chunk-qtkd5bak.js.map +11 -0
- package/dist/chunk-skqhj0rm.js +4 -0
- package/dist/{chunk-vhxzhx8b.js.map → chunk-skqhj0rm.js.map} +2 -2
- package/dist/{chunk-6bkj4y4r.js → chunk-tamww15j.js} +2 -2
- package/dist/{chunk-6bkj4y4r.js.map → chunk-tamww15j.js.map} +1 -1
- package/dist/chunk-vjpds2pf.js +3 -0
- package/dist/{chunk-m07smapm.js.map → chunk-vjpds2pf.js.map} +2 -2
- package/dist/chunk-yp311efr.js +4 -0
- package/dist/chunk-yp311efr.js.map +10 -0
- package/dist/chunk-ywq6s10g.js +5 -0
- package/dist/{chunk-5scdgffb.js.map → chunk-ywq6s10g.js.map} +3 -3
- package/dist/core/base64.d.ts +10 -0
- package/dist/core/errors.js +2 -2
- package/dist/core/errors.js.map +1 -1
- package/dist/core/hooks.d.ts +14 -0
- package/dist/core/plugin.d.ts +7 -7
- package/dist/core/push-endpoint.d.ts +29 -0
- package/dist/core/push-types.d.ts +98 -0
- package/dist/core/sms-types.d.ts +76 -0
- package/dist/core/smtp.js +2 -2
- package/dist/core/smtp.js.map +1 -1
- package/dist/core/whatsapp-types.d.ts +116 -0
- package/dist/detect.js +2 -2
- package/dist/detect.js.map +1 -1
- package/dist/dkim.js +2 -2
- package/dist/dkim.js.map +2 -2
- package/dist/idempotency.js +2 -2
- package/dist/idempotency.js.map +1 -1
- package/dist/index.d.ts +5 -32
- package/dist/index.js +0 -35
- package/dist/mailer.js +2 -2
- package/dist/mailer.js.map +1 -1
- package/dist/observability/console.js +1 -1
- package/dist/plugins/react.js +2 -2
- package/dist/plugins/react.js.map +2 -2
- package/dist/plugins/template.js +1 -1
- package/dist/pool/pool.js +2 -2
- package/dist/pool/pool.js.map +1 -1
- package/dist/push.d.ts +26 -0
- package/dist/push.js +3 -0
- package/dist/push.js.map +10 -0
- package/dist/sms.d.ts +26 -0
- package/dist/sms.js +3 -0
- package/dist/sms.js.map +10 -0
- package/dist/smtp-mailer.js +2 -2
- package/dist/smtp-mailer.js.map +2 -2
- package/dist/transports/brevo.js +2 -2
- package/dist/transports/brevo.js.map +2 -2
- package/dist/transports/cloudflare-email.js +2 -2
- package/dist/transports/cloudflare-email.js.map +2 -2
- package/dist/transports/fallback.js +2 -2
- package/dist/transports/fallback.js.map +1 -1
- package/dist/transports/loops.js +2 -2
- package/dist/transports/loops.js.map +2 -2
- package/dist/transports/mailersend.js +2 -2
- package/dist/transports/mailersend.js.map +2 -2
- package/dist/transports/mailgun.js +2 -2
- package/dist/transports/mailgun.js.map +2 -2
- package/dist/transports/mailtrap.js +2 -2
- package/dist/transports/mailtrap.js.map +2 -2
- package/dist/transports/msegat.d.ts +132 -0
- package/dist/transports/msegat.js +3 -0
- package/dist/transports/msegat.js.map +10 -0
- package/dist/transports/plunk.js +2 -2
- package/dist/transports/plunk.js.map +2 -2
- package/dist/transports/postmark.js +2 -2
- package/dist/transports/postmark.js.map +2 -2
- package/dist/transports/preview.js +2 -2
- package/dist/transports/preview.js.map +2 -2
- package/dist/transports/resend.js +2 -2
- package/dist/transports/resend.js.map +2 -2
- package/dist/transports/retry.js +2 -2
- package/dist/transports/retry.js.map +2 -2
- package/dist/transports/sendgrid.js +2 -2
- package/dist/transports/sendgrid.js.map +2 -2
- package/dist/transports/ses.js +2 -2
- package/dist/transports/ses.js.map +2 -2
- package/dist/transports/smtp.js +2 -2
- package/dist/transports/smtp.js.map +1 -1
- package/dist/transports/sndr.d.ts +41 -0
- package/dist/transports/sndr.js +3 -0
- package/dist/transports/sndr.js.map +10 -0
- package/dist/transports/sparkpost.js +2 -2
- package/dist/transports/sparkpost.js.map +2 -2
- package/dist/transports/taqnyat-mail.d.ts +33 -0
- package/dist/transports/taqnyat-mail.js +3 -0
- package/dist/transports/taqnyat-mail.js.map +10 -0
- package/dist/transports/taqnyat-phone.d.ts +4 -0
- package/dist/transports/taqnyat-sms.d.ts +131 -0
- package/dist/transports/taqnyat-sms.js +3 -0
- package/dist/transports/taqnyat-sms.js.map +10 -0
- package/dist/transports/taqnyat-whatsapp.d.ts +51 -0
- package/dist/transports/taqnyat-whatsapp.js +3 -0
- package/dist/transports/taqnyat-whatsapp.js.map +10 -0
- package/dist/transports/twilio-sms.d.ts +66 -0
- package/dist/transports/twilio-sms.js +3 -0
- package/dist/transports/twilio-sms.js.map +10 -0
- package/dist/transports/webpush.d.ts +46 -0
- package/dist/transports/webpush.js +3 -0
- package/dist/transports/webpush.js.map +10 -0
- package/dist/transports/weighted-fallback.js +2 -2
- package/dist/transports/weighted-fallback.js.map +1 -1
- package/dist/transports/whatsapp-cloud.d.ts +56 -0
- package/dist/transports/whatsapp-cloud.js +3 -0
- package/dist/transports/whatsapp-cloud.js.map +10 -0
- package/dist/webhooks/brevo.js +1 -1
- package/dist/webhooks/mailgun.js +1 -1
- package/dist/webhooks/postmark.js +1 -1
- package/dist/webhooks/resend.js +1 -1
- package/dist/webhooks/sendgrid.js +1 -1
- package/dist/webhooks/ses.js +1 -1
- package/dist/webhooks/sndr.d.ts +16 -0
- package/dist/webhooks/sndr.js +3 -0
- package/dist/webhooks/sndr.js.map +10 -0
- package/dist/webhooks/timing-safe-equal.js +1 -1
- package/dist/webhooks.d.ts +9 -2
- package/dist/webhooks.js +4 -0
- package/dist/whatsapp.d.ts +26 -0
- package/dist/whatsapp.js +3 -0
- package/dist/whatsapp.js.map +10 -0
- package/package.json +85 -4
- package/site/README.md +26 -0
- package/site/content/docs/ai/index.mdx +13 -0
- package/site/content/docs/ai/llms-txt.mdx +12 -0
- package/site/content/docs/ai/mcp.mdx +16 -0
- package/site/content/docs/ai/meta.json +9 -0
- package/site/content/docs/channels/email.mdx +100 -0
- package/site/content/docs/channels/hooks.mdx +87 -0
- package/site/content/docs/channels/index.mdx +81 -0
- package/site/content/docs/channels/meta.json +12 -0
- package/site/content/docs/channels/push.mdx +92 -0
- package/site/content/docs/channels/sms.mdx +88 -0
- package/site/content/docs/channels/whatsapp.mdx +95 -0
- package/site/content/docs/decorators/fallback.mdx +34 -0
- package/site/content/docs/decorators/idempotency.mdx +34 -0
- package/site/content/docs/decorators/index.mdx +50 -0
- package/site/content/docs/decorators/meta.json +12 -0
- package/site/content/docs/decorators/preview.mdx +34 -0
- package/site/content/docs/decorators/retry.mdx +34 -0
- package/site/content/docs/decorators/weighted-fallback.mdx +34 -0
- package/site/content/docs/get-started/entrypoints.mdx +114 -0
- package/site/content/docs/get-started/index.mdx +14 -0
- package/site/content/docs/get-started/installation.mdx +78 -0
- package/site/content/docs/get-started/introduction.mdx +77 -0
- package/site/content/docs/get-started/meta.json +12 -0
- package/site/content/docs/get-started/migrate-nodemailer.mdx +23 -0
- package/site/content/docs/get-started/runtimes.mdx +17 -0
- package/site/content/docs/guides/adapters.mdx +26 -0
- package/site/content/docs/guides/attachments.mdx +19 -0
- package/site/content/docs/guides/bundle-size.mdx +78 -0
- package/site/content/docs/guides/dkim.mdx +26 -0
- package/site/content/docs/guides/index.mdx +15 -0
- package/site/content/docs/guides/meta.json +21 -0
- package/site/content/docs/guides/oauth2.mdx +23 -0
- package/site/content/docs/guides/observability.mdx +16 -0
- package/site/content/docs/guides/plugins-template.mdx +22 -0
- package/site/content/docs/guides/pool.mdx +24 -0
- package/site/content/docs/guides/react-email.mdx +20 -0
- package/site/content/docs/guides/security.mdx +17 -0
- package/site/content/docs/guides/send-bulk.mdx +18 -0
- package/site/content/docs/guides/vendor-extras-otp.mdx +18 -0
- package/site/content/docs/guides/webhooks.mdx +120 -0
- package/site/content/docs/guides/webpush-interop.mdx +18 -0
- package/site/content/docs/index.mdx +15 -0
- package/site/content/docs/meta.json +15 -0
- package/site/content/docs/quick-start/email.mdx +40 -0
- package/site/content/docs/quick-start/index.mdx +15 -0
- package/site/content/docs/quick-start/meta.json +5 -0
- package/site/content/docs/quick-start/push.mdx +36 -0
- package/site/content/docs/quick-start/sms.mdx +36 -0
- package/site/content/docs/quick-start/whatsapp.mdx +38 -0
- package/site/content/docs/reference/errors.mdx +22 -0
- package/site/content/docs/reference/exports.mdx +83 -0
- package/site/content/docs/reference/index.mdx +15 -0
- package/site/content/docs/reference/mail-options.mdx +22 -0
- package/site/content/docs/reference/meta.json +15 -0
- package/site/content/docs/reference/push-options.mdx +20 -0
- package/site/content/docs/reference/sms-options.mdx +17 -0
- package/site/content/docs/reference/transport-contracts.mdx +17 -0
- package/site/content/docs/reference/webhook-events.mdx +70 -0
- package/site/content/docs/reference/whatsapp-options.mdx +15 -0
- package/site/content/docs/transports/brevo.mdx +40 -0
- package/site/content/docs/transports/cloudflare-email.mdx +40 -0
- package/site/content/docs/transports/index.mdx +105 -0
- package/site/content/docs/transports/loops.mdx +41 -0
- package/site/content/docs/transports/mailersend.mdx +40 -0
- package/site/content/docs/transports/mailgun.mdx +42 -0
- package/site/content/docs/transports/mailtrap.mdx +42 -0
- package/site/content/docs/transports/meta.json +32 -0
- package/site/content/docs/transports/msegat.mdx +42 -0
- package/site/content/docs/transports/plunk.mdx +40 -0
- package/site/content/docs/transports/postmark.mdx +40 -0
- package/site/content/docs/transports/resend.mdx +43 -0
- package/site/content/docs/transports/sendgrid.mdx +40 -0
- package/site/content/docs/transports/ses.mdx +44 -0
- package/site/content/docs/transports/smtp.mdx +47 -0
- package/site/content/docs/transports/sndr.mdx +144 -0
- package/site/content/docs/transports/sparkpost.mdx +41 -0
- package/site/content/docs/transports/taqnyat-mail.mdx +41 -0
- package/site/content/docs/transports/taqnyat-sms.mdx +41 -0
- package/site/content/docs/transports/taqnyat-whatsapp.mdx +40 -0
- package/site/content/docs/transports/twilio-sms.mdx +128 -0
- package/site/content/docs/transports/webpush.mdx +43 -0
- package/site/content/docs/transports/whatsapp-cloud.mdx +42 -0
- package/dist/chunk-5scdgffb.js +0 -5
- package/dist/chunk-8phpsns1.js +0 -13
- package/dist/chunk-m07smapm.js +0 -3
- package/dist/chunk-n5dan5bz.js +0 -4
- package/dist/chunk-qh90yr6d.js +0 -4
- package/dist/chunk-vhxzhx8b.js +0 -4
- package/dist/chunk-wbvhaqcp.js +0 -4
- package/dist/chunk-wsymfbkn.js +0 -4
- package/dist/chunk-yr56b0ts.js +0 -4
- package/dist/chunk-yr56b0ts.js.map +0 -11
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Entrypoints
|
|
3
|
+
description: Use focused subpaths to import only the channel or integration you need.
|
|
4
|
+
icon: Route
|
|
5
|
+
source: "package.json"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
sently exports focused subpaths so a channel can import its sender and a single provider transport.
|
|
9
|
+
The main `sently` package exports shared email factories and a few helpers — not every HTTP provider.
|
|
10
|
+
|
|
11
|
+
<Callout title="The one rule">
|
|
12
|
+
Import a sender from its channel entrypoint and its provider from a `sently/transports/*`
|
|
13
|
+
entrypoint.
|
|
14
|
+
</Callout>
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
<Steps>
|
|
19
|
+
|
|
20
|
+
<Step>
|
|
21
|
+
### Pick an email entrypoint
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createMailer } from "sently/mailer";
|
|
25
|
+
import { SndrTransport } from "sently/transports/sndr";
|
|
26
|
+
|
|
27
|
+
const mailer = await createMailer({
|
|
28
|
+
transport: new SndrTransport({
|
|
29
|
+
apiKey: process.env.SNDR_API_KEY!,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
</Step>
|
|
35
|
+
|
|
36
|
+
<Step>
|
|
37
|
+
### Use SMTP only when you have relay configuration
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { createSMTPMailer } from "sently/smtp";
|
|
41
|
+
|
|
42
|
+
const mailer = await createSMTPMailer({
|
|
43
|
+
host: "smtp.example.com",
|
|
44
|
+
port: 587,
|
|
45
|
+
auth: { user: "you@example.com", pass: process.env.SMTP_PASS! },
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
</Step>
|
|
50
|
+
|
|
51
|
+
</Steps>
|
|
52
|
+
|
|
53
|
+
## Channel entrypoints
|
|
54
|
+
|
|
55
|
+
| Import | Exports | Use |
|
|
56
|
+
| ------ | ------- | --- |
|
|
57
|
+
| `sently` | Shared factories, types, OAuth2, errors, Fallback / WeightedFallback / Cloudflare Email | General email entrypoint. |
|
|
58
|
+
| `sently/mailer` | `createMailer` | Email with an explicit transport (smallest HTTP path). |
|
|
59
|
+
| `sently/smtp` | `createSMTPMailer` | SMTP relay configuration. |
|
|
60
|
+
| `sently/sms` | `createSmsSender` | SMS sender. |
|
|
61
|
+
| `sently/whatsapp` | `createWhatsAppSender` | WhatsApp sender. |
|
|
62
|
+
| `sently/push` | `createPushSender` | Web Push sender. |
|
|
63
|
+
|
|
64
|
+
## Supporting entrypoints
|
|
65
|
+
|
|
66
|
+
| Import | Use |
|
|
67
|
+
| ------ | --- |
|
|
68
|
+
| `sently/transports/*` | One provider or email decorator transport. |
|
|
69
|
+
| `sently/webhooks/<provider>` | One webhook parser (smallest graph). |
|
|
70
|
+
| `sently/webhooks` | Convenience barrel of all webhook helpers. |
|
|
71
|
+
| `sently/errors` | Stable sently error classes and codes. |
|
|
72
|
+
| `sently/plugins/template` | Template plugin and simple engine. |
|
|
73
|
+
| `sently/auth/oauth2` | SMTP OAuth2 client. |
|
|
74
|
+
| `sently/pool` | SMTP connection pool. |
|
|
75
|
+
| `sently/dkim` | DKIM signing entrypoint. |
|
|
76
|
+
| `sently/idempotency` | Idempotency transport and memory store. |
|
|
77
|
+
|
|
78
|
+
## Troubleshooting
|
|
79
|
+
|
|
80
|
+
<Accordions>
|
|
81
|
+
|
|
82
|
+
<Accordion title="Can I pass SMTP host and port to createMailer?">
|
|
83
|
+
|
|
84
|
+
No. `createMailer` requires a transport. Import `createSMTPMailer` from `sently/smtp` for relay configuration.
|
|
85
|
+
|
|
86
|
+
</Accordion>
|
|
87
|
+
|
|
88
|
+
<Accordion title="Where do provider transports come from?">
|
|
89
|
+
|
|
90
|
+
Import the concrete transport from its exported `sently/transports/*` subpath, such as `sently/transports/sndr` or `sently/transports/resend`.
|
|
91
|
+
|
|
92
|
+
</Accordion>
|
|
93
|
+
|
|
94
|
+
<Accordion title="Why is Plunk or SNDR missing from import sently?">
|
|
95
|
+
|
|
96
|
+
HTTP providers were removed from the main barrel so bare Node/Deno imports do not load every client. Use the transport subpath.
|
|
97
|
+
|
|
98
|
+
</Accordion>
|
|
99
|
+
|
|
100
|
+
</Accordions>
|
|
101
|
+
|
|
102
|
+
## Learn more
|
|
103
|
+
|
|
104
|
+
- [Export reference](/docs/reference/exports) — full entrypoint map
|
|
105
|
+
- [All transports](/docs/transports) — providers by channel
|
|
106
|
+
- [Bundle size](/docs/guides/bundle-size) — keep stacks small
|
|
107
|
+
|
|
108
|
+
## Next
|
|
109
|
+
|
|
110
|
+
<Cards>
|
|
111
|
+
<Card title="Exports reference" description="Public package entrypoints." href="/docs/reference/exports" />
|
|
112
|
+
<Card title="Email channel" description="createMailer and MailOptions." href="/docs/channels/email" />
|
|
113
|
+
<Card title="SNDR" description="HTTP email via SNDR." href="/docs/transports/sndr" />
|
|
114
|
+
</Cards>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Get started
|
|
3
|
+
description: Install sently and send your first message.
|
|
4
|
+
icon: FolderOpen
|
|
5
|
+
source: "README.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Install sently and send your first message.
|
|
9
|
+
|
|
10
|
+
<Cards>
|
|
11
|
+
<Card title="Introduction" href="/docs/get-started/introduction" />
|
|
12
|
+
<Card title="Installation" href="/docs/get-started/installation" />
|
|
13
|
+
<Card title="Quick start" href="/docs/quick-start" />
|
|
14
|
+
</Cards>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
description: Install sently with Bun or use its published ESM package.
|
|
4
|
+
icon: Package
|
|
5
|
+
source: "package.json"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
sently is an ESM package for applications that send email, SMS, WhatsApp, or browser push.
|
|
9
|
+
Install it in the application that owns your delivery credentials and provider transport configuration.
|
|
10
|
+
|
|
11
|
+
<Callout title="The one rule">Import the narrowest sently entrypoint that contains the sender or transport you use.</Callout>
|
|
12
|
+
|
|
13
|
+
<Steps>
|
|
14
|
+
<Step title="Add the package">
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun add sently
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
</Step>
|
|
21
|
+
<Step title="Import a focused entrypoint">
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createMailer } from "sently/mailer";
|
|
25
|
+
import { ResendTransport } from "sently/transports/resend";
|
|
26
|
+
|
|
27
|
+
const mailer = await createMailer({
|
|
28
|
+
transport: new ResendTransport({
|
|
29
|
+
apiKey: process.env.RESEND_API_KEY!,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
</Step>
|
|
35
|
+
</Steps>
|
|
36
|
+
|
|
37
|
+
## Install and runtime requirements
|
|
38
|
+
|
|
39
|
+
| Requirement | Details |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| Package manager | Bun: `bun add sently`. |
|
|
42
|
+
| Module format | Use ESM imports. |
|
|
43
|
+
| Node.js | Version 18 or later. |
|
|
44
|
+
| Bun | Version 1 or later. |
|
|
45
|
+
| Email via SMTP | Use an SMTP-capable runtime adapter; HTTP transports are the portable option. |
|
|
46
|
+
|
|
47
|
+
## Common imports
|
|
48
|
+
|
|
49
|
+
| Need | Import |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| Email with a transport | `sently/mailer` |
|
|
52
|
+
| Email over SMTP | `sently/smtp` |
|
|
53
|
+
| SMS | `sently/sms` |
|
|
54
|
+
| WhatsApp | `sently/whatsapp` |
|
|
55
|
+
| Web Push | `sently/push` |
|
|
56
|
+
|
|
57
|
+
## Troubleshooting
|
|
58
|
+
|
|
59
|
+
<Accordions>
|
|
60
|
+
<Accordion title="Why cannot my runtime resolve sently?">
|
|
61
|
+
Use ESM package imports such as `sently/mailer`, rather than a file path into the package.
|
|
62
|
+
</Accordion>
|
|
63
|
+
<Accordion title="Should I import every transport from the main package?">
|
|
64
|
+
No. Provider transports are exported from their own `sently/transports/*` subpaths.
|
|
65
|
+
</Accordion>
|
|
66
|
+
</Accordions>
|
|
67
|
+
|
|
68
|
+
## Learn more
|
|
69
|
+
|
|
70
|
+
- [Entrypoints](./entrypoints)
|
|
71
|
+
- [Transports](../transports)
|
|
72
|
+
|
|
73
|
+
## Next
|
|
74
|
+
|
|
75
|
+
<Cards>
|
|
76
|
+
<Card title="Entrypoints" href="/docs/get-started/entrypoints" />
|
|
77
|
+
<Card title="Choose a channel" href="/docs/channels" />
|
|
78
|
+
</Cards>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Introduction
|
|
3
|
+
description: Choose a sender for the channel and a transport for the provider.
|
|
4
|
+
icon: Compass
|
|
5
|
+
source: "README.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
sently sends email, SMS, WhatsApp, and browser push without making provider SDK calls your application API.
|
|
9
|
+
Choose the channel sender first, then attach the provider transport that performs delivery.
|
|
10
|
+
|
|
11
|
+
<Callout title="The one rule">Use `createMailer`, `createSmsSender`, `createWhatsAppSender`, or `createPushSender` in app code; swap transports when provider configuration changes.</Callout>
|
|
12
|
+
|
|
13
|
+
<Steps>
|
|
14
|
+
<Step title="Install the package">
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun add sently
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
</Step>
|
|
21
|
+
<Step title="Send with a channel sender">
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createMailer } from "sently/mailer";
|
|
25
|
+
import { ResendTransport } from "sently/transports/resend";
|
|
26
|
+
|
|
27
|
+
const mailer = await createMailer({
|
|
28
|
+
transport: new ResendTransport({
|
|
29
|
+
apiKey: process.env.RESEND_API_KEY!,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await mailer.send({
|
|
34
|
+
from: "hello@example.com",
|
|
35
|
+
to: "person@example.com",
|
|
36
|
+
subject: "Welcome",
|
|
37
|
+
text: "Thanks for joining.",
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
</Step>
|
|
42
|
+
</Steps>
|
|
43
|
+
|
|
44
|
+
## Choose a channel
|
|
45
|
+
|
|
46
|
+
| Channel | Factory | Delivery contract |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| Email | `createMailer` / `createSMTPMailer` | `Transport` |
|
|
49
|
+
| SMS | `createSmsSender` | `SmsTransport` |
|
|
50
|
+
| WhatsApp | `createWhatsAppSender` | `WhatsAppTransport` |
|
|
51
|
+
| Push | `createPushSender` | `PushTransport` |
|
|
52
|
+
|
|
53
|
+
Email factories are asynchronous. The other channel factories return their sender synchronously; all send operations are asynchronous.
|
|
54
|
+
|
|
55
|
+
## Troubleshooting
|
|
56
|
+
|
|
57
|
+
<Accordions>
|
|
58
|
+
<Accordion title="Which factory should I use for SMTP?">
|
|
59
|
+
Use `createSMTPMailer` with SMTP host, port, and authentication. Use `createMailer` when you already have a transport.
|
|
60
|
+
</Accordion>
|
|
61
|
+
<Accordion title="Can I replace a provider later?">
|
|
62
|
+
Yes. Keep your channel sender calls and construct it with another transport that implements the same channel contract.
|
|
63
|
+
</Accordion>
|
|
64
|
+
</Accordions>
|
|
65
|
+
|
|
66
|
+
## Learn more
|
|
67
|
+
|
|
68
|
+
- [Install sently](./installation)
|
|
69
|
+
- [Choose an entrypoint](./entrypoints)
|
|
70
|
+
- [Explore channels](../channels)
|
|
71
|
+
|
|
72
|
+
## Next
|
|
73
|
+
|
|
74
|
+
<Cards>
|
|
75
|
+
<Card title="Email quick start" href="/docs/quick-start/email" />
|
|
76
|
+
<Card title="Channels" href="/docs/channels" />
|
|
77
|
+
</Cards>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migrate from Nodemailer
|
|
3
|
+
description: Move SMTP configuration and message fields to sently incrementally.
|
|
4
|
+
icon: ArrowRightLeft
|
|
5
|
+
source: "README.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Keep your message object, replace transporter construction, and await the sently factory.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createSMTPMailer } from "sently/smtp";
|
|
12
|
+
|
|
13
|
+
const mailer = await createSMTPMailer({
|
|
14
|
+
host: "smtp.example.com",
|
|
15
|
+
auth: { user: "user@example.com", pass: process.env.SMTP_PASSWORD! },
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
<Callout title="The one rule">Use `createSMTPMailer` for relay configuration; use `createMailer` only with an explicit transport.</Callout>
|
|
20
|
+
|
|
21
|
+
<Accordions><Accordion title="Why does transport-only createMailer reject host?">It only accepts a `transport`. Move relay configuration to `createSMTPMailer`.</Accordion></Accordions>
|
|
22
|
+
|
|
23
|
+
<Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Runtimes
|
|
3
|
+
description: sently supports Node.js, Bun, Deno, and Cloudflare Workers through focused integrations.
|
|
4
|
+
icon: Monitor
|
|
5
|
+
source: "README.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
HTTP transports use `fetch` and suit the supported runtimes. SMTP requires an adapter when automatic detection is unavailable.
|
|
9
|
+
|
|
10
|
+
| Runtime | SMTP adapter subpath |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| Node.js | `sently/adapters/node` |
|
|
13
|
+
| Bun | `sently/adapters/bun` |
|
|
14
|
+
| Deno | `sently/adapters/deno` |
|
|
15
|
+
| Cloudflare Workers | `sently/adapters/cf` |
|
|
16
|
+
|
|
17
|
+
<Cards><Card title="Adapters" href="/docs/guides/adapters" /></Cards>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adapters
|
|
3
|
+
description: Configure an explicit SMTP socket adapter for a supported runtime.
|
|
4
|
+
icon: Plug
|
|
5
|
+
source: "src/adapters/node.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Use an adapter only when SMTP auto-detection is not suitable for your runtime.</Callout>
|
|
9
|
+
|
|
10
|
+
| Runtime | Import | Class |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| Node.js | `sently/adapters/node` | `NodeAdapter` |
|
|
13
|
+
| Bun | `sently/adapters/bun` | `BunAdapter` |
|
|
14
|
+
| Deno | `sently/adapters/deno` | `DenoAdapter` |
|
|
15
|
+
| Cloudflare Workers | `sently/adapters/cf` | `CloudflareAdapter` |
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createSMTPMailer } from "sently/smtp";
|
|
19
|
+
import { NodeAdapter } from "sently/adapters/node";
|
|
20
|
+
|
|
21
|
+
const mailer = await createSMTPMailer({ host: "smtp.example.com", adapter: new NodeAdapter() });
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
<Accordions><Accordion title="Why does SMTP fail on an edge runtime?">Use an HTTP transport, or provide the runtime's supported SMTP adapter.</Accordion></Accordions>
|
|
25
|
+
|
|
26
|
+
<Cards><Card title="SMTP transport" href="/docs/transports/smtp" /></Cards>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Attachments
|
|
3
|
+
description: Attach bytes, strings, or runtime-supported file paths to email.
|
|
4
|
+
icon: Paperclip
|
|
5
|
+
source: "src/core/types.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Use `content` for portable attachments; `path` is available only on Node.js and Bun.</Callout>
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
await mailer.send({
|
|
12
|
+
from: "hello@example.com", to: "person@example.com", subject: "Invoice",
|
|
13
|
+
attachments: [{ filename: "invoice.txt", content: "Paid" }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Attachments can set `contentType`, `encoding`, `contentId`, `inline`, and MIME `headers`.
|
|
18
|
+
|
|
19
|
+
<Cards><Card title="Mail options" href="/docs/reference/mail-options" /></Cards>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Bundle size
|
|
3
|
+
description: Keep imports focused on the channel and transport your app actually uses.
|
|
4
|
+
icon: PackageOpen
|
|
5
|
+
source: "package.json"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
sently is split into subpaths so a receipt mailer does not pull SMS, SMTP pooling, or unused providers.
|
|
9
|
+
Measure stacks with `bun run measure:size` in the library repo when you change imports.
|
|
10
|
+
|
|
11
|
+
<Callout title="The one rule">
|
|
12
|
+
Import channel senders and provider transports from subpaths — never from a convenience barrel
|
|
13
|
+
when a focused path exists.
|
|
14
|
+
</Callout>
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
<Steps>
|
|
19
|
+
|
|
20
|
+
<Step>
|
|
21
|
+
### Prefer mailer + one transport
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createMailer } from "sently/mailer";
|
|
25
|
+
import { SndrTransport } from "sently/transports/sndr";
|
|
26
|
+
|
|
27
|
+
const mailer = await createMailer({
|
|
28
|
+
transport: new SndrTransport({ apiKey: process.env.SNDR_API_KEY! }),
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
</Step>
|
|
33
|
+
|
|
34
|
+
<Step>
|
|
35
|
+
### Prefer one webhook parser
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { parse, verifySignature } from "sently/webhooks/sndr";
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Avoid `import { … } from "sently/webhooks"` in Node/Deno without a bundler — that barrel evaluates every provider module.
|
|
42
|
+
|
|
43
|
+
</Step>
|
|
44
|
+
|
|
45
|
+
</Steps>
|
|
46
|
+
|
|
47
|
+
## Typical stacks
|
|
48
|
+
|
|
49
|
+
| Stack | Imports | Notes |
|
|
50
|
+
| ----- | ------- | ----- |
|
|
51
|
+
| HTTP email (SNDR) | `sently/mailer` + `sently/transports/sndr` | Small HTTP path. |
|
|
52
|
+
| HTTP email (Resend) | `sently/mailer` + `sently/transports/resend` | Includes attachment helpers. |
|
|
53
|
+
| SMS | `sently/sms` + `sently/transports/twilio-sms` | Channel + one SMS transport. |
|
|
54
|
+
| SMTP | `sently/smtp` | Separate from `sently/mailer`. |
|
|
55
|
+
|
|
56
|
+
## Troubleshooting
|
|
57
|
+
|
|
58
|
+
<Accordions>
|
|
59
|
+
|
|
60
|
+
<Accordion title="Why did importing createMailer from sently get larger?">
|
|
61
|
+
|
|
62
|
+
With a bundler and `sideEffects: false`, unused re-exports usually shake out. Without a bundler, the main barrel still evaluates its static imports (SMTP factory, Fallback, Cloudflare Email, …). Prefer `sently/mailer` for HTTP-only apps.
|
|
63
|
+
|
|
64
|
+
</Accordion>
|
|
65
|
+
|
|
66
|
+
</Accordions>
|
|
67
|
+
|
|
68
|
+
## Learn more
|
|
69
|
+
|
|
70
|
+
- [Entrypoints](/docs/get-started/entrypoints) — which path to import
|
|
71
|
+
- [Exports](/docs/reference/exports) — full map
|
|
72
|
+
|
|
73
|
+
## Next
|
|
74
|
+
|
|
75
|
+
<Cards>
|
|
76
|
+
<Card title="Entrypoints" description="Choose a focused import." href="/docs/get-started/entrypoints" />
|
|
77
|
+
<Card title="SNDR" description="Small HTTP email transport." href="/docs/transports/sndr" />
|
|
78
|
+
</Cards>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: DKIM
|
|
3
|
+
description: Sign outgoing messages with RSA-SHA256 or Ed25519-SHA256.
|
|
4
|
+
icon: KeyRound
|
|
5
|
+
source: "src/dkim.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Keep the private key out of source control and publish the matching DNS record before sending.</Callout>
|
|
9
|
+
|
|
10
|
+
<Steps><Step title="Sign a raw message">
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { signDKIM } from "sently/dkim";
|
|
14
|
+
|
|
15
|
+
const result = await signDKIM(rawMessage, {
|
|
16
|
+
domainName: "example.com", keySelector: "2024", privateKey: process.env.DKIM_PRIVATE_KEY!,
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
</Step></Steps>
|
|
21
|
+
|
|
22
|
+
SMTP configuration also accepts `dkim`.
|
|
23
|
+
|
|
24
|
+
<Accordions><Accordion title="Which keys are supported?">RSA keys of at least 1024 bits and Ed25519 keys are supported.</Accordion></Accordions>
|
|
25
|
+
|
|
26
|
+
<Cards><Card title="SMTP transport" href="/docs/transports/smtp" /></Cards>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Guides
|
|
3
|
+
description: Configure sently features around your delivery workflow.
|
|
4
|
+
icon: FolderOpen
|
|
5
|
+
source: "README.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Configure sently features around your delivery workflow.
|
|
9
|
+
|
|
10
|
+
<Cards>
|
|
11
|
+
<Card title="Adapters" href="/docs/guides/adapters" />
|
|
12
|
+
<Card title="Webhooks" href="/docs/guides/webhooks" />
|
|
13
|
+
<Card title="Security" href="/docs/guides/security" />
|
|
14
|
+
<Card title="Bulk sending" href="/docs/guides/send-bulk" />
|
|
15
|
+
</Cards>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Guides",
|
|
3
|
+
"icon": "Map",
|
|
4
|
+
"pages": [
|
|
5
|
+
"index",
|
|
6
|
+
"adapters",
|
|
7
|
+
"dkim",
|
|
8
|
+
"oauth2",
|
|
9
|
+
"pool",
|
|
10
|
+
"plugins-template",
|
|
11
|
+
"react-email",
|
|
12
|
+
"webhooks",
|
|
13
|
+
"observability",
|
|
14
|
+
"vendor-extras-otp",
|
|
15
|
+
"security",
|
|
16
|
+
"attachments",
|
|
17
|
+
"send-bulk",
|
|
18
|
+
"webpush-interop",
|
|
19
|
+
"bundle-size"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: OAuth2
|
|
3
|
+
description: Refresh OAuth2 tokens and use them for SMTP XOAUTH2 authentication.
|
|
4
|
+
icon: Key
|
|
5
|
+
source: "src/auth/oauth2.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Use a refresh token or `getToken`; do not embed a short-lived access token in application code.</Callout>
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { OAuth2Client } from "sently/auth/oauth2";
|
|
12
|
+
|
|
13
|
+
const client = new OAuth2Client({
|
|
14
|
+
user: "me@example.com", clientId: "...", clientSecret: "...", refreshToken: "...",
|
|
15
|
+
});
|
|
16
|
+
const token = await client.getAccessToken();
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`OAuth2Client` caches tokens in memory and refreshes them before expiry.
|
|
20
|
+
|
|
21
|
+
<Accordions><Accordion title="Can I supply tokens myself?">Yes. Provide `getToken` in the OAuth2 configuration.</Accordion></Accordions>
|
|
22
|
+
|
|
23
|
+
<Cards><Card title="SMTP transport" href="/docs/transports/smtp" /></Cards>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Observability
|
|
3
|
+
description: Attach lifecycle hooks or use the console observer for delivery diagnostics.
|
|
4
|
+
icon: ChartNoAxesColumn
|
|
5
|
+
source: "src/observability/console.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Capture metadata and durations, not message content or credentials.</Callout>
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { consoleObserver } from "sently/observability";
|
|
12
|
+
|
|
13
|
+
const mailer = await createMailer({ transport, hooks: consoleObserver("[mail]") });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
<Cards><Card title="Hooks" href="/docs/channels/hooks" /></Cards>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Template plugin
|
|
3
|
+
description: Render named HTML email templates before delivery.
|
|
4
|
+
icon: FileCode
|
|
5
|
+
source: "src/plugins/template.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Return a new message object from plugins; do not mutate the input.</Callout>
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { simpleEngine, templatePlugin } from "sently/plugins/template";
|
|
12
|
+
|
|
13
|
+
const plugin = templatePlugin({
|
|
14
|
+
engine: simpleEngine, templates: { welcome: "<h1>Hello, {{name}}!</h1>" },
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Send with `template: "welcome"` and `data: { name: "Ada" }`.
|
|
19
|
+
|
|
20
|
+
<Accordions><Accordion title="What happens to missing variables?">`simpleEngine` renders unknown variables as an empty string.</Accordion></Accordions>
|
|
21
|
+
|
|
22
|
+
<Cards><Card title="Mail options" href="/docs/reference/mail-options" /></Cards>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SMTP pooling
|
|
3
|
+
description: Reuse SMTP connections and apply shared rate limits.
|
|
4
|
+
icon: Network
|
|
5
|
+
source: "src/core/types.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Enable pooling only for a long-lived process that sends more than one message.</Callout>
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createSMTPMailer } from "sently/smtp";
|
|
12
|
+
|
|
13
|
+
const mailer = await createSMTPMailer({
|
|
14
|
+
host: "smtp.example.com", pool: true, maxConnections: 5, maxMessages: 100,
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Option | Default |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| `maxConnections` | 5 |
|
|
21
|
+
| `maxMessages` | 100 |
|
|
22
|
+
| `rateLimit` | 1000 ms |
|
|
23
|
+
|
|
24
|
+
<Cards><Card title="SMTP transport" href="/docs/transports/smtp" /></Cards>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: React Email
|
|
3
|
+
description: Render a React email element through the optional sently React plugin.
|
|
4
|
+
icon: Atom
|
|
5
|
+
source: "src/react.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Install the optional `react` and `@react-email/render` peer dependencies before using this integration.
|
|
9
|
+
|
|
10
|
+
<Callout title="The one rule">Import the React plugin from `sently/react`; it is not part of the main entrypoint.</Callout>
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { reactPlugin } from "sently/react";
|
|
14
|
+
|
|
15
|
+
const mailer = await createMailer({ transport, plugins: [reactPlugin()] });
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Pass the element as `react` in the mail options.
|
|
19
|
+
|
|
20
|
+
<Cards><Card title="Mail options" href="/docs/reference/mail-options" /></Cards>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Security
|
|
3
|
+
description: Protect credentials, delivery endpoints, and webhook integrity.
|
|
4
|
+
icon: ShieldCheck
|
|
5
|
+
source: "src/transports/webpush.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title="The one rule">Keep provider keys and VAPID private keys in a secrets manager or environment variables.</Callout>
|
|
9
|
+
|
|
10
|
+
- Enable TLS for SMTP authentication; `requireTLS` defaults to true when auth is set.
|
|
11
|
+
- Verify provider webhook signatures before parsing trusted events.
|
|
12
|
+
- Do not log email bodies, SMS bodies, or full push subscription endpoints.
|
|
13
|
+
- Treat a push endpoint as a delivery token.
|
|
14
|
+
|
|
15
|
+
<Accordions><Accordion title="Why is a push endpoint redacted in hooks?">Its path can contain a long-lived delivery token.</Accordion></Accordions>
|
|
16
|
+
|
|
17
|
+
<Cards><Card title="Webhooks" href="/docs/guides/webhooks" /></Cards>
|