@visulima/email 3.0.28 → 4.1.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 (117) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +93 -37
  3. package/dist/deliverability/dmarc-report.js +1 -1
  4. package/dist/index.d.ts +6 -0
  5. package/dist/index.js +1 -1
  6. package/dist/middleware/index.js +1 -1
  7. package/dist/packem_chunks/index.js +5 -5
  8. package/dist/packem_shared/EmailError-SXEFQEyA.js +1 -0
  9. package/dist/packem_shared/{Mail-DmYNQ0KK.js → Mail-0cxS6jre.js} +1 -1
  10. package/dist/packem_shared/{RequiredOptionError-ctDEEB1s.js → RequiredOptionError-C2wWqmiE.js} +1 -1
  11. package/dist/packem_shared/{ahaSendProvider-D95-pwFh.js → ahaSendProvider-Ci_a_O8d.js} +1 -1
  12. package/dist/packem_shared/{attachment-processor-BJFDS343.js → attachment-processor-AB1m-n9T.js} +1 -1
  13. package/dist/packem_shared/{autoSendProvider-yxUx3sEj.js → autoSendProvider-DG3pNJML.js} +1 -1
  14. package/dist/packem_shared/{awsSesProvider-DnZo9X_g.js → awsSesProvider-C4b5kuL4.js} +1 -1
  15. package/dist/packem_shared/{azureProvider-D6Z4c1yT.js → azureProvider-CEnz3uy_.js} +1 -1
  16. package/dist/packem_shared/{brevoProvider-D1yTSs0l.js → brevoProvider-BsbInXjw.js} +1 -1
  17. package/dist/packem_shared/{build-mime-message-BCFKPqaW.js → build-mime-message-D45WdgfP.js} +1 -1
  18. package/dist/packem_shared/{circuitBreakerMiddleware-DcBN7K6H.js → circuitBreakerMiddleware-Cm0m75qi.js} +1 -1
  19. package/dist/packem_shared/{cloudflareEmailProvider-DZbs35NL.js → cloudflareEmailProvider-CnpH5R5p.js} +1 -1
  20. package/dist/packem_shared/{createTestEmail-gr512snl.js → createTestEmail-DWimjf0F.js} +1 -1
  21. package/dist/packem_shared/createWorker-ChrQvLUF.js +1 -0
  22. package/dist/packem_shared/extractLinks-BwE1SjNF.js +1 -0
  23. package/dist/packem_shared/{failoverProvider-IED1M0M5.js → failoverProvider-DsBqMOfK.js} +1 -1
  24. package/dist/packem_shared/fileProvider-BnDeaSqA.js +1 -0
  25. package/dist/packem_shared/{httpProvider-CpdWJoRq.js → httpProvider-BuA00407.js} +1 -1
  26. package/dist/packem_shared/{infobipProvider-DTqFu5pM.js → infobipProvider-DVUg9jKC.js} +1 -1
  27. package/dist/packem_shared/{isValidSigningCertUrl-CK1t2a7x.js → isValidSigningCertUrl-gnYr3oyD.js} +1 -1
  28. package/dist/packem_shared/{loopsProvider-PiE2HxoW.js → loopsProvider-BJUNQ2rR.js} +1 -1
  29. package/dist/packem_shared/{mailCrabProvider-BSapw_mS.js → mailCrabProvider-CFKRofS5.js} +1 -1
  30. package/dist/packem_shared/{mailPaceProvider-BugIutTw.js → mailPaceProvider-DBQd6NYt.js} +1 -1
  31. package/dist/packem_shared/{mailchannelsProvider-Dn24mI8D.js → mailchannelsProvider-CPVW3wlH.js} +1 -1
  32. package/dist/packem_shared/{mailerSendProvider-B6X4Lhsf.js → mailerSendProvider-B2H6BtoV.js} +1 -1
  33. package/dist/packem_shared/{mailgunProvider-4sMtcQcW.js → mailgunProvider-JRVH70PB.js} +1 -1
  34. package/dist/packem_shared/{mailjetProvider-DvrHwipw.js → mailjetProvider-BzBovF5M.js} +1 -1
  35. package/dist/packem_shared/{mailomatProvider-CrkNQGfL.js → mailomatProvider-x6IHKuWU.js} +1 -1
  36. package/dist/packem_shared/{mailtrapProvider-DTgvCUrs.js → mailtrapProvider-CJTJoDcV.js} +1 -1
  37. package/dist/packem_shared/make-request-mszP240P.js +1 -0
  38. package/dist/packem_shared/{mandrillProvider-BaK0GEj7.js → mandrillProvider-BcztgKkr.js} +1 -1
  39. package/dist/packem_shared/{mockProvider-CTxxbT0d.js → mockProvider-DVtl5Jjy.js} +1 -1
  40. package/dist/packem_shared/{netcoreProvider-BZJ0noQ2.js → netcoreProvider-YWEpa-wi.js} +1 -1
  41. package/dist/packem_shared/{nodemailerProvider-DqJh8ghN.js → nodemailerProvider-WNNtLE2s.js} +1 -1
  42. package/dist/packem_shared/{opentelemetryProvider-s0gvh05u.js → opentelemetryProvider-ddbILMeS.js} +1 -1
  43. package/dist/packem_shared/{outlook365Provider-DQUSFy2d.js → outlook365Provider-D5eETMZq.js} +1 -1
  44. package/dist/packem_shared/{plunkProvider-WMi1yPya.js → plunkProvider-TrBBoX7_.js} +1 -1
  45. package/dist/packem_shared/{postalProvider-DpBFGpoX.js → postalProvider-CU53hX0R.js} +1 -1
  46. package/dist/packem_shared/{postmarkProvider-ClUaHPvw.js → postmarkProvider-DEYQp8Gv.js} +1 -1
  47. package/dist/packem_shared/{provider-base-BEz00m9R.js → provider-base-G22b4a87.js} +1 -1
  48. package/dist/packem_shared/{resendProvider-DtaB7sk0.js → resendProvider-DC7Op5Gr.js} +1 -1
  49. package/dist/packem_shared/{retry-aghj7y8m.js → retry-ByPJFAtq.js} +1 -1
  50. package/dist/packem_shared/{roundRobinProvider-Dr1DdT2L.js → roundRobinProvider-CfuNY7We.js} +1 -1
  51. package/dist/packem_shared/{scalewayProvider-BhbDUEah.js → scalewayProvider-x6S2ZSPd.js} +1 -1
  52. package/dist/packem_shared/{sendGridProvider-DBZHhxd6.js → sendGridProvider-8Po3P-ia.js} +1 -1
  53. package/dist/packem_shared/{smtpProvider-CjcOEiAh.js → smtpProvider-BPamDNuv.js} +1 -1
  54. package/dist/packem_shared/{sparkpostProvider-B19lU9D5.js → sparkpostProvider-BVu1KeNz.js} +1 -1
  55. package/dist/packem_shared/{sweegoProvider-H8KWGDff.js → sweegoProvider-DHISjS9s.js} +1 -1
  56. package/dist/packem_shared/{verifySendGridWebhook-csuRasH3.js → verifySendGridWebhook-0_3qKQA1.js} +1 -1
  57. package/dist/packem_shared/{withSuppression-B0eZ2xNQ.js → withSuppression-COCHL9Zx.js} +1 -1
  58. package/dist/packem_shared/{zeptomailProvider-L7nkdn0L.js → zeptomailProvider-IhCIl_2a.js} +1 -1
  59. package/dist/providers/ahasend/index.js +1 -1
  60. package/dist/providers/autosend/index.js +1 -1
  61. package/dist/providers/aws-ses/index.js +1 -1
  62. package/dist/providers/azure/index.js +1 -1
  63. package/dist/providers/brevo/index.js +1 -1
  64. package/dist/providers/cloudflare-email/index.js +1 -1
  65. package/dist/providers/failover/index.js +1 -1
  66. package/dist/providers/file/index.d.ts +23 -0
  67. package/dist/providers/file/index.js +1 -0
  68. package/dist/providers/http/index.js +1 -1
  69. package/dist/providers/infobip/index.js +1 -1
  70. package/dist/providers/loops/index.js +1 -1
  71. package/dist/providers/mailchannels/index.js +1 -1
  72. package/dist/providers/mailcrab/index.js +1 -1
  73. package/dist/providers/mailersend/index.js +1 -1
  74. package/dist/providers/mailgun/index.js +1 -1
  75. package/dist/providers/mailjet/index.js +1 -1
  76. package/dist/providers/mailomat/index.js +1 -1
  77. package/dist/providers/mailpace/index.js +1 -1
  78. package/dist/providers/mailtrap/index.js +1 -1
  79. package/dist/providers/mandrill/index.js +1 -1
  80. package/dist/providers/mock/index.js +1 -1
  81. package/dist/providers/netcore/index.js +1 -1
  82. package/dist/providers/nodemailer/index.js +1 -1
  83. package/dist/providers/opentelemetry/index.js +1 -1
  84. package/dist/providers/outlook365/index.js +1 -1
  85. package/dist/providers/plunk/index.js +1 -1
  86. package/dist/providers/postal/index.js +1 -1
  87. package/dist/providers/postmark/index.js +1 -1
  88. package/dist/providers/resend/index.js +1 -1
  89. package/dist/providers/roundrobin/index.js +1 -1
  90. package/dist/providers/scaleway/index.js +1 -1
  91. package/dist/providers/sendgrid/index.js +1 -1
  92. package/dist/providers/smtp/index.js +1 -1
  93. package/dist/providers/sparkpost/index.js +1 -1
  94. package/dist/providers/sweego/index.js +1 -1
  95. package/dist/providers/zeptomail/index.js +1 -1
  96. package/dist/queue/index.d.ts +2 -1
  97. package/dist/queue/index.js +1 -1
  98. package/dist/render/css-inline.js +1 -1
  99. package/dist/template-engines/handlebars.js +1 -1
  100. package/dist/template-engines/html-to-text.js +1 -1
  101. package/dist/template-engines/i18n.js +1 -1
  102. package/dist/template-engines/jsx-email.js +1 -1
  103. package/dist/template-engines/liquid.js +1 -1
  104. package/dist/template-engines/locale-files.d.ts +66 -0
  105. package/dist/template-engines/locale-files.js +1 -0
  106. package/dist/template-engines/mjml.js +1 -1
  107. package/dist/template-engines/react-email.js +1 -1
  108. package/dist/template-engines/vue-email.js +1 -1
  109. package/dist/test/index.d.ts +19 -2
  110. package/dist/test/index.js +1 -1
  111. package/dist/utils/format-email-address.js +1 -1
  112. package/dist/utils/result.js +1 -1
  113. package/dist/webhooks/index.js +1 -1
  114. package/package.json +10 -2
  115. package/dist/packem_shared/EmailError-BIaHK1Uw.js +0 -1
  116. package/dist/packem_shared/createWorker-ChuTgETP.js +0 -1
  117. package/dist/packem_shared/make-request-Cyz5_yu8.js +0 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,118 @@
1
+ ## @visulima/email [4.1.0](https://github.com/visulima/visulima/compare/@visulima/email@4.0.0...@visulima/email@4.1.0) (2026-10-23)
2
+
3
+ ### Features
4
+
5
+ * **email:** add extractLinks test helper ([#984](https://github.com/visulima/visulima/issues/984)) ([183c91f](https://github.com/visulima/visulima/commit/183c91f1e192b364773515da2ce8dbe8deafaa6d))
6
+ * **email:** add file provider for .eml output ([#983](https://github.com/visulima/visulima/issues/983)) ([9768708](https://github.com/visulima/visulima/commit/97687081ff5ac190b0d63a4f0f7442cc64ab0f55))
7
+ * **email:** dead-letter permanent failures early ([#985](https://github.com/visulima/visulima/issues/985)) ([b42d51d](https://github.com/visulima/visulima/commit/b42d51d61e4ab1e4277e4d85e28e877912920651))
8
+ * **email:** load locale-specific template files ([#986](https://github.com/visulima/visulima/issues/986)) ([cfdc461](https://github.com/visulima/visulima/commit/cfdc461091566a46168122096dade10a37477c59))
9
+
10
+ ## @visulima/email [4.0.0](https://github.com/visulima/visulima/compare/@visulima/email@3.0.28...@visulima/email@4.0.0) (2026-10-15)
11
+
12
+ ### ⚠ BREAKING CHANGES
13
+
14
+ * Deno is no longer a supported runtime or package manager.
15
+ vis targets node/bun runtimes and aube/npm/pnpm/yarn package managers; the
16
+ deno-lint/deno-fmt adapters and deno inference targets are removed.
17
+
18
+ * fix: resolve eslint errors after deno removal
19
+
20
+ - vis: use a block body for applyIgnoreScripts (arrow-body-style)
21
+ - is-ansi-color-supported: drop stale eslint-disable directives and
22
+ replace the raw-release if/else with a ternary (unicorn/prefer-ternary)
23
+
24
+ * docs(cron-parser): remove remaining deno runtime mentions
25
+
26
+ These doc/config files arrived with main's dialect-gating commit after this
27
+ branch's base, so they still listed Deno as a supported runtime.
28
+
29
+ * feat!: remove deno runtime and tooling support
30
+
31
+ Deno is being wound down: Cloudflare is acquiring the Deno team, the runtime
32
+ gets one more year of monthly maintenance before development ends, and Deno
33
+ Deploy shuts down. Drop Deno as a supported runtime, package manager, and
34
+ lint/fmt/inference target across the monorepo.
35
+
36
+ - vis: remove the deno runtime path, deno-lint/deno-fmt adapters, the
37
+ deno.json inference detector, Deno PM handling (TypeScript + Rust native
38
+ resolver), and the devcontainer deno mount; regenerate the JSON schemas.
39
+ - libraries: drop Deno runtime detection from cerebro, ono,
40
+ is-ansi-color-supported, and task-runner command parsing; remove Deno
41
+ wording from package docs and READMEs.
42
+ - delete the examples/deno directories (ono, pail, storage) and Deno docs.
43
+ - keep JSR publishing (registry usable from Node), license/attribution
44
+ comments, the secret-scanner Deno-token rule, and the historical RFCs.
45
+ * Deno is no longer a supported runtime or package manager.
46
+ vis targets node/bun runtimes and aube/npm/pnpm/yarn package managers; the
47
+ deno-lint/deno-fmt adapters and deno inference targets are removed.
48
+
49
+ * fix: resolve eslint errors after deno removal
50
+
51
+ - vis: use a block body for applyIgnoreScripts (arrow-body-style)
52
+ - is-ansi-color-supported: drop stale eslint-disable directives and
53
+ replace the raw-release if/else with a ternary (unicorn/prefer-ternary)
54
+
55
+ * chore(vis): tidy deno-removal leftovers from review
56
+
57
+ * fix(vis): drop unused logger from x handler, restore bun typing
58
+
59
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
60
+
61
+ * docs: add migration notes for removed deno exports
62
+
63
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
64
+
65
+ * feat(vis): warn on stale adapter ids and deno-only projects
66
+
67
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
68
+
69
+ * refactor(vis): derive runtime ids and reuse bun detection
70
+
71
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
72
+
73
+ * refactor(vis): drop jsr deno option and deno auth reference
74
+
75
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
76
+
77
+ * fix(vis): restore runtime id schema description
78
+
79
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
80
+
81
+ * refactor(vis): remove jsr publishing support
82
+
83
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
84
+
85
+ * feat(bytes): port @std/bytes helpers back in
86
+
87
+ Carries the Uint8Array helpers from @std/bytes@1.0.6 (MIT, Copyright the Deno authors)
88
+ into src/std-bytes.ts and re-exports them from the package entry. Keeps the public API that
89
+ the Deno-removal commit dropped, without the jsr: devDependency. Docs and AGENTS notes are
90
+ restored to describe the ported functions.
91
+
92
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
93
+
94
+ * docs(bytes): attribute ported @std/bytes source
95
+
96
+ The license file still listed @jsr/std__bytes as a bundled dependency.
97
+ Replace it with the MIT notice for the ported src/std-bytes.ts, placed outside
98
+ the generated dependency blocks.
99
+
100
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
101
+
102
+ * fix(cron-parser): keep reviewed docs and 1.1.0 version
103
+
104
+ The rebase onto the remote branch dropped the reviewed dialect sentence in the README and
105
+ the installation table row, and the release commit's 1.1.0 version bump.
106
+
107
+ ### Features
108
+
109
+ * remove deno runtime and tooling support ([#973](https://github.com/visulima/visulima/issues/973)) ([26fada1](https://github.com/visulima/visulima/commit/26fada1ac04731cba9db8f74fe20849c0a15db74))
110
+
111
+
112
+ ### Dependencies
113
+
114
+ * **@visulima/fs:** upgraded to 7.0.0
115
+
1
116
  ## @visulima/email [3.0.28](https://github.com/visulima/visulima/compare/@visulima/email@3.0.27...@visulima/email@3.0.28) (2026-10-08)
2
117
 
3
118
  ### Bug Fixes
package/README.md CHANGED
@@ -1122,6 +1122,27 @@ mock.reset();
1122
1122
  - `waitForMessage(predicate, timeout)` - Wait for matching message
1123
1123
  - `reset()` - Reset to initial state
1124
1124
 
1125
+ ### Extracting Links in Tests
1126
+
1127
+ `extractLinks` from `@visulima/email/test` returns the http(s) URLs in a message, so a test can follow a verification or reset link. It returns `href` targets from the HTML, then bare URLs from the visible HTML text and from the plain text, without duplicates. Only `a` and `area` elements contribute `href` targets, so image sources, stylesheet and base links, CSS URLs, and the contents of `script`, `style` and comments are ignored. Entities are decoded in HTML, including the hexadecimal entities that template engines use to escape `=`.
1128
+
1129
+ Pass markup as `{ html }`. A bare string is always treated as plain text.
1130
+
1131
+ ```typescript
1132
+ import { createTestEmail, extractLinks } from "@visulima/email/test";
1133
+
1134
+ const email = createTestEmail();
1135
+
1136
+ await email.mail.send({
1137
+ from: { email: "app@example.com" },
1138
+ html: '<a href="https://app.example.com/verify?token=abc&amp;lang=en">Verify</a>',
1139
+ subject: "Verify",
1140
+ to: { email: "user@example.com" },
1141
+ });
1142
+
1143
+ const [verifyUrl] = extractLinks(email.sent()[0]!.options);
1144
+ ```
1145
+
1125
1146
  ### MailCrab Provider (for Development)
1126
1147
 
1127
1148
  MailCrab is a local SMTP server for testing emails during development. This provider is a convenience wrapper around the SMTP provider with MailCrab defaults.
@@ -1148,6 +1169,23 @@ const result = await mail.send(message);
1148
1169
 
1149
1170
  **Note:** Make sure MailCrab is running locally before using this provider. MailCrab can be installed via Docker or as a standalone application.
1150
1171
 
1172
+ ### File Provider (for Development and Testing)
1173
+
1174
+ The file provider writes each message to an `.eml` file in a directory instead of sending it. Use it to inspect the exact MIME output during development or in tests.
1175
+
1176
+ ```typescript
1177
+ import { createMail, MailMessage } from "@visulima/email";
1178
+ import { fileProvider } from "@visulima/email/providers/file";
1179
+
1180
+ const mail = createMail(fileProvider({ directory: "./tmp/emails" }));
1181
+
1182
+ const result = await mail.send(new MailMessage().to("user@example.com").from("sender@example.com").subject("Test Email").html("<h1>Test</h1>"));
1183
+
1184
+ // result.data.response.path is the written file
1185
+ ```
1186
+
1187
+ Files are named `<epoch-ms>-<message-id>.eml` and are never overwritten. A Message-ID that contains path separators is sanitised before it becomes part of the filename. Bcc recipients are written into the file, since nothing is delivered.
1188
+
1151
1189
  ## Supported Providers
1152
1190
 
1153
1191
  - **AWS SES** - Amazon Simple Email Service
@@ -1155,6 +1193,7 @@ const result = await mail.send(message);
1155
1193
  - **Failover** - Automatic failover between multiple providers
1156
1194
  - **HTTP** - Generic HTTP API provider
1157
1195
  - **MailCrab** - Local development email testing (SMTP wrapper)
1196
+ - **File** - Writes messages to `.eml` files instead of sending (Node.js only)
1158
1197
  - **Mailgun** - Developer-friendly email API service
1159
1198
  - **Mailjet** - Email marketing and transactional email platform
1160
1199
  - **MailerSend** - Modern email API for developers
@@ -1188,7 +1227,7 @@ const result = await mail.send(message);
1188
1227
 
1189
1228
  ### Universal Providers (All Runtimes)
1190
1229
 
1191
- These providers work in **Node.js**, **Deno**, **Bun**, and **Cloudflare Workers**:
1230
+ These providers work in **Node.js**, **Bun**, and **Cloudflare Workers**:
1192
1231
 
1193
1232
  - ✅ **Resend** - Uses Fetch API
1194
1233
  - ✅ **HTTP** - Uses Fetch API
@@ -1225,50 +1264,67 @@ These providers require Node.js built-in modules and only work in **Node.js**:
1225
1264
  - ⚠️ **AWS SES** - Requires `node:crypto` for AWS Signature V4 signing
1226
1265
  - ⚠️ **SMTP** - Requires `node:net` and `node:tls` for SMTP connections
1227
1266
  - ⚠️ **MailCrab** - Wraps SMTP provider (requires Node.js)
1267
+ - ⚠️ **File** - Writes to the local filesystem (requires Node.js)
1228
1268
  - ⚠️ **Nodemailer** - Requires the `nodemailer` package (Node.js only)
1229
1269
 
1230
1270
  ### Template Engines
1231
1271
 
1232
1272
  Template engines are optional peer dependencies and work where their underlying packages are supported:
1233
1273
 
1234
- - **Handlebars** - Works in Node.js, Deno, Bun (where `handlebars` package is available)
1235
- - **MJML** - Works in Node.js, Deno, Bun (where `mjml` package is available)
1236
- - **React Email** - Works in Node.js, Deno, Bun (where `@react-email/render` package is available)
1237
- - **Vue Email** - Works in Node.js, Deno, Bun (where `@vue-email/render` package is available)
1238
- - **HTML-to-Text** - Works in Node.js, Deno, Bun (where `html-to-text` package is available)
1274
+ - **Handlebars** - Works in Node.js and Bun (where `handlebars` package is available)
1275
+ - **MJML** - Works in Node.js and Bun (where `mjml` package is available)
1276
+ - **React Email** - Works in Node.js and Bun (where `@react-email/render` package is available)
1277
+ - **Vue Email** - Works in Node.js and Bun (where `@vue-email/render` package is available)
1278
+ - **HTML-to-Text** - Works in Node.js and Bun (where `html-to-text` package is available)
1279
+
1280
+ ### Locale Template Files (Node.js)
1281
+
1282
+ `@visulima/email/template/locale-files` loads templates from a directory, one file per locale. For a template named `welcome`, `welcome.de.html` is used for `de` (and `de-AT`), and `welcome.html` is the fallback, registered under `defaultLocale`:
1283
+
1284
+ ```typescript
1285
+ import { renderHandlebars } from "@visulima/email/template/handlebars";
1286
+ import { createLocaleFileRenderer } from "@visulima/email/template/locale-files";
1287
+
1288
+ const render = createLocaleFileRenderer("./emails", renderHandlebars, { defaultLocale: "en" });
1289
+
1290
+ const html = await render("welcome", "de-AT", { name: "Ada" });
1291
+ ```
1292
+
1293
+ Only file names from the directory listing are read, and a requested locale only selects a key, so a locale from user input never becomes a path. Templates are read on every call; cache the result if they do not change at runtime. Layouts are not part of this loader.
1239
1294
 
1240
1295
  ### Runtime Requirements Summary
1241
1296
 
1242
- | Provider | Node.js | Deno | Bun | Cloudflare Workers |
1243
- | ------------- | ------- | ---- | ---- | ------------------ |
1244
- | Resend | ✅ | ✅ | ✅ | ✅ |
1245
- | HTTP | ✅ | ✅ | ✅ | ✅ |
1246
- | Zeptomail | ✅ | ✅ | ✅ | ✅ |
1247
- | Brevo | ✅ | ✅ | ✅ | ✅ |
1248
- | Mailgun | ✅ | ✅ | ✅ | ✅ |
1249
- | Mailjet | ✅ | ✅ | ✅ | ✅ |
1250
- | MailerSend | ✅ | ✅ | ✅ | ✅ |
1251
- | Mandrill | ✅ | ✅ | ✅ | ✅ |
1252
- | MailPace | ✅ | ✅ | ✅ | ✅ |
1253
- | Mailtrap | ✅ | ✅ | ✅ | ✅ |
1254
- | Postal | ✅ | ✅ | ✅ | ✅ |
1255
- | Postmark | ✅ | ✅ | ✅ | ✅ |
1256
- | Azure | ✅ | ✅ | ✅ | ✅ |
1257
- | Infobip | ✅ | ✅ | ✅ | ✅ |
1258
- | Scaleway | ✅ | ✅ | ✅ | ✅ |
1259
- | AhaSend | ✅ | ✅ | ✅ | ✅ |
1260
- | Mailomat | ✅ | ✅ | ✅ | ✅ |
1261
- | Sweego | ✅ | ✅ | ✅ | ✅ |
1262
- | SendGrid | ✅ | ✅ | ✅ | ✅ |
1263
- | Plunk | ✅ | ✅ | ✅ | ✅ |
1264
- | Mock | ✅ | ✅ | ✅ | ✅ |
1265
- | AWS SES | ✅ | ❌ | ❌ | ❌ |
1266
- | SMTP | ✅ | ❌ | ❌ | ❌ |
1267
- | MailCrab | ✅ | ❌ | ❌ | ❌ |
1268
- | Nodemailer | ✅ | ❌ | ❌ | ❌ |
1269
- | Failover | ✅\* | ✅\* | ✅\* | ✅\* |
1270
- | Round Robin | ✅\* | ✅\* | ✅\* | ✅\* |
1271
- | OpenTelemetry | ✅\* | ✅\* | ✅\* | ✅\* |
1297
+ | Provider | Node.js | Bun | Cloudflare Workers |
1298
+ | ------------- | ------- | ---- | ------------------ |
1299
+ | Resend | ✅ | ✅ | ✅ |
1300
+ | HTTP | ✅ | ✅ | ✅ |
1301
+ | Zeptomail | ✅ | ✅ | ✅ |
1302
+ | Brevo | ✅ | ✅ | ✅ |
1303
+ | Mailgun | ✅ | ✅ | ✅ |
1304
+ | Mailjet | ✅ | ✅ | ✅ |
1305
+ | MailerSend | ✅ | ✅ | ✅ |
1306
+ | Mandrill | ✅ | ✅ | ✅ |
1307
+ | MailPace | ✅ | ✅ | ✅ |
1308
+ | Mailtrap | ✅ | ✅ | ✅ |
1309
+ | Postal | ✅ | ✅ | ✅ |
1310
+ | Postmark | ✅ | ✅ | ✅ |
1311
+ | Azure | ✅ | ✅ | ✅ |
1312
+ | Infobip | ✅ | ✅ | ✅ |
1313
+ | Scaleway | ✅ | ✅ | ✅ |
1314
+ | AhaSend | ✅ | ✅ | ✅ |
1315
+ | Mailomat | ✅ | ✅ | ✅ |
1316
+ | Sweego | ✅ | ✅ | ✅ |
1317
+ | SendGrid | ✅ | ✅ | ✅ |
1318
+ | Plunk | ✅ | ✅ | ✅ |
1319
+ | Mock | ✅ | ✅ | ✅ |
1320
+ | AWS SES | ✅ | ❌ | ❌ |
1321
+ | SMTP | ✅ | ❌ | ❌ |
1322
+ | MailCrab | ✅ | ❌ | ❌ |
1323
+ | File | ✅ | ❌ | ❌ |
1324
+ | Nodemailer | ✅ | ❌ | ❌ |
1325
+ | Failover | ✅\* | ✅\* | ✅\* |
1326
+ | Round Robin | ✅\* | ✅\* | ✅\* |
1327
+ | OpenTelemetry | ✅\* | ✅\* | ✅\* |
1272
1328
 
1273
1329
  \* Runtime support depends on the wrapped providers. Works if all wrapped providers support the runtime.
1274
1330
 
@@ -1386,7 +1442,7 @@ See [Middleware](https://visulima.com/docs/package/email/middleware/introduction
1386
1442
 
1387
1443
  ## Queue & Worker
1388
1444
 
1389
- Durable background sending via the `EmailQueue` interface: an in-memory `MemoryQueue`, an `UnstorageQueue` (`@visulima/email/queue/unstorage`) backed by any [unstorage](https://unstorage.unjs.io/) store (Redis/FS/KV/Postgres), and a `createWorker(...)` with bounded concurrency, retry/backoff and dead-lettering.
1445
+ Durable background sending via the `EmailQueue` interface: an in-memory `MemoryQueue`, an `UnstorageQueue` (`@visulima/email/queue/unstorage`) backed by any [unstorage](https://unstorage.unjs.io/) store (Redis/FS/KV/Postgres), and a `createWorker(...)` with bounded concurrency, retry/backoff and dead-lettering. Permanent failures, such as HTTP 4xx responses other than `408`, `409` and `429`, are dead-lettered on their first attempt.
1390
1446
 
1391
1447
  ```typescript
1392
1448
  import { createMail } from "@visulima/email";
@@ -1 +1 @@
1
- import c from"../packem_shared/EmailError-BIaHK1Uw.js";const g=r=>r==null?[]:Array.isArray(r)?r:[r],e=r=>{if(typeof r=="string")return r;if(typeof r=="number"||typeof r=="boolean")return String(r)},u=r=>{const a=e(r);if(a===void 0)return;const i=Number(a);return Number.isNaN(i)?void 0:i},f=r=>g(r).map(a=>({domain:e(a.domain),result:e(a.result)})),_=async r=>{let a;try{({XMLParser:a}=await import("fast-xml-parser"))}catch(t){throw t instanceof Error&&(t.code==="ERR_MODULE_NOT_FOUND"||t.message.includes("Cannot find module")||t.message.includes("Cannot find package"))?new c("deliverability","fast-xml-parser is not installed. Please install it: pnpm add fast-xml-parser",{cause:t}):new c("deliverability",`Failed to load fast-xml-parser: ${t.message}`,{cause:t})}let i;try{i=new a({ignoreAttributes:!0,parseTagValue:!1}).parse(r)}catch(t){throw new c("deliverability",`Failed to parse DMARC report: ${t.message}`,{cause:t})}const n=i.feedback??{},o=n.report_metadata??{},m=o.date_range??{},s=n.policy_published??{},y=g(n.record).map(t=>{const d=t.row??{},p=d.policy_evaluated??{},b=t.identifiers??{},l=t.auth_results??{};return{authResults:{dkim:f(l.dkim),spf:f(l.spf)},count:u(d.count)??0,disposition:e(p.disposition),dkim:e(p.dkim),headerFrom:e(b.header_from),sourceIp:e(d.source_ip),spf:e(p.spf)}});return{dateRangeBegin:e(m.begin),dateRangeEnd:e(m.end),email:e(o.email),organizationName:e(o.org_name),policyPublished:{adkim:e(s.adkim),aspf:e(s.aspf),domain:e(s.domain),p:e(s.p),pct:u(s.pct),sp:e(s.sp)},records:y,reportId:e(o.report_id)}};export{_ as parseDmarcReport};
1
+ import c from"../packem_shared/EmailError-SXEFQEyA.js";const g=r=>r==null?[]:Array.isArray(r)?r:[r],e=r=>{if(typeof r=="string")return r;if(typeof r=="number"||typeof r=="boolean")return String(r)},u=r=>{const a=e(r);if(a===void 0)return;const i=Number(a);return Number.isNaN(i)?void 0:i},f=r=>g(r).map(a=>({domain:e(a.domain),result:e(a.result)})),_=async r=>{let a;try{({XMLParser:a}=await import("fast-xml-parser"))}catch(t){throw t instanceof Error&&(t.code==="ERR_MODULE_NOT_FOUND"||t.message.includes("Cannot find module")||t.message.includes("Cannot find package"))?new c("deliverability","fast-xml-parser is not installed. Please install it: pnpm add fast-xml-parser",{cause:t}):new c("deliverability",`Failed to load fast-xml-parser: ${t.message}`,{cause:t})}let i;try{i=new a({ignoreAttributes:!0,parseTagValue:!1}).parse(r)}catch(t){throw new c("deliverability",`Failed to parse DMARC report: ${t.message}`,{cause:t})}const n=i.feedback??{},o=n.report_metadata??{},m=o.date_range??{},s=n.policy_published??{},y=g(n.record).map(t=>{const d=t.row??{},p=d.policy_evaluated??{},b=t.identifiers??{},l=t.auth_results??{};return{authResults:{dkim:f(l.dkim),spf:f(l.spf)},count:u(d.count)??0,disposition:e(p.disposition),dkim:e(p.dkim),headerFrom:e(b.header_from),sourceIp:e(d.source_ip),spf:e(p.spf)}});return{dateRangeBegin:e(m.begin),dateRangeEnd:e(m.end),email:e(o.email),organizationName:e(o.org_name),policyPublished:{adkim:e(s.adkim),aspf:e(s.aspf),domain:e(s.domain),p:e(s.p),pct:u(s.pct),sp:e(s.sp)},records:y,reportId:e(o.report_id)}};export{_ as parseDmarcReport};
package/dist/index.d.ts CHANGED
@@ -65,10 +65,16 @@ declare class VisulimaError extends Error {
65
65
  declare class EmailError extends VisulimaError {
66
66
  readonly component: string;
67
67
  readonly code?: string;
68
+ /**
69
+ * True when repeating the same request would fail the same way, so a queue worker should
70
+ * dead-letter the job instead of retrying it.
71
+ */
72
+ readonly permanent: boolean;
68
73
  constructor(component: string, message: string, options?: {
69
74
  cause?: Error | unknown;
70
75
  code?: string;
71
76
  hint?: string | string[];
77
+ permanent?: boolean;
72
78
  });
73
79
  }
74
80
  /**
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{detectMimeType as a,generateContentId as t,readFileAsBuffer as o}from"./packem_shared/detectMimeType-BRz3Qjyz.js";import{default as p}from"./packem_shared/DraftMailMessage-B0gwf8n_.js";import{default as m}from"./packem_shared/EmailError-BIaHK1Uw.js";import{default as l}from"./packem_shared/RequiredOptionError-ctDEEB1s.js";import{Mail as u,createMail as x}from"./packem_shared/Mail-DmYNQ0KK.js";import{default as M}from"./packem_shared/MailMessage-DmmaNHHc.js";import{defineProvider as E}from"./packem_shared/defineProvider-C9q-7iwt.js";import{default as g}from"./utils/parse-eml.js";import{isErr as y,isOk as w,mapOk as A,tryAsync as F,unwrap as h,unwrapOr as q}from"./utils/result.js";import{default as B}from"./utils/validation/check-feature-support.js";export{p as DraftMailMessage,m as EmailError,u as Mail,M as MailMessage,l as RequiredOptionError,B as checkFeatureSupport,x as createMail,E as defineProvider,a as detectMimeType,t as generateContentId,y as isErr,w as isOk,A as mapOk,g as parseEml,o as readFileAsBuffer,F as tryAsync,h as unwrap,q as unwrapOr};
1
+ import{detectMimeType as a,generateContentId as t,readFileAsBuffer as o}from"./packem_shared/detectMimeType-BRz3Qjyz.js";import{default as p}from"./packem_shared/DraftMailMessage-B0gwf8n_.js";import{default as m}from"./packem_shared/EmailError-SXEFQEyA.js";import{default as l}from"./packem_shared/RequiredOptionError-C2wWqmiE.js";import{Mail as u,createMail as x}from"./packem_shared/Mail-0cxS6jre.js";import{default as M}from"./packem_shared/MailMessage-DmmaNHHc.js";import{defineProvider as E}from"./packem_shared/defineProvider-C9q-7iwt.js";import{default as g}from"./utils/parse-eml.js";import{isErr as y,isOk as w,mapOk as A,tryAsync as F,unwrap as h,unwrapOr as q}from"./utils/result.js";import{default as B}from"./utils/validation/check-feature-support.js";export{p as DraftMailMessage,m as EmailError,u as Mail,M as MailMessage,l as RequiredOptionError,B as checkFeatureSupport,x as createMail,E as defineProvider,a as detectMimeType,t as generateContentId,y as isErr,w as isOk,A as mapOk,g as parseEml,o as readFileAsBuffer,F as tryAsync,h as unwrap,q as unwrapOr};
@@ -1 +1 @@
1
- import{circuitBreakerMiddleware as o}from"../packem_shared/circuitBreakerMiddleware-DcBN7K6H.js";import{dedupeMiddleware as i}from"../packem_shared/dedupeMiddleware-BTo8Qjje.js";import{withEvents as p}from"../packem_shared/withEvents-BinK2hMw.js";import{loggingMiddleware as f}from"../packem_shared/loggingMiddleware-DNVf8O1B.js";import{withMetrics as w}from"../packem_shared/withMetrics-i3mZVfeE.js";import{oauth2Middleware as l}from"../packem_shared/oauth2Middleware-C0M1w3_2.js";import{RATE_LIMIT_PRESETS as h,rateLimitMiddleware as s}from"../packem_shared/RATE_LIMIT_PRESETS-BIFmRuh2.js";import{default as c}from"../packem_shared/withRender-Ce6leoYE.js";import{retryMiddleware as E}from"../packem_shared/retryMiddleware-CaTv0UIm.js";import{withSuppression as g}from"../packem_shared/withSuppression-B0eZ2xNQ.js";import{withTelemetry as S}from"../packem_shared/withTelemetry-DEKTis1I.js";import{composeMiddleware as I}from"../packem_shared/composeMiddleware-B3RCDFsy.js";export{h as RATE_LIMIT_PRESETS,o as circuitBreakerMiddleware,I as composeMiddleware,i as dedupeMiddleware,f as loggingMiddleware,l as oauth2Middleware,s as rateLimitMiddleware,E as retryMiddleware,p as withEvents,w as withMetrics,c as withRender,g as withSuppression,S as withTelemetry};
1
+ import{circuitBreakerMiddleware as o}from"../packem_shared/circuitBreakerMiddleware-Cm0m75qi.js";import{dedupeMiddleware as i}from"../packem_shared/dedupeMiddleware-BTo8Qjje.js";import{withEvents as p}from"../packem_shared/withEvents-BinK2hMw.js";import{loggingMiddleware as f}from"../packem_shared/loggingMiddleware-DNVf8O1B.js";import{withMetrics as w}from"../packem_shared/withMetrics-i3mZVfeE.js";import{oauth2Middleware as l}from"../packem_shared/oauth2Middleware-C0M1w3_2.js";import{RATE_LIMIT_PRESETS as h,rateLimitMiddleware as s}from"../packem_shared/RATE_LIMIT_PRESETS-BIFmRuh2.js";import{default as c}from"../packem_shared/withRender-Ce6leoYE.js";import{retryMiddleware as E}from"../packem_shared/retryMiddleware-CaTv0UIm.js";import{withSuppression as g}from"../packem_shared/withSuppression-COCHL9Zx.js";import{withTelemetry as S}from"../packem_shared/withTelemetry-DEKTis1I.js";import{composeMiddleware as I}from"../packem_shared/composeMiddleware-B3RCDFsy.js";export{h as RATE_LIMIT_PRESETS,o as circuitBreakerMiddleware,I as composeMiddleware,i as dedupeMiddleware,f as loggingMiddleware,l as oauth2Middleware,s as rateLimitMiddleware,E as retryMiddleware,p as withEvents,w as withMetrics,c as withRender,g as withSuppression,S as withTelemetry};