sently 0.10.0 → 1.0.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 +1 -1
- package/CHANGELOG.md +50 -2
- package/README.md +21 -18
- package/SECURITY.md +59 -0
- package/dist/chunk-z1589fjk.js.map +1 -1
- package/dist/core/push-types.d.ts +1 -1
- package/dist/transports/mailpit.d.ts +166 -0
- package/dist/transports/mailpit.js +3 -0
- package/dist/transports/mailpit.js.map +10 -0
- package/dist/transports/webpush.d.ts +5 -1
- package/dist/transports/webpush.js +2 -2
- package/dist/transports/webpush.js.map +3 -3
- package/package.json +15 -2
- package/site/content/docs/ai/llms-txt.mdx +47 -2
- package/site/content/docs/channels/email.mdx +3 -0
- package/site/content/docs/channels/index.mdx +3 -1
- package/site/content/docs/channels/push.mdx +4 -0
- package/site/content/docs/decorators/fallback.mdx +5 -0
- package/site/content/docs/decorators/index.mdx +2 -1
- package/site/content/docs/decorators/preview.mdx +52 -9
- package/site/content/docs/get-started/entrypoints.mdx +5 -3
- package/site/content/docs/get-started/index.mdx +8 -2
- package/site/content/docs/get-started/introduction.mdx +7 -3
- package/site/content/docs/get-started/meta.json +4 -1
- package/site/content/docs/get-started/migrate-nodemailer.mdx +132 -5
- package/site/content/docs/get-started/non-goals.mdx +57 -0
- package/site/content/docs/get-started/stability.mdx +69 -0
- package/site/content/docs/get-started/support-matrix.mdx +62 -0
- package/site/content/docs/guides/compare.mdx +87 -0
- package/site/content/docs/guides/failover.mdx +121 -0
- package/site/content/docs/guides/index.mdx +2 -0
- package/site/content/docs/guides/meta.json +2 -0
- package/site/content/docs/guides/security.mdx +38 -8
- package/site/content/docs/index.mdx +78 -4
- package/site/content/docs/meta.json +0 -1
- package/site/content/docs/reference/exports.mdx +5 -2
- package/site/content/docs/reference/push-options.mdx +14 -0
- package/site/content/docs/transports/fcm.mdx +8 -4
- package/site/content/docs/transports/index.mdx +9 -3
- package/site/content/docs/transports/mailpit.mdx +123 -0
- package/site/content/docs/transports/meta.json +1 -0
- package/site/content/docs/transports/smtp.mdx +61 -22
- package/site/content/docs/transports/webpush.mdx +9 -2
- package/site/content/docs/quick-start/email.mdx +0 -40
- package/site/content/docs/quick-start/index.mdx +0 -15
- package/site/content/docs/quick-start/meta.json +0 -5
- package/site/content/docs/quick-start/push.mdx +0 -53
- package/site/content/docs/quick-start/sms.mdx +0 -36
- package/site/content/docs/quick-start/whatsapp.mdx +0 -38
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Mailpit
|
|
3
|
+
description: Catch outbound email in a local Mailpit instance during development.
|
|
4
|
+
icon: Inbox
|
|
5
|
+
source: "src/transports/mailpit.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Catch outbound email in a local [Mailpit](https://github.com/axllent/mailpit) instance while you develop.
|
|
9
|
+
Use it for the welcome email or password-reset flow before you point at a production provider.
|
|
10
|
+
|
|
11
|
+
<Callout title="The one rule">
|
|
12
|
+
Use Mailpit only in development — swap to a production transport before you deploy.
|
|
13
|
+
</Callout>
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
Start Mailpit (SMTP `1025`, UI `8025`):
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
docker run -d --rm -p 1025:1025 -p 8025:8025 axllent/mailpit
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
<Steps>
|
|
24
|
+
<Step title="Create the transport">
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { createMailer } from "sently/mailer";
|
|
28
|
+
import { MailpitTransport } from "sently/transports/mailpit";
|
|
29
|
+
|
|
30
|
+
const mailpit = new MailpitTransport();
|
|
31
|
+
const mailer = await createMailer({ transport: mailpit });
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
</Step>
|
|
35
|
+
<Step title="Send through the mailer">
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
await mailer.send({
|
|
39
|
+
from: "dev@example.com",
|
|
40
|
+
to: "you@example.com",
|
|
41
|
+
subject: "Hello",
|
|
42
|
+
text: "Captured by Mailpit",
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
</Step>
|
|
47
|
+
<Step title="Inspect the inbox">
|
|
48
|
+
|
|
49
|
+
Open `http://localhost:8025`, or list messages from code:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const inbox = await mailpit.messages();
|
|
53
|
+
console.log(inbox.messages[0]?.Subject);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
</Step>
|
|
57
|
+
</Steps>
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
| Option | Type | Default | Meaning |
|
|
62
|
+
| --- | --- | --- | --- |
|
|
63
|
+
| `host` | `string` | `"localhost"` | SMTP hostname |
|
|
64
|
+
| `port` | `number` | `1025` | SMTP port |
|
|
65
|
+
| `secure` | `boolean` | `false` | Implicit TLS on connect |
|
|
66
|
+
| `requireTLS` | `boolean` | `false` | Refuse AUTH without TLS |
|
|
67
|
+
| `auth` | `SMTPAuth` | — | Optional SMTP credentials |
|
|
68
|
+
| `tls` | `TLSOptions` | — | TLS options when TLS is enabled |
|
|
69
|
+
| `connectionTimeout` | `number` | — | Socket connect timeout (ms) |
|
|
70
|
+
| `adapter` | `SocketAdapter` | auto-detected | Runtime TCP adapter |
|
|
71
|
+
| `apiUrl` | `string` | `"http://localhost:8025"` | Web UI / REST API base |
|
|
72
|
+
| `apiAuth` | `{ user, pass }` | — | Basic auth for the UI/API |
|
|
73
|
+
|
|
74
|
+
`provider` is `"mailpit"`. `verify()` checks SMTP; `close()` closes the socket adapter.
|
|
75
|
+
|
|
76
|
+
## REST helpers
|
|
77
|
+
|
|
78
|
+
Vendor extras stay on the transport instance (not on `createMailer`):
|
|
79
|
+
|
|
80
|
+
| Method | Mailpit API | Meaning |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `messages({ limit?, start? })` | `GET /api/v1/messages` | List captured messages (newest first) |
|
|
83
|
+
| `getMessage(id)` | `GET /api/v1/message/{id}` | Full message body |
|
|
84
|
+
| `deleteMessages(ids)` | `DELETE /api/v1/messages` | Delete by id |
|
|
85
|
+
| `deleteAll()` | `DELETE` with empty `IDs` | Clear the inbox |
|
|
86
|
+
| `webUrl` | — | UI base URL (same as `apiUrl`) |
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
await mailpit.deleteAll();
|
|
90
|
+
await mailer.send({ from: "a@test.com", to: "b@test.com", subject: "T", text: "ok" });
|
|
91
|
+
const list = await mailpit.messages({ limit: 1 });
|
|
92
|
+
const full = await mailpit.getMessage(list.messages[0]!.ID);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
REST failures throw `MailpitError` (`provider: "mailpit"`). Empty `getMessage("")` throws with status `400`.
|
|
96
|
+
|
|
97
|
+
## Troubleshooting
|
|
98
|
+
|
|
99
|
+
<Accordions>
|
|
100
|
+
<Accordion title="Connection refused on port 1025">
|
|
101
|
+
Mailpit is not running, or the SMTP port is remapped. Start the container above, or set `host` / `port` to match your install.
|
|
102
|
+
</Accordion>
|
|
103
|
+
<Accordion title="API helpers fail but send works">
|
|
104
|
+
SMTP and the UI/API can bind to different hosts. Set `apiUrl` (and `apiAuth` if the UI requires Basic auth).
|
|
105
|
+
</Accordion>
|
|
106
|
+
<Accordion title="Should I use createSMTPMailer instead?">
|
|
107
|
+
Yes, if you only need SMTP. `MailpitTransport` adds local defaults and REST helpers for tests and inspection.
|
|
108
|
+
</Accordion>
|
|
109
|
+
</Accordions>
|
|
110
|
+
|
|
111
|
+
## Learn more
|
|
112
|
+
|
|
113
|
+
- [SMTP](./smtp) — generic SMTP when you are not on Mailpit
|
|
114
|
+
- [Preview](/docs/decorators/preview) — write `.eml` files to disk instead
|
|
115
|
+
- [Email channel](/docs/channels/email) — `createMailer` contract
|
|
116
|
+
|
|
117
|
+
## Next
|
|
118
|
+
|
|
119
|
+
<Cards>
|
|
120
|
+
<Card title="Email channel" href="/docs/channels/email" />
|
|
121
|
+
<Card title="SMTP" href="/docs/transports/smtp" />
|
|
122
|
+
<Card title="Transports" href="/docs/transports" />
|
|
123
|
+
</Cards>
|
|
@@ -1,47 +1,86 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: SMTP
|
|
3
|
-
description: Connect to an SMTP relay with
|
|
3
|
+
description: Connect to an SMTP relay with host, port, and auth.
|
|
4
4
|
icon: Truck
|
|
5
5
|
source: "src/transports/smtp.ts"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Connect to an SMTP relay
|
|
8
|
+
Connect to an SMTP relay for production or a local catcher.
|
|
9
|
+
Prefer `createSMTPMailer` when your config starts with host and port — it picks a runtime adapter for you.
|
|
9
10
|
|
|
10
|
-
<Callout title="The one rule">
|
|
11
|
+
<Callout title="The one rule">
|
|
12
|
+
Use `createSMTPMailer` for host/port config; use `createMailer` only with an explicit `SMTPTransport` that already has an adapter.
|
|
13
|
+
</Callout>
|
|
11
14
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
| Option | Type | Default or requirement |
|
|
15
|
-
| --- | --- | --- |
|
|
16
|
-
| `host` | `string` | required |
|
|
17
|
-
| `port` | `number` | 587 or 465 based on secure |
|
|
18
|
-
| `secure` | `boolean` | false |
|
|
19
|
-
| `auth` | `SMTPAuth` | optional |
|
|
20
|
-
| `requireTLS` | `boolean` | true when auth is set |
|
|
21
|
-
| `adapter` | `SocketAdapter` | optional |
|
|
22
|
-
| `pool` | `boolean` | false |
|
|
23
|
-
| `dkim` | `DKIMConfig` | optional |
|
|
15
|
+
## Quick start
|
|
24
16
|
|
|
25
17
|
<Steps>
|
|
26
|
-
<Step title="
|
|
18
|
+
<Step title="Create an SMTP mailer">
|
|
27
19
|
|
|
28
20
|
```ts
|
|
29
|
-
import {
|
|
30
|
-
import { SMTPTransport } from "sently/transports/smtp";
|
|
21
|
+
import { createSMTPMailer } from "sently/smtp";
|
|
31
22
|
|
|
32
|
-
const
|
|
23
|
+
const mailer = await createSMTPMailer({
|
|
24
|
+
host: "smtp.example.com",
|
|
25
|
+
port: 587,
|
|
26
|
+
auth: { user: "you@example.com", pass: process.env.SMTP_PASSWORD! },
|
|
27
|
+
});
|
|
33
28
|
```
|
|
34
29
|
|
|
35
30
|
</Step>
|
|
36
31
|
<Step title="Send with the channel API">
|
|
37
32
|
|
|
38
33
|
```ts
|
|
39
|
-
await
|
|
34
|
+
await mailer.send({
|
|
35
|
+
from: "hello@example.com",
|
|
36
|
+
to: "person@example.com",
|
|
37
|
+
subject: "Hello",
|
|
38
|
+
text: "Hi",
|
|
39
|
+
});
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
</Step>
|
|
43
43
|
</Steps>
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
| Option | Type | Default or requirement |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `host` | `string` | required |
|
|
50
|
+
| `port` | `number` | `587`, or `465` when `secure` |
|
|
51
|
+
| `secure` | `boolean` | `false` |
|
|
52
|
+
| `auth` | `SMTPAuth` | optional |
|
|
53
|
+
| `requireTLS` | `boolean` | `true` when `auth` is set |
|
|
54
|
+
| `adapter` | `SocketAdapter` | auto via `createSMTPMailer` |
|
|
55
|
+
| `pool` | `boolean` | `false` |
|
|
56
|
+
| `dkim` | `DKIMConfig` | optional |
|
|
57
|
+
|
|
58
|
+
For local capture with defaults and REST helpers, use [Mailpit](./mailpit) instead of hand-wiring `localhost:1025`.
|
|
59
|
+
|
|
60
|
+
## Troubleshooting
|
|
61
|
+
|
|
62
|
+
<Accordions>
|
|
63
|
+
<Accordion title="Should I call the provider SDK?">
|
|
64
|
+
No. Use the sently sender; provider-specific extras stay on the transport instance.
|
|
65
|
+
</Accordion>
|
|
66
|
+
<Accordion title="createMailer rejects host and port">
|
|
67
|
+
Pass an explicit transport, or use `createSMTPMailer` for relay configuration.
|
|
68
|
+
</Accordion>
|
|
69
|
+
<Accordion title="Local development without a real relay">
|
|
70
|
+
Use [Mailpit](./mailpit) (`sently/transports/mailpit`) or [Preview](/docs/decorators/preview).
|
|
71
|
+
</Accordion>
|
|
72
|
+
</Accordions>
|
|
73
|
+
|
|
74
|
+
## Learn more
|
|
75
|
+
|
|
76
|
+
- [Mailpit](./mailpit) — local SMTP catcher with inbox API
|
|
77
|
+
- [Email channel](/docs/channels/email) — `createMailer` / `createSMTPMailer`
|
|
78
|
+
- [Runtimes](/docs/get-started/runtimes) — socket adapters
|
|
79
|
+
|
|
80
|
+
## Next
|
|
46
81
|
|
|
47
|
-
<Cards
|
|
82
|
+
<Cards>
|
|
83
|
+
<Card title="Mailpit" href="/docs/transports/mailpit" />
|
|
84
|
+
<Card title="Email channel" href="/docs/channels/email" />
|
|
85
|
+
<Card title="Transports" href="/docs/transports" />
|
|
86
|
+
</Cards>
|
|
@@ -15,7 +15,7 @@ Encrypt and send browser notifications with VAPID.
|
|
|
15
15
|
| --- | --- | --- |
|
|
16
16
|
| `vapidPublicKey` | `string` | required |
|
|
17
17
|
| `vapidPrivateKey` | `string` | required |
|
|
18
|
-
| `subject` | `string` | required |
|
|
18
|
+
| `subject` | `string` | required — `mailto:you@example.com` or `https://example.com/contact` (validated at construction) |
|
|
19
19
|
| `allowedEndpointHosts` | `string[]` | optional |
|
|
20
20
|
|
|
21
21
|
<Steps>
|
|
@@ -38,6 +38,13 @@ await sender.send({ subscription, title: "Hello", body: "World" });
|
|
|
38
38
|
</Step>
|
|
39
39
|
</Steps>
|
|
40
40
|
|
|
41
|
-
<Accordions
|
|
41
|
+
<Accordions>
|
|
42
|
+
<Accordion title="Should I call the provider SDK?">
|
|
43
|
+
No. Use the sently sender; provider-specific extras stay on the transport instance.
|
|
44
|
+
</Accordion>
|
|
45
|
+
<Accordion title="Why does construction throw on subject?">
|
|
46
|
+
VAPID `subject` must be a real `mailto:` address or `https:` URL. Values like `@oke.local` (no prefix) are rejected immediately as `WebPushError` so push services never return a confusing 403 later.
|
|
47
|
+
</Accordion>
|
|
48
|
+
</Accordions>
|
|
42
49
|
|
|
43
50
|
<Cards><Card title="Push channel" href="/docs/channels/push" /></Cards>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Email
|
|
3
|
-
description: Send email through an HTTP transport.
|
|
4
|
-
icon: Mail
|
|
5
|
-
source: "src/mailer.ts"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
<Callout title="The one rule">`createMailer` is asynchronous; await it before sending.</Callout>
|
|
9
|
-
|
|
10
|
-
<Steps>
|
|
11
|
-
<Step title="Create a transport-backed mailer">
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createMailer } from "sently/mailer";
|
|
15
|
-
import { ResendTransport } from "sently/transports/resend";
|
|
16
|
-
|
|
17
|
-
const mailer = await createMailer({
|
|
18
|
-
transport: new ResendTransport({ apiKey: process.env.RESEND_API_KEY! }),
|
|
19
|
-
});
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
</Step>
|
|
23
|
-
<Step title="Send email">
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
await mailer.send({
|
|
27
|
-
from: "hello@example.com",
|
|
28
|
-
to: "person@example.com",
|
|
29
|
-
subject: "Welcome",
|
|
30
|
-
text: "Thanks for joining.",
|
|
31
|
-
});
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
</Step>
|
|
35
|
-
</Steps>
|
|
36
|
-
|
|
37
|
-
<Cards>
|
|
38
|
-
<Card title="Email channel" href="/docs/channels/email" />
|
|
39
|
-
<Card title="Resend transport" href="/docs/transports/resend" />
|
|
40
|
-
</Cards>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Quick start
|
|
3
|
-
description: Send your first message on each channel.
|
|
4
|
-
icon: Zap
|
|
5
|
-
source: "README.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Pick a channel and send in a few lines. Same model every time — sender, transport, send.
|
|
9
|
-
|
|
10
|
-
<Cards>
|
|
11
|
-
<Card title="Email" href="/docs/quick-start/email" />
|
|
12
|
-
<Card title="SMS" href="/docs/quick-start/sms" />
|
|
13
|
-
<Card title="WhatsApp" href="/docs/quick-start/whatsapp" />
|
|
14
|
-
<Card title="Push" href="/docs/quick-start/push" />
|
|
15
|
-
</Cards>
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Push
|
|
3
|
-
description: Send a Web Push or FCM notification through a channel sender.
|
|
4
|
-
icon: Bell
|
|
5
|
-
source: "src/push.ts"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Send a browser Web Push or FCM device notification through `createPushSender`.
|
|
9
|
-
|
|
10
|
-
<Callout title="The one rule">
|
|
11
|
-
Use `subscription` with `WebPushTransport`, or `token` with `FcmTransport` — not both shapes on the wrong transport.
|
|
12
|
-
</Callout>
|
|
13
|
-
|
|
14
|
-
## Quick start
|
|
15
|
-
|
|
16
|
-
<Steps>
|
|
17
|
-
<Step title="Create a Web Push sender">
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import { createPushSender } from "sently/push";
|
|
21
|
-
import { WebPushTransport } from "sently/transports/webpush";
|
|
22
|
-
|
|
23
|
-
const push = createPushSender({
|
|
24
|
-
transport: new WebPushTransport({
|
|
25
|
-
vapidPublicKey: process.env.VAPID_PUBLIC_KEY!,
|
|
26
|
-
vapidPrivateKey: process.env.VAPID_PRIVATE_KEY!,
|
|
27
|
-
subject: "mailto:you@example.com",
|
|
28
|
-
}),
|
|
29
|
-
});
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
</Step>
|
|
33
|
-
<Step title="Send">
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
await push.send({
|
|
37
|
-
subscription,
|
|
38
|
-
title: "Update",
|
|
39
|
-
body: "Your report is ready.",
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
</Step>
|
|
44
|
-
</Steps>
|
|
45
|
-
|
|
46
|
-
For FCM device tokens, use `FcmTransport` and `token` instead of `subscription` — see [FCM](/docs/transports/fcm).
|
|
47
|
-
|
|
48
|
-
## Next
|
|
49
|
-
|
|
50
|
-
<Cards>
|
|
51
|
-
<Card title="Push channel" href="/docs/channels/push" />
|
|
52
|
-
<Card title="FCM transport" href="/docs/transports/fcm" />
|
|
53
|
-
</Cards>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: SMS
|
|
3
|
-
description: Send an SMS through a channel sender.
|
|
4
|
-
icon: MessageSquareText
|
|
5
|
-
source: "src/sms.ts"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
<Callout title="The one rule">Create the SMS sender once, then call `send` with `to` and `body`.</Callout>
|
|
9
|
-
|
|
10
|
-
<Steps>
|
|
11
|
-
<Step title="Create the sender">
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createSmsSender } from "sently/sms";
|
|
15
|
-
import { TwilioSmsTransport } from "sently/transports/twilio-sms";
|
|
16
|
-
|
|
17
|
-
const sms = createSmsSender({
|
|
18
|
-
transport: new TwilioSmsTransport({
|
|
19
|
-
accountSid: process.env.TWILIO_ACCOUNT_SID!,
|
|
20
|
-
authToken: process.env.TWILIO_AUTH_TOKEN!,
|
|
21
|
-
from: "+15557654321",
|
|
22
|
-
}),
|
|
23
|
-
});
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
</Step>
|
|
27
|
-
<Step title="Send">
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
await sms.send({ to: "+15551234567", body: "Your code is ready." });
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
</Step>
|
|
34
|
-
</Steps>
|
|
35
|
-
|
|
36
|
-
<Cards><Card title="SMS channel" href="/docs/channels/sms" /></Cards>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: WhatsApp
|
|
3
|
-
description: Send a WhatsApp message through a channel sender.
|
|
4
|
-
icon: MessagesSquare
|
|
5
|
-
source: "src/whatsapp.ts"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
<Callout title="The one rule">Use a template outside the open customer-service window; use free text only inside it.</Callout>
|
|
9
|
-
|
|
10
|
-
<Steps>
|
|
11
|
-
<Step title="Create the sender">
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createWhatsAppSender } from "sently/whatsapp";
|
|
15
|
-
import { WhatsAppCloudTransport } from "sently/transports/whatsapp-cloud";
|
|
16
|
-
|
|
17
|
-
const whatsapp = createWhatsAppSender({
|
|
18
|
-
transport: new WhatsAppCloudTransport({
|
|
19
|
-
accessToken: process.env.WHATSAPP_TOKEN!,
|
|
20
|
-
phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID!,
|
|
21
|
-
}),
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
</Step>
|
|
26
|
-
<Step title="Send a template">
|
|
27
|
-
|
|
28
|
-
```ts
|
|
29
|
-
await whatsapp.send({
|
|
30
|
-
to: "15551234567",
|
|
31
|
-
template: { name: "welcome", language: "en_US" },
|
|
32
|
-
});
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
</Step>
|
|
36
|
-
</Steps>
|
|
37
|
-
|
|
38
|
-
<Cards><Card title="WhatsApp channel" href="/docs/channels/whatsapp" /></Cards>
|