sently 0.8.0 → 0.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.
Files changed (249) hide show
  1. package/AGENTS.md +34 -0
  2. package/CHANGELOG.md +33 -1
  3. package/README.md +89 -960
  4. package/dist/adapters/bun.js +1 -1
  5. package/dist/adapters/cf.js +2 -2
  6. package/dist/adapters/cf.js.map +2 -2
  7. package/dist/adapters/deno.js +1 -1
  8. package/dist/adapters/node.js +1 -1
  9. package/dist/auth/oauth2.js +2 -2
  10. package/dist/auth/oauth2.js.map +1 -1
  11. package/dist/chunk-0gqy32pe.js +4 -0
  12. package/dist/{chunk-n5dan5bz.js.map → chunk-0gqy32pe.js.map} +2 -2
  13. package/dist/{chunk-z62q7kqr.js → chunk-0qxws3kj.js} +2 -2
  14. package/dist/{chunk-z62q7kqr.js.map → chunk-0qxws3kj.js.map} +1 -1
  15. package/dist/chunk-29z7fkzy.js +4 -0
  16. package/dist/{chunk-wsymfbkn.js.map → chunk-29z7fkzy.js.map} +2 -2
  17. package/dist/chunk-5915vbcj.js +4 -0
  18. package/dist/chunk-5915vbcj.js.map +10 -0
  19. package/dist/{chunk-nbmq8ejv.js → chunk-6npp3x3c.js} +2 -2
  20. package/dist/{chunk-nbmq8ejv.js.map → chunk-6npp3x3c.js.map} +1 -1
  21. package/dist/chunk-7gy2q9sh.js +4 -0
  22. package/dist/chunk-7gy2q9sh.js.map +10 -0
  23. package/dist/{chunk-zst8an2p.js → chunk-8dty8c4p.js} +2 -2
  24. package/dist/{chunk-zst8an2p.js.map → chunk-8dty8c4p.js.map} +2 -2
  25. package/dist/{chunk-f3dz43cy.js → chunk-8njyga62.js} +2 -2
  26. package/dist/{chunk-f3dz43cy.js.map → chunk-8njyga62.js.map} +1 -1
  27. package/dist/chunk-93vqxxj2.js +4 -0
  28. package/dist/{chunk-qh90yr6d.js.map → chunk-93vqxxj2.js.map} +2 -2
  29. package/dist/chunk-b602dhck.js +4 -0
  30. package/dist/{chunk-wbvhaqcp.js.map → chunk-b602dhck.js.map} +2 -2
  31. package/dist/{chunk-9zkv5azm.js → chunk-gp4fwrs8.js} +2 -2
  32. package/dist/{chunk-9zkv5azm.js.map → chunk-gp4fwrs8.js.map} +1 -1
  33. package/dist/chunk-n0qeyzqm.js +13 -0
  34. package/dist/{chunk-8phpsns1.js.map → chunk-n0qeyzqm.js.map} +2 -2
  35. package/dist/chunk-qtkd5bak.js +4 -0
  36. package/dist/chunk-qtkd5bak.js.map +11 -0
  37. package/dist/chunk-skqhj0rm.js +4 -0
  38. package/dist/{chunk-vhxzhx8b.js.map → chunk-skqhj0rm.js.map} +2 -2
  39. package/dist/{chunk-6bkj4y4r.js → chunk-tamww15j.js} +2 -2
  40. package/dist/{chunk-6bkj4y4r.js.map → chunk-tamww15j.js.map} +1 -1
  41. package/dist/chunk-vjpds2pf.js +3 -0
  42. package/dist/{chunk-m07smapm.js.map → chunk-vjpds2pf.js.map} +2 -2
  43. package/dist/chunk-yp311efr.js +4 -0
  44. package/dist/chunk-yp311efr.js.map +10 -0
  45. package/dist/chunk-ywq6s10g.js +5 -0
  46. package/dist/{chunk-5scdgffb.js.map → chunk-ywq6s10g.js.map} +3 -3
  47. package/dist/core/base64.d.ts +10 -0
  48. package/dist/core/errors.js +2 -2
  49. package/dist/core/errors.js.map +1 -1
  50. package/dist/core/hooks.d.ts +14 -0
  51. package/dist/core/plugin.d.ts +7 -7
  52. package/dist/core/push-endpoint.d.ts +29 -0
  53. package/dist/core/push-types.d.ts +98 -0
  54. package/dist/core/sms-types.d.ts +76 -0
  55. package/dist/core/smtp.js +2 -2
  56. package/dist/core/smtp.js.map +1 -1
  57. package/dist/core/whatsapp-types.d.ts +116 -0
  58. package/dist/detect.js +2 -2
  59. package/dist/detect.js.map +1 -1
  60. package/dist/dkim.js +2 -2
  61. package/dist/dkim.js.map +2 -2
  62. package/dist/idempotency.js +2 -2
  63. package/dist/idempotency.js.map +1 -1
  64. package/dist/index.d.ts +5 -32
  65. package/dist/index.js +0 -35
  66. package/dist/mailer.js +2 -2
  67. package/dist/mailer.js.map +1 -1
  68. package/dist/observability/console.js +1 -1
  69. package/dist/plugins/react.js +2 -2
  70. package/dist/plugins/react.js.map +2 -2
  71. package/dist/plugins/template.js +1 -1
  72. package/dist/pool/pool.js +2 -2
  73. package/dist/pool/pool.js.map +1 -1
  74. package/dist/push.d.ts +26 -0
  75. package/dist/push.js +3 -0
  76. package/dist/push.js.map +10 -0
  77. package/dist/sms.d.ts +26 -0
  78. package/dist/sms.js +3 -0
  79. package/dist/sms.js.map +10 -0
  80. package/dist/smtp-mailer.js +2 -2
  81. package/dist/smtp-mailer.js.map +2 -2
  82. package/dist/transports/brevo.js +2 -2
  83. package/dist/transports/brevo.js.map +2 -2
  84. package/dist/transports/cloudflare-email.js +2 -2
  85. package/dist/transports/cloudflare-email.js.map +2 -2
  86. package/dist/transports/fallback.js +2 -2
  87. package/dist/transports/fallback.js.map +1 -1
  88. package/dist/transports/loops.js +2 -2
  89. package/dist/transports/loops.js.map +2 -2
  90. package/dist/transports/mailersend.js +2 -2
  91. package/dist/transports/mailersend.js.map +2 -2
  92. package/dist/transports/mailgun.js +2 -2
  93. package/dist/transports/mailgun.js.map +2 -2
  94. package/dist/transports/mailtrap.js +2 -2
  95. package/dist/transports/mailtrap.js.map +2 -2
  96. package/dist/transports/msegat.d.ts +132 -0
  97. package/dist/transports/msegat.js +3 -0
  98. package/dist/transports/msegat.js.map +10 -0
  99. package/dist/transports/plunk.js +2 -2
  100. package/dist/transports/plunk.js.map +2 -2
  101. package/dist/transports/postmark.js +2 -2
  102. package/dist/transports/postmark.js.map +2 -2
  103. package/dist/transports/preview.js +2 -2
  104. package/dist/transports/preview.js.map +2 -2
  105. package/dist/transports/resend.js +2 -2
  106. package/dist/transports/resend.js.map +2 -2
  107. package/dist/transports/retry.js +2 -2
  108. package/dist/transports/retry.js.map +2 -2
  109. package/dist/transports/sendgrid.js +2 -2
  110. package/dist/transports/sendgrid.js.map +2 -2
  111. package/dist/transports/ses.js +2 -2
  112. package/dist/transports/ses.js.map +2 -2
  113. package/dist/transports/smtp.js +2 -2
  114. package/dist/transports/smtp.js.map +1 -1
  115. package/dist/transports/sndr.d.ts +41 -0
  116. package/dist/transports/sndr.js +3 -0
  117. package/dist/transports/sndr.js.map +10 -0
  118. package/dist/transports/sparkpost.js +2 -2
  119. package/dist/transports/sparkpost.js.map +2 -2
  120. package/dist/transports/taqnyat-mail.d.ts +33 -0
  121. package/dist/transports/taqnyat-mail.js +3 -0
  122. package/dist/transports/taqnyat-mail.js.map +10 -0
  123. package/dist/transports/taqnyat-phone.d.ts +4 -0
  124. package/dist/transports/taqnyat-sms.d.ts +131 -0
  125. package/dist/transports/taqnyat-sms.js +3 -0
  126. package/dist/transports/taqnyat-sms.js.map +10 -0
  127. package/dist/transports/taqnyat-whatsapp.d.ts +51 -0
  128. package/dist/transports/taqnyat-whatsapp.js +3 -0
  129. package/dist/transports/taqnyat-whatsapp.js.map +10 -0
  130. package/dist/transports/twilio-sms.d.ts +66 -0
  131. package/dist/transports/twilio-sms.js +3 -0
  132. package/dist/transports/twilio-sms.js.map +10 -0
  133. package/dist/transports/webpush.d.ts +46 -0
  134. package/dist/transports/webpush.js +3 -0
  135. package/dist/transports/webpush.js.map +10 -0
  136. package/dist/transports/weighted-fallback.js +2 -2
  137. package/dist/transports/weighted-fallback.js.map +1 -1
  138. package/dist/transports/whatsapp-cloud.d.ts +56 -0
  139. package/dist/transports/whatsapp-cloud.js +3 -0
  140. package/dist/transports/whatsapp-cloud.js.map +10 -0
  141. package/dist/webhooks/brevo.js +1 -1
  142. package/dist/webhooks/mailgun.js +1 -1
  143. package/dist/webhooks/postmark.js +1 -1
  144. package/dist/webhooks/resend.js +1 -1
  145. package/dist/webhooks/sendgrid.js +1 -1
  146. package/dist/webhooks/ses.js +1 -1
  147. package/dist/webhooks/sndr.d.ts +16 -0
  148. package/dist/webhooks/sndr.js +3 -0
  149. package/dist/webhooks/sndr.js.map +10 -0
  150. package/dist/webhooks/timing-safe-equal.js +1 -1
  151. package/dist/webhooks.d.ts +9 -2
  152. package/dist/webhooks.js +4 -0
  153. package/dist/whatsapp.d.ts +26 -0
  154. package/dist/whatsapp.js +3 -0
  155. package/dist/whatsapp.js.map +10 -0
  156. package/package.json +85 -4
  157. package/site/README.md +26 -0
  158. package/site/content/docs/ai/index.mdx +13 -0
  159. package/site/content/docs/ai/llms-txt.mdx +12 -0
  160. package/site/content/docs/ai/mcp.mdx +16 -0
  161. package/site/content/docs/ai/meta.json +9 -0
  162. package/site/content/docs/channels/email.mdx +100 -0
  163. package/site/content/docs/channels/hooks.mdx +87 -0
  164. package/site/content/docs/channels/index.mdx +81 -0
  165. package/site/content/docs/channels/meta.json +12 -0
  166. package/site/content/docs/channels/push.mdx +92 -0
  167. package/site/content/docs/channels/sms.mdx +88 -0
  168. package/site/content/docs/channels/whatsapp.mdx +95 -0
  169. package/site/content/docs/decorators/fallback.mdx +34 -0
  170. package/site/content/docs/decorators/idempotency.mdx +34 -0
  171. package/site/content/docs/decorators/index.mdx +50 -0
  172. package/site/content/docs/decorators/meta.json +12 -0
  173. package/site/content/docs/decorators/preview.mdx +34 -0
  174. package/site/content/docs/decorators/retry.mdx +34 -0
  175. package/site/content/docs/decorators/weighted-fallback.mdx +34 -0
  176. package/site/content/docs/get-started/entrypoints.mdx +114 -0
  177. package/site/content/docs/get-started/index.mdx +14 -0
  178. package/site/content/docs/get-started/installation.mdx +78 -0
  179. package/site/content/docs/get-started/introduction.mdx +77 -0
  180. package/site/content/docs/get-started/meta.json +12 -0
  181. package/site/content/docs/get-started/migrate-nodemailer.mdx +23 -0
  182. package/site/content/docs/get-started/runtimes.mdx +17 -0
  183. package/site/content/docs/guides/adapters.mdx +26 -0
  184. package/site/content/docs/guides/attachments.mdx +19 -0
  185. package/site/content/docs/guides/bundle-size.mdx +78 -0
  186. package/site/content/docs/guides/dkim.mdx +26 -0
  187. package/site/content/docs/guides/index.mdx +15 -0
  188. package/site/content/docs/guides/meta.json +21 -0
  189. package/site/content/docs/guides/oauth2.mdx +23 -0
  190. package/site/content/docs/guides/observability.mdx +16 -0
  191. package/site/content/docs/guides/plugins-template.mdx +22 -0
  192. package/site/content/docs/guides/pool.mdx +24 -0
  193. package/site/content/docs/guides/react-email.mdx +20 -0
  194. package/site/content/docs/guides/security.mdx +17 -0
  195. package/site/content/docs/guides/send-bulk.mdx +18 -0
  196. package/site/content/docs/guides/vendor-extras-otp.mdx +18 -0
  197. package/site/content/docs/guides/webhooks.mdx +120 -0
  198. package/site/content/docs/guides/webpush-interop.mdx +18 -0
  199. package/site/content/docs/index.mdx +15 -0
  200. package/site/content/docs/meta.json +15 -0
  201. package/site/content/docs/quick-start/email.mdx +40 -0
  202. package/site/content/docs/quick-start/index.mdx +15 -0
  203. package/site/content/docs/quick-start/meta.json +5 -0
  204. package/site/content/docs/quick-start/push.mdx +36 -0
  205. package/site/content/docs/quick-start/sms.mdx +36 -0
  206. package/site/content/docs/quick-start/whatsapp.mdx +38 -0
  207. package/site/content/docs/reference/errors.mdx +22 -0
  208. package/site/content/docs/reference/exports.mdx +83 -0
  209. package/site/content/docs/reference/index.mdx +15 -0
  210. package/site/content/docs/reference/mail-options.mdx +22 -0
  211. package/site/content/docs/reference/meta.json +15 -0
  212. package/site/content/docs/reference/push-options.mdx +20 -0
  213. package/site/content/docs/reference/sms-options.mdx +17 -0
  214. package/site/content/docs/reference/transport-contracts.mdx +17 -0
  215. package/site/content/docs/reference/webhook-events.mdx +70 -0
  216. package/site/content/docs/reference/whatsapp-options.mdx +15 -0
  217. package/site/content/docs/transports/brevo.mdx +40 -0
  218. package/site/content/docs/transports/cloudflare-email.mdx +40 -0
  219. package/site/content/docs/transports/index.mdx +105 -0
  220. package/site/content/docs/transports/loops.mdx +41 -0
  221. package/site/content/docs/transports/mailersend.mdx +40 -0
  222. package/site/content/docs/transports/mailgun.mdx +42 -0
  223. package/site/content/docs/transports/mailtrap.mdx +42 -0
  224. package/site/content/docs/transports/meta.json +32 -0
  225. package/site/content/docs/transports/msegat.mdx +42 -0
  226. package/site/content/docs/transports/plunk.mdx +40 -0
  227. package/site/content/docs/transports/postmark.mdx +40 -0
  228. package/site/content/docs/transports/resend.mdx +43 -0
  229. package/site/content/docs/transports/sendgrid.mdx +40 -0
  230. package/site/content/docs/transports/ses.mdx +44 -0
  231. package/site/content/docs/transports/smtp.mdx +47 -0
  232. package/site/content/docs/transports/sndr.mdx +144 -0
  233. package/site/content/docs/transports/sparkpost.mdx +41 -0
  234. package/site/content/docs/transports/taqnyat-mail.mdx +41 -0
  235. package/site/content/docs/transports/taqnyat-sms.mdx +41 -0
  236. package/site/content/docs/transports/taqnyat-whatsapp.mdx +40 -0
  237. package/site/content/docs/transports/twilio-sms.mdx +128 -0
  238. package/site/content/docs/transports/webpush.mdx +43 -0
  239. package/site/content/docs/transports/whatsapp-cloud.mdx +42 -0
  240. package/dist/chunk-5scdgffb.js +0 -5
  241. package/dist/chunk-8phpsns1.js +0 -13
  242. package/dist/chunk-m07smapm.js +0 -3
  243. package/dist/chunk-n5dan5bz.js +0 -4
  244. package/dist/chunk-qh90yr6d.js +0 -4
  245. package/dist/chunk-vhxzhx8b.js +0 -4
  246. package/dist/chunk-wbvhaqcp.js +0 -4
  247. package/dist/chunk-wsymfbkn.js +0 -4
  248. package/dist/chunk-yr56b0ts.js +0 -4
  249. package/dist/chunk-yr56b0ts.js.map +0 -11
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: WhatsApp options
3
+ description: Template and session text shapes accepted by `WhatsAppSender.send`.
4
+ icon: MessagesSquare
5
+ source: "src/core/whatsapp-types.ts"
6
+ ---
7
+
8
+ | Shape | Required fields |
9
+ | --- | --- |
10
+ | Template | `to`, `template.name`, `template.language` |
11
+ | Text | `to`, `text` |
12
+
13
+ Both shapes accept optional `messageId`. Template components can include `header`, `body`, or `button` parameters.
14
+
15
+ <Cards><Card title="WhatsApp channel" href="/docs/channels/whatsapp" /></Cards>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Brevo
3
+ description: Send email through the Brevo HTTP API.
4
+ icon: Truck
5
+ source: "src/transports/brevo.ts"
6
+ ---
7
+
8
+ Send email through the Brevo HTTP API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiKey` | `string` | required |
17
+
18
+ <Steps>
19
+ <Step title="Configure the transport">
20
+
21
+ ```ts
22
+ import { createMailer } from "sently/mailer";
23
+ import { BrevoTransport } from "sently/transports/brevo";
24
+
25
+ const sender = createMailer({ transport: new BrevoTransport({ apiKey: process.env.BREVO_API_KEY! }) });
26
+ ```
27
+
28
+ </Step>
29
+ <Step title="Send with the channel API">
30
+
31
+ ```ts
32
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
33
+ ```
34
+
35
+ </Step>
36
+ </Steps>
37
+
38
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
39
+
40
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Cloudflare Email
3
+ description: Use a Cloudflare Workers send_email binding.
4
+ icon: Truck
5
+ source: "src/transports/cloudflare-email.ts"
6
+ ---
7
+
8
+ Use a Cloudflare Workers send_email binding.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `sendEmail` | `CloudflareSendEmailFn` | required |
17
+
18
+ <Steps>
19
+ <Step title="Configure the transport">
20
+
21
+ ```ts
22
+ import { createMailer } from "sently/mailer";
23
+ import { CloudflareEmailTransport } from "sently/transports/cloudflare-email";
24
+
25
+ const sender = createMailer({ transport: new CloudflareEmailTransport({ sendEmail: env.SEND_EMAIL }) });
26
+ ```
27
+
28
+ </Step>
29
+ <Step title="Send with the channel API">
30
+
31
+ ```ts
32
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
33
+ ```
34
+
35
+ </Step>
36
+ </Steps>
37
+
38
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
39
+
40
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: Transports
3
+ description: Choose a provider transport for a channel sender.
4
+ icon: Truck
5
+ source: "package.json"
6
+ ---
7
+
8
+ Transports connect a sently channel sender to a delivery provider.
9
+ Pick the transport that matches the channel you are sending on.
10
+
11
+ <Callout title="The one rule">Keep application delivery calls on a sently channel sender and replace only its transport when you change providers.</Callout>
12
+
13
+ <Steps>
14
+ <Step title="Import a sender and its transport">
15
+
16
+ ```ts
17
+ import { createMailer } from "sently/mailer";
18
+ import { ResendTransport } from "sently/transports/resend";
19
+
20
+ const mailer = await createMailer({
21
+ transport: new ResendTransport({
22
+ apiKey: process.env.RESEND_API_KEY!,
23
+ }),
24
+ });
25
+ ```
26
+
27
+ </Step>
28
+ <Step title="Send through the channel">
29
+
30
+ ```ts
31
+ await mailer.send({
32
+ from: "hello@example.com",
33
+ to: "person@example.com",
34
+ subject: "Welcome",
35
+ text: "Thanks for joining.",
36
+ });
37
+ ```
38
+
39
+ </Step>
40
+ </Steps>
41
+
42
+ ## Exported transports
43
+
44
+ Every import below is an exported package subpath.
45
+
46
+ | Transport | Channel | Import |
47
+ | --- | --- | --- |
48
+ | [SMTP](./smtp) | Email | `sently/transports/smtp` |
49
+ | [Resend](./resend) | Email | `sently/transports/resend` |
50
+ | [SendGrid](./sendgrid) | Email | `sently/transports/sendgrid` |
51
+ | [Postmark](./postmark) | Email | `sently/transports/postmark` |
52
+ | [Mailgun](./mailgun) | Email | `sently/transports/mailgun` |
53
+ | [SES](./ses) | Email | `sently/transports/ses` |
54
+ | [Brevo](./brevo) | Email | `sently/transports/brevo` |
55
+ | [MailerSend](./mailersend) | Email | `sently/transports/mailersend` |
56
+ | [Plunk](./plunk) | Email | `sently/transports/plunk` |
57
+ | [SparkPost](./sparkpost) | Email | `sently/transports/sparkpost` |
58
+ | [Mailtrap](./mailtrap) | Email | `sently/transports/mailtrap` |
59
+ | [Loops](./loops) | Email | `sently/transports/loops` |
60
+ | [Cloudflare Email](./cloudflare-email) | Email | `sently/transports/cloudflare-email` |
61
+ | [SNDR](./sndr) | Email | `sently/transports/sndr` |
62
+ | [Taqnyat Mail](./taqnyat-mail) | Email | `sently/transports/taqnyat-mail` |
63
+ | [Twilio SMS](./twilio-sms) | SMS | `sently/transports/twilio-sms` |
64
+ | [Taqnyat SMS](./taqnyat-sms) | SMS | `sently/transports/taqnyat-sms` |
65
+ | [Msegat](./msegat) | SMS | `sently/transports/msegat` |
66
+ | [WhatsApp Cloud](./whatsapp-cloud) | WhatsApp | `sently/transports/whatsapp-cloud` |
67
+ | [Taqnyat WhatsApp](./taqnyat-whatsapp) | WhatsApp | `sently/transports/taqnyat-whatsapp` |
68
+ | [Web Push](./webpush) | Push | `sently/transports/webpush` |
69
+
70
+ For retry, fallback, preview, and idempotency wrappers, see [Decorators](../decorators).
71
+
72
+ ## Channel contracts
73
+
74
+ | Channel | Sender | Transport contract |
75
+ | --- | --- | --- |
76
+ | Email | `createMailer` / `createSMTPMailer` | `Transport` |
77
+ | SMS | `createSmsSender` | `SmsTransport` |
78
+ | WhatsApp | `createWhatsAppSender` | `WhatsAppTransport` |
79
+ | Push | `createPushSender` | `PushTransport` |
80
+
81
+ ## Troubleshooting
82
+
83
+ <Accordions>
84
+ <Accordion title="Can I use an email transport for SMS or WhatsApp?">
85
+ No. A transport implements one channel contract. Choose a transport listed for the channel sender you use.
86
+ </Accordion>
87
+ <Accordion title="How do I add retries or fallback?">
88
+ Wrap an email transport with a [decorator](../decorators), then pass the wrapper to `createMailer`.
89
+ </Accordion>
90
+ </Accordions>
91
+
92
+ ## Learn more
93
+
94
+ - [Decorators](../decorators)
95
+ - [Email channel](../channels/email)
96
+ - [SMS channel](../channels/sms)
97
+ - [Transport contracts](../reference/transport-contracts)
98
+
99
+ ## Next
100
+
101
+ <Cards>
102
+ <Card title="Decorators" href="/docs/decorators" />
103
+ <Card title="Email channel" href="/docs/channels/email" />
104
+ <Card title="SMS channel" href="/docs/channels/sms" />
105
+ </Cards>
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Loops
3
+ description: Send template-based transactional email through Loops.
4
+ icon: Truck
5
+ source: "src/transports/loops.ts"
6
+ ---
7
+
8
+ Send template-based transactional email through Loops.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiKey` | `string` | required |
17
+ | `defaultTransactionalId` | `string` | optional |
18
+
19
+ <Steps>
20
+ <Step title="Configure the transport">
21
+
22
+ ```ts
23
+ import { createMailer } from "sently/mailer";
24
+ import { LoopsTransport } from "sently/transports/loops";
25
+
26
+ const sender = createMailer({ transport: new LoopsTransport({ apiKey: process.env.LOOPS_API_KEY!, defaultTransactionalId: "cl..." }) });
27
+ ```
28
+
29
+ </Step>
30
+ <Step title="Send with the channel API">
31
+
32
+ ```ts
33
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
34
+ ```
35
+
36
+ </Step>
37
+ </Steps>
38
+
39
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
40
+
41
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: MailerSend
3
+ description: Send email through the MailerSend HTTP API.
4
+ icon: Truck
5
+ source: "src/transports/mailersend.ts"
6
+ ---
7
+
8
+ Send email through the MailerSend HTTP API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiToken` | `string` | required |
17
+
18
+ <Steps>
19
+ <Step title="Configure the transport">
20
+
21
+ ```ts
22
+ import { createMailer } from "sently/mailer";
23
+ import { MailerSendTransport } from "sently/transports/mailersend";
24
+
25
+ const sender = createMailer({ transport: new MailerSendTransport({ apiToken: process.env.MAILERSEND_API_TOKEN! }) });
26
+ ```
27
+
28
+ </Step>
29
+ <Step title="Send with the channel API">
30
+
31
+ ```ts
32
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
33
+ ```
34
+
35
+ </Step>
36
+ </Steps>
37
+
38
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
39
+
40
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Mailgun
3
+ description: Send email through the Mailgun Messages API.
4
+ icon: Truck
5
+ source: "src/transports/mailgun.ts"
6
+ ---
7
+
8
+ Send email through the Mailgun Messages API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiKey` | `string` | required |
17
+ | `domain` | `string` | required |
18
+ | `region` | `"us" | "eu"` | "us" |
19
+
20
+ <Steps>
21
+ <Step title="Configure the transport">
22
+
23
+ ```ts
24
+ import { createMailer } from "sently/mailer";
25
+ import { MailgunTransport } from "sently/transports/mailgun";
26
+
27
+ const sender = createMailer({ transport: new MailgunTransport({ apiKey: process.env.MAILGUN_API_KEY!, domain: "mg.example.com" }) });
28
+ ```
29
+
30
+ </Step>
31
+ <Step title="Send with the channel API">
32
+
33
+ ```ts
34
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
35
+ ```
36
+
37
+ </Step>
38
+ </Steps>
39
+
40
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
41
+
42
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Mailtrap
3
+ description: Send email through Mailtrap delivery or sandbox mode.
4
+ icon: Truck
5
+ source: "src/transports/mailtrap.ts"
6
+ ---
7
+
8
+ Send email through Mailtrap delivery or sandbox mode.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiToken` | `string` | required |
17
+ | `sandbox` | `boolean` | false |
18
+ | `inboxId` | `string` | required when sandbox is true |
19
+
20
+ <Steps>
21
+ <Step title="Configure the transport">
22
+
23
+ ```ts
24
+ import { createMailer } from "sently/mailer";
25
+ import { MailtrapTransport } from "sently/transports/mailtrap";
26
+
27
+ const sender = createMailer({ transport: new MailtrapTransport({ apiToken: process.env.MAILTRAP_API_TOKEN! }) });
28
+ ```
29
+
30
+ </Step>
31
+ <Step title="Send with the channel API">
32
+
33
+ ```ts
34
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
35
+ ```
36
+
37
+ </Step>
38
+ </Steps>
39
+
40
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
41
+
42
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,32 @@
1
+ {
2
+ "title": "Transports",
3
+ "icon": "Truck",
4
+ "pages": [
5
+ "index",
6
+ "---Email---",
7
+ "smtp",
8
+ "resend",
9
+ "sendgrid",
10
+ "postmark",
11
+ "mailgun",
12
+ "ses",
13
+ "brevo",
14
+ "mailersend",
15
+ "plunk",
16
+ "sparkpost",
17
+ "mailtrap",
18
+ "loops",
19
+ "cloudflare-email",
20
+ "sndr",
21
+ "taqnyat-mail",
22
+ "---SMS---",
23
+ "twilio-sms",
24
+ "taqnyat-sms",
25
+ "msegat",
26
+ "---WhatsApp---",
27
+ "whatsapp-cloud",
28
+ "taqnyat-whatsapp",
29
+ "---Push---",
30
+ "webpush"
31
+ ]
32
+ }
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Msegat
3
+ description: Send SMS through Msegat and use its concrete OTP helpers.
4
+ icon: Truck
5
+ source: "src/transports/msegat.ts"
6
+ ---
7
+
8
+ Send SMS through Msegat and use its concrete OTP helpers.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `userName` | `string` | required |
17
+ | `apiKey` | `string` | required |
18
+ | `sender` | `string` | required |
19
+
20
+ <Steps>
21
+ <Step title="Configure the transport">
22
+
23
+ ```ts
24
+ import { createSmsSender } from "sently/sms";
25
+ import { MsegatTransport } from "sently/transports/msegat";
26
+
27
+ const sender = createSmsSender({ transport: new MsegatTransport({ userName: "...", apiKey: "...", sender: "MyBrand" }) });
28
+ ```
29
+
30
+ </Step>
31
+ <Step title="Send with the channel API">
32
+
33
+ ```ts
34
+ await sender.send({ to: "+15551234567", body: "Hello" });
35
+ ```
36
+
37
+ </Step>
38
+ </Steps>
39
+
40
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
41
+
42
+ <Cards><Card title="Sms channel" href="/docs/channels/sms" /></Cards>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Plunk
3
+ description: Send email through the Plunk HTTP API.
4
+ icon: Truck
5
+ source: "src/transports/plunk.ts"
6
+ ---
7
+
8
+ Send email through the Plunk HTTP API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiKey` | `string` | required |
17
+
18
+ <Steps>
19
+ <Step title="Configure the transport">
20
+
21
+ ```ts
22
+ import { createMailer } from "sently/mailer";
23
+ import { PlunkTransport } from "sently/transports/plunk";
24
+
25
+ const sender = createMailer({ transport: new PlunkTransport({ apiKey: process.env.PLUNK_API_KEY! }) });
26
+ ```
27
+
28
+ </Step>
29
+ <Step title="Send with the channel API">
30
+
31
+ ```ts
32
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
33
+ ```
34
+
35
+ </Step>
36
+ </Steps>
37
+
38
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
39
+
40
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Postmark
3
+ description: Send email through the Postmark API.
4
+ icon: Truck
5
+ source: "src/transports/postmark.ts"
6
+ ---
7
+
8
+ Send email through the Postmark API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `serverToken` | `string` | required |
17
+
18
+ <Steps>
19
+ <Step title="Configure the transport">
20
+
21
+ ```ts
22
+ import { createMailer } from "sently/mailer";
23
+ import { PostmarkTransport } from "sently/transports/postmark";
24
+
25
+ const sender = createMailer({ transport: new PostmarkTransport({ serverToken: process.env.POSTMARK_TOKEN! }) });
26
+ ```
27
+
28
+ </Step>
29
+ <Step title="Send with the channel API">
30
+
31
+ ```ts
32
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
33
+ ```
34
+
35
+ </Step>
36
+ </Steps>
37
+
38
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
39
+
40
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,43 @@
1
+ ---
2
+ title: Resend
3
+ description: Send email through the Resend HTTP API.
4
+ icon: Truck
5
+ source: "src/transports/resend.ts"
6
+ ---
7
+
8
+ Send email through the Resend HTTP API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiKey` | `string` | required |
17
+ | `baseUrl` | `string` | https://api.resend.com |
18
+ | `rateDelta` | `number` | 2 |
19
+ | `rateLimit` | `number` | 1000 |
20
+
21
+ <Steps>
22
+ <Step title="Configure the transport">
23
+
24
+ ```ts
25
+ import { createMailer } from "sently/mailer";
26
+ import { ResendTransport } from "sently/transports/resend";
27
+
28
+ const sender = createMailer({ transport: new ResendTransport({ apiKey: process.env.RESEND_API_KEY! }) });
29
+ ```
30
+
31
+ </Step>
32
+ <Step title="Send with the channel API">
33
+
34
+ ```ts
35
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
36
+ ```
37
+
38
+ </Step>
39
+ </Steps>
40
+
41
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
42
+
43
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: SendGrid
3
+ description: Send email through the SendGrid v3 API.
4
+ icon: Truck
5
+ source: "src/transports/sendgrid.ts"
6
+ ---
7
+
8
+ Send email through the SendGrid v3 API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `apiKey` | `string` | required |
17
+
18
+ <Steps>
19
+ <Step title="Configure the transport">
20
+
21
+ ```ts
22
+ import { createMailer } from "sently/mailer";
23
+ import { SendGridTransport } from "sently/transports/sendgrid";
24
+
25
+ const sender = createMailer({ transport: new SendGridTransport({ apiKey: process.env.SENDGRID_API_KEY! }) });
26
+ ```
27
+
28
+ </Step>
29
+ <Step title="Send with the channel API">
30
+
31
+ ```ts
32
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
33
+ ```
34
+
35
+ </Step>
36
+ </Steps>
37
+
38
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
39
+
40
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Amazon SES
3
+ description: Send email through the AWS SES v2 API.
4
+ icon: Truck
5
+ source: "src/transports/ses.ts"
6
+ ---
7
+
8
+ Send email through the AWS SES v2 API.
9
+
10
+ <Callout title="The one rule">Create this transport under the matching sently channel sender.</Callout>
11
+
12
+ ## Configuration
13
+
14
+ | Option | Type | Default or requirement |
15
+ | --- | --- | --- |
16
+ | `accessKeyId` | `string` | required |
17
+ | `secretAccessKey` | `string` | required |
18
+ | `region` | `string` | us-east-1 |
19
+ | `sessionToken` | `string` | optional |
20
+ | `dkim` | `DKIMConfig` | optional |
21
+
22
+ <Steps>
23
+ <Step title="Configure the transport">
24
+
25
+ ```ts
26
+ import { createMailer } from "sently/mailer";
27
+ import { SESTransport } from "sently/transports/ses";
28
+
29
+ const sender = createMailer({ transport: new SESTransport({ accessKeyId: "...", secretAccessKey: "..." }) });
30
+ ```
31
+
32
+ </Step>
33
+ <Step title="Send with the channel API">
34
+
35
+ ```ts
36
+ await sender.send({ from: "hello@example.com", to: "person@example.com", subject: "Hello", text: "Hi" });
37
+ ```
38
+
39
+ </Step>
40
+ </Steps>
41
+
42
+ <Accordions><Accordion title="Should I call the provider SDK?">No. Use the sently sender; provider-specific extras stay on the transport instance.</Accordion></Accordions>
43
+
44
+ <Cards><Card title="Email channel" href="/docs/channels/email" /></Cards>