@visulima/email 1.0.1 → 2.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 (51) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +48 -5
  3. package/dist/index.js +1 -1
  4. package/dist/middleware/index.d.ts +13 -5
  5. package/dist/middleware/index.js +1 -1
  6. package/dist/packem_shared/{Mail-C1zp-fqt.js → Mail-CYAwMRnX.js} +1 -1
  7. package/dist/packem_shared/autoSendProvider-Bz3g6aZi.js +1 -0
  8. package/dist/packem_shared/{awsSesProvider-BGZJUIep.js → awsSesProvider-962hIcbo.js} +1 -1
  9. package/dist/packem_shared/{build-mime-message-B6927SQy.js → build-mime-message-BW5FQ2Bt.js} +1 -1
  10. package/dist/packem_shared/{cloudflareEmailProvider-Bv-ty-74.js → cloudflareEmailProvider-B8mOEl3N.js} +1 -1
  11. package/dist/packem_shared/create-token-cache-D56KQGVQ.js +1 -0
  12. package/dist/packem_shared/{createTestEmail-D3XPGiHY.js → createTestEmail-f12yLlWn.js} +1 -1
  13. package/dist/packem_shared/{mailCrabProvider-CPtBT6Th.js → mailCrabProvider-DRE5snM9.js} +1 -1
  14. package/dist/packem_shared/{mailPaceProvider-CJEvOFBh.js → mailPaceProvider-DZent57J.js} +1 -1
  15. package/dist/packem_shared/{mandrillProvider-DWPFh_Sj.js → mandrillProvider-DSsAknmA.js} +1 -1
  16. package/dist/packem_shared/oauth2Middleware-DQh-hIkv.js +1 -0
  17. package/dist/packem_shared/outlook365Provider-CkjXkY-7.js +1 -0
  18. package/dist/packem_shared/{plunkProvider-yTlrJVEp.js → plunkProvider-D3T2T-2V.js} +1 -1
  19. package/dist/packem_shared/{postmarkProvider-CDx85Yge.js → postmarkProvider-vspVSSOp.js} +1 -1
  20. package/dist/packem_shared/{sanitize-header-DJhgZl3y.js → sanitize-header-DtQwAnzg.js} +1 -1
  21. package/dist/packem_shared/{smtpProvider-Bm0yP97W.js → smtpProvider-5MI3-EPh.js} +1 -1
  22. package/dist/packem_shared/{zeptomailProvider-DKBPSHPj.js → zeptomailProvider-DUesgbC-.js} +1 -1
  23. package/dist/providers/autosend/index.d.ts +56 -0
  24. package/dist/providers/autosend/index.js +1 -0
  25. package/dist/providers/aws-ses/index.js +1 -1
  26. package/dist/providers/cloudflare-email/index.js +1 -1
  27. package/dist/providers/mailcrab/index.js +1 -1
  28. package/dist/providers/mailpace/index.js +1 -1
  29. package/dist/providers/mandrill/index.js +1 -1
  30. package/dist/providers/outlook365/index.d.ts +83 -5
  31. package/dist/providers/outlook365/index.js +1 -1
  32. package/dist/providers/plunk/index.js +1 -1
  33. package/dist/providers/postmark/index.js +1 -1
  34. package/dist/providers/smtp/index.js +1 -1
  35. package/dist/providers/zeptomail/index.js +1 -1
  36. package/dist/render/cid.d.ts +17 -0
  37. package/dist/render/css-inline.d.ts +15 -0
  38. package/dist/render/css-inline.js +1 -0
  39. package/dist/render/dark-mode.d.ts +20 -0
  40. package/dist/render/preheader.d.ts +24 -0
  41. package/dist/test/index.js +1 -1
  42. package/package.json +35 -19
  43. package/dist/packem_shared/inlineCss-BQ7d2Cyz.js +0 -1
  44. package/dist/packem_shared/oauth2Middleware-CodqXkyj.js +0 -1
  45. package/dist/packem_shared/outlook365Provider-63ggDpqV.js +0 -1
  46. package/dist/packem_shared/postProcessHtml-DqKi2Ucg.js +0 -1
  47. package/dist/render/index.d.ts +0 -107
  48. package/dist/render/index.js +0 -1
  49. /package/dist/{packem_shared/extractCidReferences-BuoTREMp.js → render/cid.js} +0 -0
  50. /package/dist/{packem_shared/addDarkModeSupport-DZYxULjl.js → render/dark-mode.js} +0 -0
  51. /package/dist/{packem_shared/injectPreheader-CF9WHZ7J.js → render/preheader.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,57 @@
1
+ ## @visulima/email [2.1.0](https://github.com/visulima/visulima/compare/%40visulima%2Femail%402.0.0...%40visulima%2Femail%402.1.0) (2026-07-17)
2
+
3
+
4
+ ### Dependencies
5
+
6
+ * **@visulima/fs:** upgraded to 5.0.3
7
+
8
+ ## @visulima/email [2.0.0](https://github.com/visulima/visulima/compare/%40visulima%2Femail%401.0.1...%40visulima%2Femail%402.0.0) (2026-07-15)
9
+
10
+
11
+ ### ⚠ BREAKING CHANGES
12
+
13
+ * **email:** the `@visulima/email/render` barrel and the `postProcessHtml` helper (with `PostProcessOptions`) have been removed, and the CSS inliner now resolves the optional `juice` peer at import time.
14
+
15
+ **Why:** importing `@visulima/email` eagerly evaluated `createRequire(import.meta.url)` from the render `css-inline` module, which the bundler folds into the shared chunk that the package root pulls. In bundled non-Node runtimes (Cloudflare Workers/workerd, Vite production builds) `import.meta.url` is `undefined`, so the worker crashed at boot — before serving any request — even for consumers that never inline CSS ([#723](https://github.com/visulima/visulima/issues/723)).
16
+
17
+ **Migration:**
18
+
19
+ 1. Import each render helper from its own subpath instead of the removed `@visulima/email/render` barrel:
20
+
21
+ ```diff
22
+ - import { injectPreheader, addDarkModeSupport, rewriteCidLinks, extractCidReferences } from "@visulima/email/render";
23
+ + import { injectPreheader } from "@visulima/email/render/preheader";
24
+ + import { addDarkModeSupport } from "@visulima/email/render/dark-mode";
25
+ + import { rewriteCidLinks, extractCidReferences } from "@visulima/email/render/cid";
26
+ ```
27
+
28
+ 2. Replace `postProcessHtml(...)` by composing the helpers yourself (order: inline CSS → preheader → dark-mode → CID rewrite):
29
+
30
+ ```diff
31
+ - import { postProcessHtml } from "@visulima/email/render";
32
+ -
33
+ - const out = postProcessHtml(html, { inlineCss: true, preheader: "Hi", darkMode: true });
34
+ + import inlineCss from "@visulima/email/render/css-inline";
35
+ + import { injectPreheader } from "@visulima/email/render/preheader";
36
+ + import { addDarkModeSupport } from "@visulima/email/render/dark-mode";
37
+ +
38
+ + const out = addDarkModeSupport(injectPreheader(inlineCss(html), "Hi"));
39
+ ```
40
+
41
+ Read the nesting inside-out to follow the pipeline order: `inlineCss` runs first, then `injectPreheader`, then `addDarkModeSupport`. CID rewriting is intentionally omitted here because the original `postProcessHtml` call set no `cidResolver`; if you used one, apply it as the outermost call — `rewriteCidLinks(out, resolver)`.
42
+
43
+ 3. `inlineCss` now lives at `@visulima/email/render/css-inline` (default export) and imports `juice` eagerly. Install the optional peer (`pnpm add juice`) before importing it — a missing peer now surfaces as a module-resolution error at import time rather than an `EmailError` on first call. Import it only where you actually inline CSS so `juice` (a Node-only library) stays out of edge/worker bundles.
44
+
45
+
46
+ ### Bug Fixes
47
+
48
+ * **email:** make render exports worker-safe ([#726](https://github.com/visulima/visulima/pull/726)) ([2d09b49](https://github.com/visulima/visulima/commit/2d09b4985e78c71c208b12b3507659b9ab5594cf))
49
+
50
+
51
+ ### Dependencies
52
+
53
+ * **@visulima/fs:** upgraded to 5.0.2
54
+
1
55
  ## @visulima/email [1.0.1](https://github.com/visulima/visulima/compare/%40visulima%2Femail%401.0.0...%40visulima%2Femail%401.0.1) (2026-07-15)
2
56
 
3
57
 
package/README.md CHANGED
@@ -341,6 +341,33 @@ const roundRobin = roundRobinProvider({
341
341
 
342
342
  **Note:** The round-robin provider starts at a random provider and then rotates through providers for each subsequent email. If a provider is unavailable, it will automatically try the next provider in the rotation.
343
343
 
344
+ ### AutoSend Provider
345
+
346
+ AutoSend is a transactional and marketing email service with volume-based pricing. Universal runtime (Fetch API).
347
+
348
+ ```typescript
349
+ import { createMail } from "@visulima/email";
350
+ import { autoSendProvider } from "@visulima/email/providers/autosend";
351
+
352
+ const mail = createMail(
353
+ autoSendProvider({
354
+ apiKey: process.env.AUTOSEND_API_KEY,
355
+ }),
356
+ );
357
+
358
+ await mail.send({
359
+ from: { email: "hello@mail.yourdomain.com", name: "Your Company" },
360
+ to: { email: "customer@example.com", name: "Jane Doe" },
361
+ subject: "Welcome!",
362
+ html: "<h1>Thanks for signing up.</h1>",
363
+ // AutoSend-specific: templateId, dynamicData, trackingOpen, trackingClick,
364
+ // unsubscribeGroupId, bypassSuppressions
365
+ });
366
+ ```
367
+
368
+ AutoSend's send endpoint takes a **single** `to` recipient (max 50 across to/cc/bcc). Passing several
369
+ is rejected rather than silently truncated.
370
+
344
371
  ### Mailgun Provider
345
372
 
346
373
  Mailgun is a developer-friendly email API service built for transactional emails and automated messaging.
@@ -955,16 +982,32 @@ await mail.send({
955
982
 
956
983
  ### Outlook365 Provider
957
984
 
958
- Sends through Microsoft Graph `sendMail`. Universal runtime (Fetch API). Bring your own OAuth2 token (`Mail.Send` scope)
959
- via `accessToken` or `getAccessToken` no auth SDK is bundled.
985
+ Sends through Microsoft Graph `sendMail`. Universal runtime (Fetch API). No auth SDK is bundled authenticate with
986
+ the built-in app-only (client credentials) or delegated (refresh token) flow, or bring your own OAuth2 token
987
+ (`Mail.Send` scope) via `accessToken` / `getAccessToken`.
960
988
 
961
989
  ```typescript
962
- import { createMail, outlook365Provider } from "@visulima/email/providers/outlook365";
990
+ import { createMail } from "@visulima/email";
991
+ import { outlook365Provider } from "@visulima/email/providers/outlook365";
963
992
 
993
+ // App-only (client credentials) — userId is required, app-only tokens have no "me" mailbox.
964
994
  const mail = createMail(
965
995
  outlook365Provider({
966
- getAccessToken: async () => getGraphAccessToken(),
967
- userId: "sender@contoso.com", // or "me" (default)
996
+ tenantId: process.env.AZURE_TENANT_ID,
997
+ clientId: process.env.AZURE_CLIENT_ID,
998
+ clientSecret: process.env.AZURE_CLIENT_SECRET,
999
+ userId: "sender@contoso.com",
1000
+ }),
1001
+ );
1002
+
1003
+ // Delegated (refresh token) — sends as the consenting user.
1004
+ const delegated = createMail(
1005
+ outlook365Provider({
1006
+ tenantId: process.env.AZURE_TENANT_ID,
1007
+ clientId: process.env.AZURE_CLIENT_ID,
1008
+ refreshToken: await loadRefreshToken(),
1009
+ // Azure AD may rotate the refresh token; this is awaited before the token is used.
1010
+ onRefreshToken: async (token) => saveRefreshToken(token),
968
1011
  }),
969
1012
  );
970
1013
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{detectMimeType as a,generateContentId as t,readFileAsBuffer as o}from"./packem_shared/detectMimeType-DFH3kp6K.js";import{default as p}from"./packem_shared/DraftMailMessage-CGTVuy2z.js";import{default as m}from"./packem_shared/EmailError-B-sEf3bp.js";import{default as l}from"./packem_shared/RequiredOptionError-DuNNY_a5.js";import{Mail as u,createMail as x}from"./packem_shared/Mail-C1zp-fqt.js";import{default as M}from"./packem_shared/MailMessage-DQRgs5Dz.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-DFH3kp6K.js";import{default as p}from"./packem_shared/DraftMailMessage-CGTVuy2z.js";import{default as m}from"./packem_shared/EmailError-B-sEf3bp.js";import{default as l}from"./packem_shared/RequiredOptionError-DuNNY_a5.js";import{Mail as u,createMail as x}from"./packem_shared/Mail-CYAwMRnX.js";import{default as M}from"./packem_shared/MailMessage-DQRgs5Dz.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};
@@ -150,9 +150,9 @@ interface MetricsMiddlewareOptions {
150
150
  */
151
151
  declare const withMetrics: (recorder: MetricsRecorder, options?: MetricsMiddlewareOptions) => Middleware;
152
152
  /**
153
- * An OAuth2 access token plus its expiry.
153
+ * A token that may carry an absolute expiry.
154
154
  */
155
- interface OAuth2Token {
155
+ interface CacheableToken {
156
156
  /**
157
157
  * The bearer access token.
158
158
  */
@@ -163,6 +163,13 @@ interface OAuth2Token {
163
163
  expiresAt?: number;
164
164
  }
165
165
  /**
166
+ * Options for {@link createTokenCache}.
167
+ */
168
+ /**
169
+ * An OAuth2 access token plus its expiry.
170
+ */
171
+ type OAuth2Token = CacheableToken;
172
+ /**
166
173
  * Options for the {@link oauth2Middleware}.
167
174
  */
168
175
  interface OAuth2MiddlewareOptions {
@@ -250,16 +257,17 @@ declare const RATE_LIMIT_PRESETS: {
250
257
  declare const rateLimitMiddleware: (options: RateLimitMiddlewareOptions) => Middleware;
251
258
  /**
252
259
  * Wraps a transform that rewrites the message before it is sent — e.g. running the HTML through the
253
- * `@visulima/email/render` post-processing pipeline (preheader, CID rewrite, dark-mode, CSS inline).
260
+ * render helpers (preheader, dark-mode, CID rewrite) and the opt-in CSS inliner.
254
261
  * @param transform Maps the resolved {@link EmailOptions} to its rendered form.
255
262
  * @returns A middleware that applies the transform ahead of the provider call.
256
263
  * @example
257
264
  * ```ts
258
- * import { postProcessHtml } from "@visulima/email/render";
265
+ * import { injectPreheader } from "@visulima/email/render/preheader";
266
+ * import { addDarkModeSupport } from "@visulima/email/render/dark-mode";
259
267
  *
260
268
  * mail.use(withRender(async (email) => ({
261
269
  * ...email,
262
- * html: email.html ? postProcessHtml(email.html, { preheader: "Hi!", darkMode: true }) : email.html,
270
+ * html: email.html ? addDarkModeSupport(injectPreheader(email.html, "Hi!")) : email.html,
263
271
  * })));
264
272
  * ```
265
273
  */
@@ -1 +1 @@
1
- import{circuitBreakerMiddleware as o}from"../packem_shared/circuitBreakerMiddleware-D2SA_07f.js";import{dedupeMiddleware as i}from"../packem_shared/dedupeMiddleware-B6ajWOTi.js";import{withEvents as p}from"../packem_shared/withEvents-CCVblSqj.js";import{loggingMiddleware as f}from"../packem_shared/loggingMiddleware-CZIiVMVp.js";import{withMetrics as w}from"../packem_shared/withMetrics-DWywX_6M.js";import{oauth2Middleware as l}from"../packem_shared/oauth2Middleware-CodqXkyj.js";import{RATE_LIMIT_PRESETS as h,rateLimitMiddleware as s}from"../packem_shared/RATE_LIMIT_PRESETS-BPADLgcA.js";import{default as c}from"../packem_shared/withRender-VP9wE5Yr.js";import{retryMiddleware as E}from"../packem_shared/retryMiddleware-DbViDX4r.js";import{withSuppression as g}from"../packem_shared/withSuppression-DBaZDMAr.js";import{withTelemetry as S}from"../packem_shared/withTelemetry-DL2qo0Hp.js";import{composeMiddleware as I}from"../packem_shared/composeMiddleware-BHwLLEzK.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-D2SA_07f.js";import{dedupeMiddleware as i}from"../packem_shared/dedupeMiddleware-B6ajWOTi.js";import{withEvents as p}from"../packem_shared/withEvents-CCVblSqj.js";import{loggingMiddleware as f}from"../packem_shared/loggingMiddleware-CZIiVMVp.js";import{withMetrics as w}from"../packem_shared/withMetrics-DWywX_6M.js";import{oauth2Middleware as l}from"../packem_shared/oauth2Middleware-DQh-hIkv.js";import{RATE_LIMIT_PRESETS as h,rateLimitMiddleware as s}from"../packem_shared/RATE_LIMIT_PRESETS-BPADLgcA.js";import{default as c}from"../packem_shared/withRender-VP9wE5Yr.js";import{retryMiddleware as E}from"../packem_shared/retryMiddleware-DbViDX4r.js";import{withSuppression as g}from"../packem_shared/withSuppression-DBaZDMAr.js";import{withTelemetry as S}from"../packem_shared/withTelemetry-DL2qo0Hp.js";import{composeMiddleware as I}from"../packem_shared/composeMiddleware-BHwLLEzK.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 +1 @@
1
- import h from"./DraftMailMessage-CGTVuy2z.js";import v from"./EmailError-B-sEf3bp.js";import f from"./MailMessage-DQRgs5Dz.js";import{composeMiddleware as C}from"./composeMiddleware-BHwLLEzK.js";import{F as w}from"./build-mime-message-B6927SQy.js";import{c as M}from"./create-logger-BQTS3f-I.js";import{s as l}from"./headers-to-record-De1Eg951.js";import T from"../utils/validation/check-feature-support.js";const S=(i,e,r)=>{e.success&&e.data?i&&i.info("Email sent successfully",{messageId:e.data.messageId,provider:e.data.provider}):i&&i.error("Email send failed",{error:e.error,provider:r})},j=async(i,e,r)=>{const s={...i,to:e.to};return e.cc&&(s.cc=e.cc),e.bcc&&(s.bcc=e.bcc),e.replyTo&&(s.replyTo=e.replyTo),e.headers&&(s.headers={...l(i.headers??{}),...l(e.headers)}),s.subject=e.subject??i.subject,r&&e.data&&(s.subject=await r(s.subject,e.data),i.html!==void 0&&(s.html=await r(i.html,e.data)),i.text!==void 0&&(s.text=await r(i.text,e.data))),s};class u{static extractErrorMessages(e){return e instanceof Error?[e.message]:[String(e??"Unknown error")]}provider;logger;loggerInstance;globalConfig;featureCheck;middlewares=[];composedSend;mountedProviders=new Map;constructor(e,r){this.provider=e,this.featureCheck=r?.featureCheck??"error"}setLogger(e){return this.loggerInstance=e,this.logger=M("Mail",e),this}use(e){return this.middlewares.push(e),this.composedSend=void 0,this}mount(e,r){return this.mountedProviders.set(e,r),this}setFrom(e){return this.globalConfig??={},this.globalConfig.from=e,this.logger&&this.logger.debug("Default from address updated",{from:e.email}),this}setReplyTo(e){return this.globalConfig??={},this.globalConfig.replyTo=e,this.logger&&this.logger.debug("Default reply-to address updated",{replyTo:e.email}),this}setHeaders(e){if(this.globalConfig??={},this.globalConfig.headers=e,this.logger){const r=l(e);this.logger.debug("Default headers updated",{count:Object.keys(r).length,headers:Object.keys(r)})}return this}async draft(e){let r=e instanceof f||e instanceof h?await this.buildDraftFromMessage(e):await this.buildDraftFromOptions(e);r=this.applyGlobalConfig(r);const s=r.headers?l(r.headers):{};r.headers={...s,"X-Unsent":"1"};const t=await w(r,{includeBcc:!0});return this.logger&&this.logger.debug("Draft created successfully in EML format",{from:r.from.email,size:t.length,subject:r.subject,to:Array.isArray(r.to)?r.to.length:1}),t}async send(e){if(e instanceof h)throw new TypeError("Cannot send draft messages. Convert to MailMessage first or remove X-Unsent header.");let r;if(e instanceof f)this.logger&&this.logger.debug("Sending MailMessage instance"),this.loggerInstance&&e.setLogger(this.loggerInstance),r=await e.build();else{const o=e;this.logger&&this.logger.debug("Sending email with options",{subject:o.subject,to:Array.isArray(o.to)?o.to.length:1}),r=o}r=this.applyGlobalConfig(r);const s=this.assertFeatureSupport(r);if(s)return{error:s,success:!1};const t=await this.dispatch(r);return S(this.logger,t,this.provider.name??"unknown"),t}sendMany(e,r){const s=Math.max(1,Math.floor(r?.concurrency??1));return s===1?this.sendManySerial(e,r?.signal):this.sendManyConcurrent(e,s,r?.signal)}sendBatch(e,r,s){const t=async function*(){const o=e instanceof f?await e.build():e;for(const a of r)yield await j(o,a,s?.render)};return this.sendMany(t(),{concurrency:s?.concurrency,signal:s?.signal})}async sendOneToReceipt(e){const r=this.provider.name;try{const s=await this.send(e);return s.success&&s.data?{messageId:s.data.messageId,provider:s.data.provider??r,response:s.data.response,successful:!0,timestamp:s.data.timestamp}:{errorMessages:u.extractErrorMessages(s.error),provider:r,successful:!1}}catch(s){return{errorMessages:u.extractErrorMessages(s),provider:r,successful:!1}}}async*sendManySerial(e,r){const s=this.provider.name;let t=0,o=0,a=0;this.logger&&this.logger.debug("Starting batch email send",{provider:s});for await(const n of e){if(n instanceof h)throw new TypeError("Cannot send draft messages. Convert to MailMessage first or remove X-Unsent header.");if(r?.aborted){this.logger&&this.logger.warn("Batch send operation was aborted",{failed:a,processed:t,successful:o}),yield{errorMessages:["Send operation was aborted"],provider:s,successful:!1};return}t+=1;const g=await this.sendOneToReceipt(n);g.successful?o+=1:a+=1,yield g}this.logger&&this.logger.debug("Batch email send completed",{failureCount:a,processedCount:t,provider:s,successCount:o})}async*sendManyConcurrent(e,r,s){const t=this.provider.name;this.logger&&this.logger.debug("Starting concurrent batch email send",{concurrency:r,provider:t});const o=Symbol.asyncIterator in e?e[Symbol.asyncIterator]():e[Symbol.iterator](),a=new Map;let n=0,g=!1,p=!1;const m=async()=>{for(;!g&&!p&&a.size<r;){const d=await o.next();if(d.done){g=!0;break}const c=d.value;if(c instanceof h)throw new TypeError("Cannot send draft messages. Convert to MailMessage first or remove X-Unsent header.");const b=n;n+=1,a.set(b,this.sendOneToReceipt(c).then(y=>({id:b,receipt:y})))}};for(await m();a.size>0;){if(s?.aborted){p=!0,yield{errorMessages:["Send operation was aborted"],provider:t,successful:!1};return}const{id:d,receipt:c}=await Promise.race(a.values());a.delete(d),yield c,await m()}this.logger&&this.logger.debug("Concurrent batch email send completed",{processedCount:n,provider:t})}async dispatch(e){return this.middlewares.length===0?await this.resolveProvider(e).sendEmail(e):(this.composedSend??=C(this.middlewares,r=>Promise.resolve(this.resolveProvider(r).sendEmail(r))),await this.composedSend(e))}resolveProvider(e){return e.stream!==void 0?this.mountedProviders.get(e.stream)??this.provider:this.provider}assertFeatureSupport(e){if(this.featureCheck==="off")return;const{supported:r,violations:s}=T(e,this.provider.features);if(r)return;const t=this.provider.name??"unknown",o=s.map(n=>n.field),a=s.map(n=>n.message);if(this.featureCheck==="warn"){this.logger&&this.logger.warn("Message uses capabilities the provider does not support",{fields:o,provider:t});return}return this.logger&&this.logger.error("Message rejected by capability guard",{fields:o,provider:t}),new v(t,`Provider does not support the following message fields: ${o.join(", ")}`,{code:"UNSUPPORTED_FEATURES",hint:a})}async buildDraftFromMessage(e){return this.logger&&this.logger.debug("Creating draft from MailMessage instance"),this.loggerInstance&&e.setLogger(this.loggerInstance),this.applyGlobalConfigToMessage(e),await e.build()}async buildDraftFromOptions(e){return this.logger&&this.logger.debug("Creating draft from email options",{subject:e.subject,to:Array.isArray(e.to)?e.to.length:1}),e}applyGlobalConfigToMessage(e){const r=this.globalConfig?.from;r&&!e.getFrom()&&e.from(r);const s=this.globalConfig?.replyTo;if(s&&!e.getReplyTo()&&e.replyTo(s),this.globalConfig?.headers){const t=l(this.globalConfig.headers);Object.entries(t).forEach(([o,a])=>{e.header(o,a)})}}applyGlobalConfig(e){if(!this.globalConfig)return e;const r={...e};if(!r.from&&this.globalConfig.from&&(r.from=this.globalConfig.from,this.logger&&this.logger.debug("Applied global from address",{from:this.globalConfig.from.email})),!r.replyTo&&this.globalConfig.replyTo&&(r.replyTo=this.globalConfig.replyTo,this.logger&&this.logger.debug("Applied global reply-to address",{replyTo:this.globalConfig.replyTo.email})),this.globalConfig.headers){const s=l(this.globalConfig.headers),t=r.headers?l(r.headers):{};r.headers={...s,...t},this.logger&&this.logger.debug("Merged global headers",{globalCount:Object.keys(s).length,messageCount:Object.keys(t).length})}return r}}const D=(i,e)=>new u(i,e);export{u as Mail,D as createMail};
1
+ import h from"./DraftMailMessage-CGTVuy2z.js";import v from"./EmailError-B-sEf3bp.js";import f from"./MailMessage-DQRgs5Dz.js";import{composeMiddleware as C}from"./composeMiddleware-BHwLLEzK.js";import{F as w}from"./build-mime-message-BW5FQ2Bt.js";import{c as M}from"./create-logger-BQTS3f-I.js";import{s as l}from"./headers-to-record-De1Eg951.js";import T from"../utils/validation/check-feature-support.js";const S=(i,e,r)=>{e.success&&e.data?i&&i.info("Email sent successfully",{messageId:e.data.messageId,provider:e.data.provider}):i&&i.error("Email send failed",{error:e.error,provider:r})},j=async(i,e,r)=>{const s={...i,to:e.to};return e.cc&&(s.cc=e.cc),e.bcc&&(s.bcc=e.bcc),e.replyTo&&(s.replyTo=e.replyTo),e.headers&&(s.headers={...l(i.headers??{}),...l(e.headers)}),s.subject=e.subject??i.subject,r&&e.data&&(s.subject=await r(s.subject,e.data),i.html!==void 0&&(s.html=await r(i.html,e.data)),i.text!==void 0&&(s.text=await r(i.text,e.data))),s};class u{static extractErrorMessages(e){return e instanceof Error?[e.message]:[String(e??"Unknown error")]}provider;logger;loggerInstance;globalConfig;featureCheck;middlewares=[];composedSend;mountedProviders=new Map;constructor(e,r){this.provider=e,this.featureCheck=r?.featureCheck??"error"}setLogger(e){return this.loggerInstance=e,this.logger=M("Mail",e),this}use(e){return this.middlewares.push(e),this.composedSend=void 0,this}mount(e,r){return this.mountedProviders.set(e,r),this}setFrom(e){return this.globalConfig??={},this.globalConfig.from=e,this.logger&&this.logger.debug("Default from address updated",{from:e.email}),this}setReplyTo(e){return this.globalConfig??={},this.globalConfig.replyTo=e,this.logger&&this.logger.debug("Default reply-to address updated",{replyTo:e.email}),this}setHeaders(e){if(this.globalConfig??={},this.globalConfig.headers=e,this.logger){const r=l(e);this.logger.debug("Default headers updated",{count:Object.keys(r).length,headers:Object.keys(r)})}return this}async draft(e){let r=e instanceof f||e instanceof h?await this.buildDraftFromMessage(e):await this.buildDraftFromOptions(e);r=this.applyGlobalConfig(r);const s=r.headers?l(r.headers):{};r.headers={...s,"X-Unsent":"1"};const t=await w(r,{includeBcc:!0});return this.logger&&this.logger.debug("Draft created successfully in EML format",{from:r.from.email,size:t.length,subject:r.subject,to:Array.isArray(r.to)?r.to.length:1}),t}async send(e){if(e instanceof h)throw new TypeError("Cannot send draft messages. Convert to MailMessage first or remove X-Unsent header.");let r;if(e instanceof f)this.logger&&this.logger.debug("Sending MailMessage instance"),this.loggerInstance&&e.setLogger(this.loggerInstance),r=await e.build();else{const o=e;this.logger&&this.logger.debug("Sending email with options",{subject:o.subject,to:Array.isArray(o.to)?o.to.length:1}),r=o}r=this.applyGlobalConfig(r);const s=this.assertFeatureSupport(r);if(s)return{error:s,success:!1};const t=await this.dispatch(r);return S(this.logger,t,this.provider.name??"unknown"),t}sendMany(e,r){const s=Math.max(1,Math.floor(r?.concurrency??1));return s===1?this.sendManySerial(e,r?.signal):this.sendManyConcurrent(e,s,r?.signal)}sendBatch(e,r,s){const t=async function*(){const o=e instanceof f?await e.build():e;for(const a of r)yield await j(o,a,s?.render)};return this.sendMany(t(),{concurrency:s?.concurrency,signal:s?.signal})}async sendOneToReceipt(e){const r=this.provider.name;try{const s=await this.send(e);return s.success&&s.data?{messageId:s.data.messageId,provider:s.data.provider??r,response:s.data.response,successful:!0,timestamp:s.data.timestamp}:{errorMessages:u.extractErrorMessages(s.error),provider:r,successful:!1}}catch(s){return{errorMessages:u.extractErrorMessages(s),provider:r,successful:!1}}}async*sendManySerial(e,r){const s=this.provider.name;let t=0,o=0,a=0;this.logger&&this.logger.debug("Starting batch email send",{provider:s});for await(const n of e){if(n instanceof h)throw new TypeError("Cannot send draft messages. Convert to MailMessage first or remove X-Unsent header.");if(r?.aborted){this.logger&&this.logger.warn("Batch send operation was aborted",{failed:a,processed:t,successful:o}),yield{errorMessages:["Send operation was aborted"],provider:s,successful:!1};return}t+=1;const g=await this.sendOneToReceipt(n);g.successful?o+=1:a+=1,yield g}this.logger&&this.logger.debug("Batch email send completed",{failureCount:a,processedCount:t,provider:s,successCount:o})}async*sendManyConcurrent(e,r,s){const t=this.provider.name;this.logger&&this.logger.debug("Starting concurrent batch email send",{concurrency:r,provider:t});const o=Symbol.asyncIterator in e?e[Symbol.asyncIterator]():e[Symbol.iterator](),a=new Map;let n=0,g=!1,p=!1;const m=async()=>{for(;!g&&!p&&a.size<r;){const d=await o.next();if(d.done){g=!0;break}const c=d.value;if(c instanceof h)throw new TypeError("Cannot send draft messages. Convert to MailMessage first or remove X-Unsent header.");const b=n;n+=1,a.set(b,this.sendOneToReceipt(c).then(y=>({id:b,receipt:y})))}};for(await m();a.size>0;){if(s?.aborted){p=!0,yield{errorMessages:["Send operation was aborted"],provider:t,successful:!1};return}const{id:d,receipt:c}=await Promise.race(a.values());a.delete(d),yield c,await m()}this.logger&&this.logger.debug("Concurrent batch email send completed",{processedCount:n,provider:t})}async dispatch(e){return this.middlewares.length===0?await this.resolveProvider(e).sendEmail(e):(this.composedSend??=C(this.middlewares,r=>Promise.resolve(this.resolveProvider(r).sendEmail(r))),await this.composedSend(e))}resolveProvider(e){return e.stream!==void 0?this.mountedProviders.get(e.stream)??this.provider:this.provider}assertFeatureSupport(e){if(this.featureCheck==="off")return;const{supported:r,violations:s}=T(e,this.provider.features);if(r)return;const t=this.provider.name??"unknown",o=s.map(n=>n.field),a=s.map(n=>n.message);if(this.featureCheck==="warn"){this.logger&&this.logger.warn("Message uses capabilities the provider does not support",{fields:o,provider:t});return}return this.logger&&this.logger.error("Message rejected by capability guard",{fields:o,provider:t}),new v(t,`Provider does not support the following message fields: ${o.join(", ")}`,{code:"UNSUPPORTED_FEATURES",hint:a})}async buildDraftFromMessage(e){return this.logger&&this.logger.debug("Creating draft from MailMessage instance"),this.loggerInstance&&e.setLogger(this.loggerInstance),this.applyGlobalConfigToMessage(e),await e.build()}async buildDraftFromOptions(e){return this.logger&&this.logger.debug("Creating draft from email options",{subject:e.subject,to:Array.isArray(e.to)?e.to.length:1}),e}applyGlobalConfigToMessage(e){const r=this.globalConfig?.from;r&&!e.getFrom()&&e.from(r);const s=this.globalConfig?.replyTo;if(s&&!e.getReplyTo()&&e.replyTo(s),this.globalConfig?.headers){const t=l(this.globalConfig.headers);Object.entries(t).forEach(([o,a])=>{e.header(o,a)})}}applyGlobalConfig(e){if(!this.globalConfig)return e;const r={...e};if(!r.from&&this.globalConfig.from&&(r.from=this.globalConfig.from,this.logger&&this.logger.debug("Applied global from address",{from:this.globalConfig.from.email})),!r.replyTo&&this.globalConfig.replyTo&&(r.replyTo=this.globalConfig.replyTo,this.logger&&this.logger.debug("Applied global reply-to address",{replyTo:this.globalConfig.replyTo.email})),this.globalConfig.headers){const s=l(this.globalConfig.headers),t=r.headers?l(r.headers):{};r.headers={...s,...t},this.logger&&this.logger.debug("Merged global headers",{globalCount:Object.keys(s).length,messageCount:Object.keys(t).length})}return r}}const D=(i,e)=>new u(i,e);export{u as Mail,D as createMail};
@@ -0,0 +1 @@
1
+ import c from"./EmailError-B-sEf3bp.js";import T from"./RequiredOptionError-DuNNY_a5.js";import{s as x}from"./headers-to-record-De1Eg951.js";import{m as z}from"./make-request-BlK_B72c.js";import{u as K}from"./retry-3pnxTuNs.js";import{s as P,a as G}from"./sanitize-header-DtQwAnzg.js";import{f as C}from"./validate-email-options-mCM9dVug.js";import{defineProvider as E}from"./defineProvider-C9q-7iwt.js";import{a as y,f as w}from"./address-formatter-BWR2Dddx.js";import{h as q,P as D,c as B}from"./provider-base-C7PuopYK.js";import{c as F}from"./attachment-processor-CMp7qqMI.js";const n="autosend",H="https://api.autosend.com/v1",N=3e4,R=3,v=50,$=20,A=40*1024*1024,k=20,I=1e3,j=998,Z=/^[A-Z0-9-]{1,76}$/i,J="^[A-Za-z0-9-]{1,76}$",L="Either text or html content is required",g=t=>[t].flat(),V=async t=>{const s=await F(t,n);return{content:s.content,contentType:s.contentType,fileName:s.filename}},U=(t,s)=>{const i=g(t.to);if(i.length!==1)return`AutoSend's send endpoint takes exactly one 'to' recipient, but ${String(i.length)} were given — use 'cc'/'bcc', or send one message per recipient`;const o=i.length+(t.cc?g(t.cc).length:0)+(t.bcc?g(t.bcc).length:0);if(o>v)return`AutoSend allows at most ${String(v)} recipients across to/cc/bcc, but ${String(o)} were given`;if(t.attachments&&t.attachments.length>$)return`AutoSend allows at most ${String($)} attachments, but ${String(t.attachments.length)} were given`;const e=t.attachments?.find(r=>r.cid);if(e)return`AutoSend does not support inline (cid) attachments, but '${e.filename}' sets one — host the image and reference it by URL instead`;if(t.subject.length>j)return`AutoSend allows a subject of at most ${String(j)} characters, but ${String(t.subject.length)} were given`;const a=Object.keys(s);if(a.length>k)return`AutoSend allows at most ${String(k)} custom headers, but ${String(a.length)} were given`;const d=a.find(r=>!Z.test(r));if(d!==void 0)return`AutoSend header names must match ${J}, but '${d}' does not`;const u=a.find(r=>s[r].length>I);if(u!==void 0)return`AutoSend allows header values of at most ${String(I)} characters, but '${u}' is longer`},X=t=>{if(typeof t!="object"||t===null)return{};const s=t;if(s.success===!0)return{emailId:typeof s.data?.emailId=="string"?s.data.emailId:void 0};const i=[s.message,s.error].find(o=>typeof o=="string");return{reason:typeof i=="string"?i:void 0}},ie=E((t={})=>{if(!t.apiKey)throw new T(n,"apiKey");const s={apiKey:t.apiKey,debug:t.debug??!1,endpoint:t.endpoint??H,logger:t.logger,retries:t.retries??R,timeout:t.timeout??N},i=new D,o=B(n,t.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!0,tracking:!0},async initialize(){i.setInitialized()},async isAvailable(){return s.apiKey.length>0},name:n,options:s,async sendEmail(e){try{const a=C(e).filter(l=>!(e.templateId!==void 0&&l===L));if(a.length>0)return{error:new c(n,`Invalid email options: ${a.join(", ")}`),success:!1};const d=e.headers?x(e.headers):{},u=U(e,d);if(u)return{error:new c(n,u),success:!1};const r={from:y(e.from),subject:e.subject,to:y(g(e.to)[0])};if(e.templateId?r.templateId=e.templateId:(e.html&&(r.html=e.html),e.text&&(r.text=e.text)),e.cc&&(r.cc=w(e.cc)),e.bcc&&(r.bcc=w(e.bcc)),e.replyTo&&(r.replyTo=y(e.replyTo)),e.dynamicData&&(r.dynamicData=e.dynamicData),e.unsubscribeGroupId&&(r.unsubscribeGroupId=e.unsubscribeGroupId),e.trackingClick!==void 0&&(r.trackingClick=e.trackingClick),e.trackingOpen!==void 0&&(r.trackingOpen=e.trackingOpen),e.bypassSuppressions!==void 0&&(r.bypassSuppressions=e.bypassSuppressions),Object.keys(d).length>0&&(r.headers=Object.fromEntries(Object.entries(d).map(([l,p])=>[P(l),G(p)]))),e.attachments&&e.attachments.length>0){const l=await Promise.all(e.attachments.map(async b=>V(b))),p=l.reduce((b,O)=>b+O.content.length,0);if(p>A)return{error:new c(n,`AutoSend allows at most ${String(A)} bytes of attachments after Base64 encoding, but this message carries ${String(p)}`),success:!1};r.attachments=l}const f=await K(async()=>z(`${s.endpoint}/mails/send`,{headers:{Authorization:`Bearer ${s.apiKey}`,"Content-Type":"application/json"},method:"POST",timeout:s.timeout},JSON.stringify(r)),s.retries),S=f.data?.body,{emailId:h,reason:m}=X(S);return f.success?m?{error:new c(n,`Failed to send email: ${m}`),success:!1}:h?(o.debug(`Email queued successfully: ${h}`),{data:{messageId:h,provider:n,response:S,sent:!0,timestamp:new Date},success:!0}):{error:new c(n,"AutoSend accepted the message but returned no emailId"),success:!1}:{error:m?new c(n,`Failed to send email: ${m}`):f.error??new c(n,"Failed to send email"),success:!1}}catch(a){return{error:q(n,"send email",a,o),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{ie as default};
@@ -1,4 +1,4 @@
1
- import{createRequire as D}from"node:module";import E from"./EmailError-B-sEf3bp.js";import L from"./RequiredOptionError-DuNNY_a5.js";import{c as F}from"./create-logger-BQTS3f-I.js";import f from"../utils/format-email-address.js";import{s as G}from"./headers-to-record-De1Eg951.js";import{m as Q}from"./make-request-BlK_B72c.js";import{s as q,a as X}from"./sanitize-header-DJhgZl3y.js";import{f as Y}from"./validate-email-options-mCM9dVug.js";import{defineProvider as Z}from"./defineProvider-C9q-7iwt.js";const N=D(import.meta.url),A=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,V=y=>{if(typeof A<"u"&&A.versions&&A.versions.node){const[a,d]=A.versions.node.split(".").map(Number);if(a>22||a===22&&d>=3||a===20&&d>=16)return A.getBuiltinModule(y)}return N(y)},{randomUUID:v,createHash:R,createHmac:$}=V("node:crypto"),J=globalThis.Buffer!==void 0,I=()=>{if(!J)throw new Error("Buffer is required for AWS SES provider");return globalThis.Buffer},h="aws-ses",j={apiVersion:"2010-12-01",maxAttempts:3,region:"us-east-1"},ue=Z((y={})=>{const a={...j,...y},d=F("AWS-SES",y.logger),P=(e,i,t,s,o)=>{const u=Object.keys(t).toSorted().map(c=>{const l=t[c];return l===void 0?"":`${encodeURIComponent(c)}=${encodeURIComponent(l)}`}).filter(Boolean).join("&"),r=`${Object.keys(s).toSorted().map(c=>`${c.toLowerCase()}:${s[c]}`).join(`
1
+ import{createRequire as D}from"node:module";import E from"./EmailError-B-sEf3bp.js";import L from"./RequiredOptionError-DuNNY_a5.js";import{c as F}from"./create-logger-BQTS3f-I.js";import f from"../utils/format-email-address.js";import{s as G}from"./headers-to-record-De1Eg951.js";import{m as Q}from"./make-request-BlK_B72c.js";import{a as q,s as X}from"./sanitize-header-DtQwAnzg.js";import{f as Y}from"./validate-email-options-mCM9dVug.js";import{defineProvider as Z}from"./defineProvider-C9q-7iwt.js";const N=D(import.meta.url),A=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,V=y=>{if(typeof A<"u"&&A.versions&&A.versions.node){const[a,d]=A.versions.node.split(".").map(Number);if(a>22||a===22&&d>=3||a===20&&d>=16)return A.getBuiltinModule(y)}return N(y)},{randomUUID:v,createHash:R,createHmac:$}=V("node:crypto"),J=globalThis.Buffer!==void 0,I=()=>{if(!J)throw new Error("Buffer is required for AWS SES provider");return globalThis.Buffer},h="aws-ses",j={apiVersion:"2010-12-01",maxAttempts:3,region:"us-east-1"},ue=Z((y={})=>{const a={...j,...y},d=F("AWS-SES",y.logger),P=(e,i,t,s,o)=>{const u=Object.keys(t).toSorted().map(c=>{const l=t[c];return l===void 0?"":`${encodeURIComponent(c)}=${encodeURIComponent(l)}`}).filter(Boolean).join("&"),r=`${Object.keys(s).toSorted().map(c=>`${c.toLowerCase()}:${s[c]}`).join(`
2
2
  `)}
3
3
  `,n=Object.keys(s).toSorted().map(c=>c.toLowerCase()).join(";"),g=R("sha256").update(o).digest("hex");return[e,i,u,r,n,g].join(`
4
4
  `)},W=(e,i,t)=>{const s=e.slice(0,8),o=R("sha256").update(t).digest("hex");return["AWS4-HMAC-SHA256",e,`${s}/${i}/ses/aws4_request`,o].join(`
@@ -1,3 +1,3 @@
1
- import v from"./EmailError-B-sEf3bp.js";import l from"../utils/format-email-address.js";import{r as F}from"./generate-boundary-DQbzDiOI.js";import{s as M}from"./headers-to-record-De1Eg951.js";import{f as g}from"./quoted-printable-nSGDA1tA.js";import{a as T,s as f}from"./sanitize-header-DJhgZl3y.js";const d=globalThis.Buffer!==void 0,$=t=>{if(typeof t=="string"){if(d)return Buffer.from(t,"utf8").toString("base64");const e=new TextEncoder().encode(t);let r="";const n=8192;for(let s=0;s<e.length;s+=n){const i=e.subarray(s,Math.min(s+n,e.length));r+=String.fromCharCode(...i)}return btoa(r)}if(d&&t instanceof Buffer)return t.toString("base64");const a=t instanceof Uint8Array?t:new Uint8Array(t);if(d)return Buffer.from(a).toString("base64");let h="";const o=8192;for(let e=0;e<a.length;e+=o){const r=a.subarray(e,Math.min(e+o,a.length));h+=String.fromCharCode(...r)}return btoa(h)},j=globalThis.Buffer!==void 0,A=/[^\u0000-\u007F]/,S=t=>!A.test(t),U=t=>{if(S(t))return t;const a=45,h=new TextDecoder,o=j?Buffer.from(t,"utf8"):new TextEncoder().encode(t),e=[];let r=0;for(;r<o.length;){let n=Math.min(r+a,o.length);if(n<o.length)for(;n>r&&(o[n]&192)===128;)n-=1;const s=o.subarray(r,n),i=h.decode(s);e.push(`=?UTF-8?B?${$(i)}?=`),r=n}return e.join(" ")},b=t=>Array.isArray(t)?t.map(a=>l(a)).join(", "):l(t),y=/[^ -]/,C=t=>U(f(t)),D=globalThis.Buffer!==void 0,x=t=>t.replaceAll(/.{1,76}/g,`$&\r
1
+ import v from"./EmailError-B-sEf3bp.js";import l from"../utils/format-email-address.js";import{r as F}from"./generate-boundary-DQbzDiOI.js";import{s as M}from"./headers-to-record-De1Eg951.js";import{f as g}from"./quoted-printable-nSGDA1tA.js";import{s as T,a as f}from"./sanitize-header-DtQwAnzg.js";const d=globalThis.Buffer!==void 0,$=t=>{if(typeof t=="string"){if(d)return Buffer.from(t,"utf8").toString("base64");const e=new TextEncoder().encode(t);let r="";const n=8192;for(let s=0;s<e.length;s+=n){const i=e.subarray(s,Math.min(s+n,e.length));r+=String.fromCharCode(...i)}return btoa(r)}if(d&&t instanceof Buffer)return t.toString("base64");const a=t instanceof Uint8Array?t:new Uint8Array(t);if(d)return Buffer.from(a).toString("base64");let h="";const o=8192;for(let e=0;e<a.length;e+=o){const r=a.subarray(e,Math.min(e+o,a.length));h+=String.fromCharCode(...r)}return btoa(h)},j=globalThis.Buffer!==void 0,A=/[^\u0000-\u007F]/,S=t=>!A.test(t),U=t=>{if(S(t))return t;const a=45,h=new TextDecoder,o=j?Buffer.from(t,"utf8"):new TextEncoder().encode(t),e=[];let r=0;for(;r<o.length;){let n=Math.min(r+a,o.length);if(n<o.length)for(;n>r&&(o[n]&192)===128;)n-=1;const s=o.subarray(r,n),i=h.decode(s);e.push(`=?UTF-8?B?${$(i)}?=`),r=n}return e.join(" ")},b=t=>Array.isArray(t)?t.map(a=>l(a)).join(", "):l(t),y=/[^ -]/,C=t=>U(f(t)),D=globalThis.Buffer!==void 0,x=t=>t.replaceAll(/.{1,76}/g,`$&\r
2
2
  `).trimEnd(),P=async(t,a={})=>{const{includeBcc:h=!1}=a,o=F(),e=[`From: ${l(t.from)}`,`To: ${b(t.to)}`];if(t.cc&&e.push(`Cc: ${b(t.cc)}`),h&&t.bcc&&e.push(`Bcc: ${b(t.bcc)}`),t.replyTo&&e.push(`Reply-To: ${l(t.replyTo)}`),e.push(`Subject: ${C(t.subject)}`,"MIME-Version: 1.0"),t.headers){const r=M(t.headers);Object.entries(r).forEach(([n,s])=>{const i=T(n),p=f(s);e.push(`${i}: ${p}`)})}if(e.push(`Content-Type: multipart/mixed; boundary="${o}"`,""),t.text&&(y.test(t.text)?e.push(`--${o}`,"Content-Type: text/plain; charset=UTF-8","Content-Transfer-Encoding: quoted-printable","",g(t.text),""):e.push(`--${o}`,"Content-Type: text/plain; charset=UTF-8","Content-Transfer-Encoding: 7bit","",t.text,"")),t.html&&(y.test(t.html)?e.push(`--${o}`,"Content-Type: text/html; charset=UTF-8","Content-Transfer-Encoding: quoted-printable","",g(t.html),""):e.push(`--${o}`,"Content-Type: text/html; charset=UTF-8","Content-Transfer-Encoding: 7bit","",t.html,"")),t.attachments&&t.attachments.length>0){const r=await Promise.all(t.attachments.map(async n=>{let s;if(n.raw!==void 0)s=n.raw;else{if(n.content===void 0)throw new v("attachment",`Attachment '${n.filename}' must have content, raw, or be resolved from path/href before building MIME message`);s=n.content instanceof Promise?await n.content:n.content}return{...n,resolvedContent:s}}));for(const n of r){e.push(`--${o}`);const s=f(n.contentType??"application/octet-stream"),i=C(n.filename);e.push(`Content-Type: ${s}; name="${i}"`);const p=f(n.contentDisposition??"attachment");e.push(`Content-Disposition: ${p}; filename="${i}"`),n.cid&&e.push(`Content-ID: <${f(n.cid)}>`),n.headers&&Object.entries(n.headers).forEach(([m,w])=>{const B=T(m),E=f(w);e.push(`${B}: ${E}`)});const u=f(n.encoding??"base64");e.push(`Content-Transfer-Encoding: ${u}`,"");const c=n.resolvedContent;if(u==="base64")e.push(x($(c)));else if(u==="7bit"||u==="8bit")if(typeof c=="string")e.push(c);else if(D&&c instanceof Buffer)e.push(c.toString("utf8"));else{const m=new TextDecoder;e.push(m.decode(c))}else e.push(x($(c)));e.push("")}}return e.push(`--${o}--`),e.join(`\r
3
3
  `)};export{P as F};
@@ -1 +1 @@
1
- import a from"./EmailError-B-sEf3bp.js";import m from"./RequiredOptionError-DuNNY_a5.js";import{F as d}from"./build-mime-message-B6927SQy.js";import{e as f}from"./generate-message-id-gXAuMz4g.js";import{s as u}from"./headers-to-record-De1Eg951.js";import{f as p}from"./validate-email-options-mCM9dVug.js";import{defineProvider as g}from"./defineProvider-C9q-7iwt.js";import{h,c as v}from"./provider-base-C7PuopYK.js";const r="cloudflare-email",C=g((t={})=>{if(typeof t.send!="function")throw new m(r,"send");const c=v(r,t.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!1},async initialize(){await Promise.resolve()},async isAvailable(){return typeof t.send=="function"},name:r,async sendEmail(e){try{const s=p(e);if(s.length>0)return{error:new a(r,`Invalid email options: ${s.join(", ")}`),success:!1};const i=Array.isArray(e.to)?e.to:[e.to];if(i.length!==1||e.cc!==void 0||e.bcc!==void 0)return{error:new a(r,"Cloudflare Email supports exactly one `to` recipient and does not support cc/bcc"),success:!1};const[o]=i;if(!o)return{error:new a(r,"A single `to` recipient is required"),success:!1};const n=f(),l=await d({...e,headers:{...e.headers?u(e.headers):{},"Message-ID":n}});return await t.send(e.from.email,o.email,l),{data:{messageId:n,provider:r,sent:!0,timestamp:new Date},success:!0}}catch(s){return{error:h(r,"send email",s,c),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{C as default};
1
+ import a from"./EmailError-B-sEf3bp.js";import m from"./RequiredOptionError-DuNNY_a5.js";import{F as d}from"./build-mime-message-BW5FQ2Bt.js";import{e as f}from"./generate-message-id-gXAuMz4g.js";import{s as u}from"./headers-to-record-De1Eg951.js";import{f as p}from"./validate-email-options-mCM9dVug.js";import{defineProvider as g}from"./defineProvider-C9q-7iwt.js";import{h,c as v}from"./provider-base-C7PuopYK.js";const r="cloudflare-email",C=g((t={})=>{if(typeof t.send!="function")throw new m(r,"send");const c=v(r,t.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!1},async initialize(){await Promise.resolve()},async isAvailable(){return typeof t.send=="function"},name:r,async sendEmail(e){try{const s=p(e);if(s.length>0)return{error:new a(r,`Invalid email options: ${s.join(", ")}`),success:!1};const i=Array.isArray(e.to)?e.to:[e.to];if(i.length!==1||e.cc!==void 0||e.bcc!==void 0)return{error:new a(r,"Cloudflare Email supports exactly one `to` recipient and does not support cc/bcc"),success:!1};const[o]=i;if(!o)return{error:new a(r,"A single `to` recipient is required"),success:!1};const n=f(),l=await d({...e,headers:{...e.headers?u(e.headers):{},"Message-ID":n}});return await t.send(e.from.email,o.email,l),{data:{messageId:n,provider:r,sent:!0,timestamp:new Date},success:!0}}catch(s){return{error:h(r,"send email",s,c),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{C as default};
@@ -0,0 +1 @@
1
+ const w=(a,s={})=>{const{now:i=Date.now,skewMs:o=6e4}=s,c=Math.max(0,o);let t,n;const r=e=>e.expiresAt===void 0||e.expiresAt-c>i();return async()=>t&&r(t)?t:(n??=a().then(e=>(t=e,e)).finally(()=>{n=void 0}),await n)};export{w as d};
@@ -1 +1 @@
1
- import{createMail as w}from"./Mail-C1zp-fqt.js";import u from"./mockProvider-Behywbl1.js";const d=(t,o,e,n)=>{const r=Date.now()+e;return new Promise((s,c)=>{const a=()=>{const i=t.find(m=>o(m));if(i){s(i);return}if(Date.now()>=r){c(new Error("waitFor timed out before a matching message was captured"));return}setTimeout(a,n)};a()})},l=()=>{const t=u(),o=w(t),e=t.getInstance?.();if(!e)throw new Error("mockProvider() did not expose getInstance(); cannot create a test harness");return{mail:o,reset:()=>{e.length=0},sent:()=>e,waitFor:(n,r={})=>d(e,n,r.timeout??1e3,r.interval??10)}};export{l as createTestEmail};
1
+ import{createMail as w}from"./Mail-CYAwMRnX.js";import u from"./mockProvider-Behywbl1.js";const d=(t,o,e,n)=>{const r=Date.now()+e;return new Promise((s,c)=>{const a=()=>{const i=t.find(m=>o(m));if(i){s(i);return}if(Date.now()>=r){c(new Error("waitFor timed out before a matching message was captured"));return}setTimeout(a,n)};a()})},l=()=>{const t=u(),o=w(t),e=t.getInstance?.();if(!e)throw new Error("mockProvider() did not expose getInstance(); cannot create a test harness");return{mail:o,reset:()=>{e.length=0},sent:()=>e,waitFor:(n,r={})=>d(e,n,r.timeout??1e3,r.interval??10)}};export{l as createTestEmail};
@@ -1 +1 @@
1
- import{defineProvider as l}from"./defineProvider-C9q-7iwt.js";import o from"./smtpProvider-Bm0yP97W.js";const s="mailcrab",u="localhost",n=1025,g=l((t={})=>{const e={debug:t.debug??!1,host:t.host??u,logger:t.logger,port:t.port??n,retries:t.retries,secure:t.secure??!1,timeout:t.timeout},a=o({debug:e.debug,host:e.host,logger:e.logger,port:e.port,retries:e.retries,secure:e.secure,timeout:e.timeout});return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!1},async initialize(){await a.initialize()},async isAvailable(){return a.isAvailable()},name:s,options:e,async sendEmail(i){const r=await a.sendEmail(i);return r.success&&r.data?{data:{...r.data,provider:s},success:!0}:r},async validateCredentials(){return a.validateCredentials?.()??!1}}});export{g as default};
1
+ import{defineProvider as l}from"./defineProvider-C9q-7iwt.js";import o from"./smtpProvider-5MI3-EPh.js";const s="mailcrab",u="localhost",n=1025,g=l((t={})=>{const e={debug:t.debug??!1,host:t.host??u,logger:t.logger,port:t.port??n,retries:t.retries,secure:t.secure??!1,timeout:t.timeout},a=o({debug:e.debug,host:e.host,logger:e.logger,port:e.port,retries:e.retries,secure:e.secure,timeout:e.timeout});return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!1},async initialize(){await a.initialize()},async isAvailable(){return a.isAvailable()},name:s,options:e,async sendEmail(i){const r=await a.sendEmail(i);return r.success&&r.data?{data:{...r.data,provider:s},success:!0}:r},async validateCredentials(){return a.validateCredentials?.()??!1}}});export{g as default};
@@ -1 +1 @@
1
- import c from"./EmailError-B-sEf3bp.js";import P from"./RequiredOptionError-DuNNY_a5.js";import{e as I}from"./generate-message-id-gXAuMz4g.js";import{s as T}from"./headers-to-record-De1Eg951.js";import{m as d}from"./make-request-BlK_B72c.js";import{u as g}from"./retry-3pnxTuNs.js";import{a as A,s as k}from"./sanitize-header-DJhgZl3y.js";import{f as z}from"./validate-email-options-mCM9dVug.js";import{defineProvider as j}from"./defineProvider-C9q-7iwt.js";import{P as E,h as f,c as C}from"./provider-base-C7PuopYK.js";import{j as u,g as h}from"./address-formatter-BWR2Dddx.js";const r="mailpace",M="https://app.mailpace.com/api/v1",S=3e4,q=3,R=j((o={})=>{if(!o.apiToken)throw new P(r,"apiToken");const s={apiToken:o.apiToken,debug:o.debug??!1,endpoint:o.endpoint??M,retries:o.retries??q,timeout:o.timeout??S,...o.logger&&{logger:o.logger}},l=new E,i=C(r,o.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!0,templates:!0,tracking:!1},async getEmail(e){try{if(!e)return{error:new c(r,"Email ID is required to retrieve email details"),success:!1};await l.ensureInitialized(()=>this.initialize(),r);const a={Authorization:`Bearer ${s.apiToken}`,"Content-Type":"application/json"};i.debug("Retrieving email details",{id:e});const t=await g(async()=>d(`${s.endpoint}/emails/${e}`,{headers:a,method:"GET",timeout:s.timeout}),s.retries);return t.success?(i.debug("Email details retrieved successfully"),{data:t.data?.body,success:!0}):(i.debug("API request failed when retrieving email",t.error),{error:new c(r,`Failed to retrieve email: ${t.error instanceof Error?t.error.message:"Unknown error"}`,{cause:t.error}),success:!1})}catch(a){return{error:f(r,"retrieve email",a,i),success:!1}}},async initialize(){await l.ensureInitialized(async()=>{if(!await this.isAvailable())throw new c(r,"MailPace API not available or invalid API token");i.debug("Provider initialized successfully")},r)},async isAvailable(){try{const e={Authorization:`Bearer ${s.apiToken}`,"Content-Type":"application/json"};i.debug("Checking MailPace API availability");const a=await d(`${s.endpoint}/account`,{headers:e,method:"GET",timeout:s.timeout});return i.debug("MailPace API availability check response:",{error:a.error instanceof Error?a.error.message:void 0,statusCode:a.data?.statusCode,success:a.success}),!!(a.success&&a.data&&typeof a.data=="object"&&"statusCode"in a.data&&typeof a.data.statusCode=="number"&&a.data.statusCode>=200&&a.data.statusCode<300)}catch(e){return i.debug("Error checking availability:",e),!1}},name:r,options:s,async sendEmail(e){try{const a=z(e);if(a.length>0)return{error:new c(r,`Invalid email options: ${a.join(", ")}`),success:!1};await l.ensureInitialized(()=>this.initialize(),r);const t={from:h(e.from),subject:e.subject,to:u(e.to)};if(e.html&&(t.htmlbody=e.html),e.text&&(t.textbody=e.text),e.cc&&(t.cc=u(e.cc)),e.bcc&&(t.bcc=u(e.bcc)),e.replyTo&&(t.replyto=h(e.replyTo)),e.templateId&&(t.template_id=e.templateId,e.templateVariables&&(t.template_variables=e.templateVariables)),e.tags&&e.tags.length>0&&(t.tags=e.tags),e.listUnsubscribe&&(t.list_unsubscribe=e.listUnsubscribe),e.headers){const y=T(e.headers),p={};Object.entries(y).forEach(([v,w])=>{p[A(v)]=k(w)}),t.headers=p}e.attachments&&e.attachments.length>0&&(t.attachments=e.attachments),i.debug("Sending email via MailPace API",{subject:t.subject,to:t.to});const b={Authorization:`Bearer ${s.apiToken}`,"Content-Type":"application/json"},n=await g(async()=>d(`${s.endpoint}/send`,{headers:b,method:"POST",timeout:s.timeout},JSON.stringify(t)),s.retries);if(!n.success)return i.debug("API request failed when sending email",n.error),{error:n.error??new c(r,"Failed to send email"),success:!1};const m=n.data?.body?.id??I();return i.debug("Email sent successfully",{messageId:m}),{data:{messageId:m,provider:r,response:n.data,sent:!0,timestamp:new Date},success:!0}}catch(a){return{error:f(r,"send email",a,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{R as default};
1
+ import c from"./EmailError-B-sEf3bp.js";import P from"./RequiredOptionError-DuNNY_a5.js";import{e as I}from"./generate-message-id-gXAuMz4g.js";import{s as T}from"./headers-to-record-De1Eg951.js";import{m as d}from"./make-request-BlK_B72c.js";import{u as g}from"./retry-3pnxTuNs.js";import{s as A,a as k}from"./sanitize-header-DtQwAnzg.js";import{f as z}from"./validate-email-options-mCM9dVug.js";import{defineProvider as j}from"./defineProvider-C9q-7iwt.js";import{P as E,h as f,c as C}from"./provider-base-C7PuopYK.js";import{j as u,g as h}from"./address-formatter-BWR2Dddx.js";const r="mailpace",M="https://app.mailpace.com/api/v1",S=3e4,q=3,R=j((o={})=>{if(!o.apiToken)throw new P(r,"apiToken");const s={apiToken:o.apiToken,debug:o.debug??!1,endpoint:o.endpoint??M,retries:o.retries??q,timeout:o.timeout??S,...o.logger&&{logger:o.logger}},l=new E,i=C(r,o.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!0,templates:!0,tracking:!1},async getEmail(e){try{if(!e)return{error:new c(r,"Email ID is required to retrieve email details"),success:!1};await l.ensureInitialized(()=>this.initialize(),r);const a={Authorization:`Bearer ${s.apiToken}`,"Content-Type":"application/json"};i.debug("Retrieving email details",{id:e});const t=await g(async()=>d(`${s.endpoint}/emails/${e}`,{headers:a,method:"GET",timeout:s.timeout}),s.retries);return t.success?(i.debug("Email details retrieved successfully"),{data:t.data?.body,success:!0}):(i.debug("API request failed when retrieving email",t.error),{error:new c(r,`Failed to retrieve email: ${t.error instanceof Error?t.error.message:"Unknown error"}`,{cause:t.error}),success:!1})}catch(a){return{error:f(r,"retrieve email",a,i),success:!1}}},async initialize(){await l.ensureInitialized(async()=>{if(!await this.isAvailable())throw new c(r,"MailPace API not available or invalid API token");i.debug("Provider initialized successfully")},r)},async isAvailable(){try{const e={Authorization:`Bearer ${s.apiToken}`,"Content-Type":"application/json"};i.debug("Checking MailPace API availability");const a=await d(`${s.endpoint}/account`,{headers:e,method:"GET",timeout:s.timeout});return i.debug("MailPace API availability check response:",{error:a.error instanceof Error?a.error.message:void 0,statusCode:a.data?.statusCode,success:a.success}),!!(a.success&&a.data&&typeof a.data=="object"&&"statusCode"in a.data&&typeof a.data.statusCode=="number"&&a.data.statusCode>=200&&a.data.statusCode<300)}catch(e){return i.debug("Error checking availability:",e),!1}},name:r,options:s,async sendEmail(e){try{const a=z(e);if(a.length>0)return{error:new c(r,`Invalid email options: ${a.join(", ")}`),success:!1};await l.ensureInitialized(()=>this.initialize(),r);const t={from:h(e.from),subject:e.subject,to:u(e.to)};if(e.html&&(t.htmlbody=e.html),e.text&&(t.textbody=e.text),e.cc&&(t.cc=u(e.cc)),e.bcc&&(t.bcc=u(e.bcc)),e.replyTo&&(t.replyto=h(e.replyTo)),e.templateId&&(t.template_id=e.templateId,e.templateVariables&&(t.template_variables=e.templateVariables)),e.tags&&e.tags.length>0&&(t.tags=e.tags),e.listUnsubscribe&&(t.list_unsubscribe=e.listUnsubscribe),e.headers){const y=T(e.headers),p={};Object.entries(y).forEach(([v,w])=>{p[A(v)]=k(w)}),t.headers=p}e.attachments&&e.attachments.length>0&&(t.attachments=e.attachments),i.debug("Sending email via MailPace API",{subject:t.subject,to:t.to});const b={Authorization:`Bearer ${s.apiToken}`,"Content-Type":"application/json"},n=await g(async()=>d(`${s.endpoint}/send`,{headers:b,method:"POST",timeout:s.timeout},JSON.stringify(t)),s.retries);if(!n.success)return i.debug("API request failed when sending email",n.error),{error:n.error??new c(r,"Failed to send email"),success:!1};const m=n.data?.body?.id??I();return i.debug("Email sent successfully",{messageId:m}),{data:{messageId:m,provider:r,response:n.data,sent:!0,timestamp:new Date},success:!0}}catch(a){return{error:f(r,"send email",a,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{R as default};
@@ -1 +1 @@
1
- import d from"./EmailError-B-sEf3bp.js";import P from"./RequiredOptionError-DuNNY_a5.js";import{e as C}from"./generate-message-id-gXAuMz4g.js";import{s as j}from"./headers-to-record-De1Eg951.js";import{m as g}from"./make-request-BlK_B72c.js";import{u as y}from"./retry-3pnxTuNs.js";import{s as h,a as I}from"./sanitize-header-DJhgZl3y.js";import{f as T}from"./validate-email-options-mCM9dVug.js";import{defineProvider as _}from"./defineProvider-C9q-7iwt.js";import{P as k,h as b,c as z}from"./provider-base-C7PuopYK.js";import{k as p}from"./address-formatter-BWR2Dddx.js";import{p as E}from"./attachment-processor-CMp7qqMI.js";const a="mandrill",S="https://mandrillapp.com/api/1.0",K=3e4,M=3,B=_((l={})=>{if(!l.apiKey)throw new P(a,"apiKey");const s={apiKey:l.apiKey,debug:l.debug??!1,endpoint:l.endpoint??S,retries:l.retries??M,timeout:l.timeout??K,...l.logger&&{logger:l.logger}},u=new k,i=z(a,l.logger);return{features:{attachments:!0,batchSending:!0,customHeaders:!0,html:!0,replyTo:!0,scheduling:!0,tagging:!0,templates:!0,tracking:!0},async getEmail(e){try{if(!e)return{error:new d(a,"Email ID is required to retrieve email details"),success:!1};await u.ensureInitialized(()=>this.initialize(),a),i.debug("Retrieving email details",{id:e});const n={id:e,key:s.apiKey},t={"Content-Type":"application/json"},o=await y(async()=>g(`${s.endpoint}/messages/info.json`,{headers:t,method:"POST",timeout:s.timeout},JSON.stringify(n)),s.retries);return o.success?(i.debug("Email details retrieved successfully"),{data:o.data?.body,success:!0}):(i.debug("API request failed when retrieving email",o.error),{error:new d(a,`Failed to retrieve email: ${o.error instanceof Error?o.error.message:"Unknown error"}`,{cause:o.error}),success:!1})}catch(n){return{error:b(a,"retrieve email",n,i),success:!1}}},async initialize(){await u.ensureInitialized(async()=>{if(!await this.isAvailable())throw new d(a,"Mandrill API not available or invalid API key");i.debug("Provider initialized successfully")},a)},async isAvailable(){try{i.debug("Checking Mandrill API availability");const e={key:s.apiKey},n={"Content-Type":"application/json"},t=await g(`${s.endpoint}/users/info.json`,{headers:n,method:"POST",timeout:s.timeout},JSON.stringify(e));return i.debug("Mandrill API availability check response:",{error:t.error instanceof Error?t.error.message:void 0,statusCode:t.data?.statusCode,success:t.success}),!!(t.success&&t.data&&typeof t.data=="object"&&"statusCode"in t.data&&typeof t.data.statusCode=="number"&&t.data.statusCode>=200&&t.data.statusCode<300)}catch(e){return i.debug("Error checking availability:",e),!1}},name:a,options:s,async sendEmail(e){try{const n=T(e);if(n.length>0)return{error:new d(a,`Invalid email options: ${n.join(", ")}`),success:!1};await u.ensureInitialized(()=>this.initialize(),a);const t={from_email:e.from.email,html:e.html??"",subject:e.subject,text:e.text??"",...e.from.name&&{from_name:e.from.name},to:p(e.to,"to")};if(e.cc){const r=p(e.cc,"cc");for(const c of r)c.type="cc";t.to=[...t.to,...r]}if(e.bcc){const r=p(e.bcc,"bcc");for(const c of r)c.type="bcc";t.to=[...t.to,...r]}if(e.replyTo){const r=e.replyTo.name?`${h(e.replyTo.name)} <${e.replyTo.email}>`:e.replyTo.email;t.headers={"Reply-To":r}}if(e.headers){const r=j(e.headers),c={};Object.entries(r).forEach(([w,A])=>{c[I(w)]=h(A)}),t.headers={...t.headers,...c}}e.tags&&e.tags.length>0&&(t.tags=e.tags),e.metadata&&(t.metadata=e.metadata),(e.googleAnalyticsDomains||e.googleAnalyticsCampaign)&&(t.google_analytics_domains=e.googleAnalyticsDomains,t.google_analytics_campaign=e.googleAnalyticsCampaign),e.subaccount&&(t.subaccount=e.subaccount),e.attachments&&e.attachments.length>0&&(t.attachments=await Promise.all(e.attachments.map(async r=>({content:await E(r,a),name:r.filename,type:r.contentType??"application/octet-stream"}))));const o={key:s.apiKey,message:t};e.templateName&&(o.template_name=e.templateName,e.templateContent&&(o.template_content=e.templateContent),e.templateVariables&&(o.template_vars=e.templateVariables)),e.globalMergeVars&&(t.global_merge_vars=e.globalMergeVars),e.mergeVars&&(t.merge_vars=e.mergeVars),e.sendAt&&(o.send_at=e.sendAt),i.debug("Sending email via Mandrill API",{subject:t.subject,to:t.to});const v={"Content-Type":"application/json"},m=await y(async()=>g(`${s.endpoint}/messages/send.json`,{headers:v,method:"POST",timeout:s.timeout},JSON.stringify(o)),s.retries);if(!m.success)return i.debug("API request failed when sending email",m.error),{error:m.error??new d(a,"Failed to send email"),success:!1};const f=m.data?.body?.[0]?.id??C();return i.debug("Email sent successfully",{messageId:f}),{data:{messageId:f,provider:a,response:m.data,sent:!0,timestamp:new Date},success:!0}}catch(n){return{error:b(a,"send email",n,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{B as default};
1
+ import d from"./EmailError-B-sEf3bp.js";import P from"./RequiredOptionError-DuNNY_a5.js";import{e as C}from"./generate-message-id-gXAuMz4g.js";import{s as j}from"./headers-to-record-De1Eg951.js";import{m as g}from"./make-request-BlK_B72c.js";import{u as y}from"./retry-3pnxTuNs.js";import{a as h,s as I}from"./sanitize-header-DtQwAnzg.js";import{f as T}from"./validate-email-options-mCM9dVug.js";import{defineProvider as _}from"./defineProvider-C9q-7iwt.js";import{P as k,h as b,c as z}from"./provider-base-C7PuopYK.js";import{k as p}from"./address-formatter-BWR2Dddx.js";import{p as E}from"./attachment-processor-CMp7qqMI.js";const a="mandrill",S="https://mandrillapp.com/api/1.0",K=3e4,M=3,B=_((l={})=>{if(!l.apiKey)throw new P(a,"apiKey");const s={apiKey:l.apiKey,debug:l.debug??!1,endpoint:l.endpoint??S,retries:l.retries??M,timeout:l.timeout??K,...l.logger&&{logger:l.logger}},u=new k,i=z(a,l.logger);return{features:{attachments:!0,batchSending:!0,customHeaders:!0,html:!0,replyTo:!0,scheduling:!0,tagging:!0,templates:!0,tracking:!0},async getEmail(e){try{if(!e)return{error:new d(a,"Email ID is required to retrieve email details"),success:!1};await u.ensureInitialized(()=>this.initialize(),a),i.debug("Retrieving email details",{id:e});const n={id:e,key:s.apiKey},t={"Content-Type":"application/json"},o=await y(async()=>g(`${s.endpoint}/messages/info.json`,{headers:t,method:"POST",timeout:s.timeout},JSON.stringify(n)),s.retries);return o.success?(i.debug("Email details retrieved successfully"),{data:o.data?.body,success:!0}):(i.debug("API request failed when retrieving email",o.error),{error:new d(a,`Failed to retrieve email: ${o.error instanceof Error?o.error.message:"Unknown error"}`,{cause:o.error}),success:!1})}catch(n){return{error:b(a,"retrieve email",n,i),success:!1}}},async initialize(){await u.ensureInitialized(async()=>{if(!await this.isAvailable())throw new d(a,"Mandrill API not available or invalid API key");i.debug("Provider initialized successfully")},a)},async isAvailable(){try{i.debug("Checking Mandrill API availability");const e={key:s.apiKey},n={"Content-Type":"application/json"},t=await g(`${s.endpoint}/users/info.json`,{headers:n,method:"POST",timeout:s.timeout},JSON.stringify(e));return i.debug("Mandrill API availability check response:",{error:t.error instanceof Error?t.error.message:void 0,statusCode:t.data?.statusCode,success:t.success}),!!(t.success&&t.data&&typeof t.data=="object"&&"statusCode"in t.data&&typeof t.data.statusCode=="number"&&t.data.statusCode>=200&&t.data.statusCode<300)}catch(e){return i.debug("Error checking availability:",e),!1}},name:a,options:s,async sendEmail(e){try{const n=T(e);if(n.length>0)return{error:new d(a,`Invalid email options: ${n.join(", ")}`),success:!1};await u.ensureInitialized(()=>this.initialize(),a);const t={from_email:e.from.email,html:e.html??"",subject:e.subject,text:e.text??"",...e.from.name&&{from_name:e.from.name},to:p(e.to,"to")};if(e.cc){const r=p(e.cc,"cc");for(const c of r)c.type="cc";t.to=[...t.to,...r]}if(e.bcc){const r=p(e.bcc,"bcc");for(const c of r)c.type="bcc";t.to=[...t.to,...r]}if(e.replyTo){const r=e.replyTo.name?`${h(e.replyTo.name)} <${e.replyTo.email}>`:e.replyTo.email;t.headers={"Reply-To":r}}if(e.headers){const r=j(e.headers),c={};Object.entries(r).forEach(([w,A])=>{c[I(w)]=h(A)}),t.headers={...t.headers,...c}}e.tags&&e.tags.length>0&&(t.tags=e.tags),e.metadata&&(t.metadata=e.metadata),(e.googleAnalyticsDomains||e.googleAnalyticsCampaign)&&(t.google_analytics_domains=e.googleAnalyticsDomains,t.google_analytics_campaign=e.googleAnalyticsCampaign),e.subaccount&&(t.subaccount=e.subaccount),e.attachments&&e.attachments.length>0&&(t.attachments=await Promise.all(e.attachments.map(async r=>({content:await E(r,a),name:r.filename,type:r.contentType??"application/octet-stream"}))));const o={key:s.apiKey,message:t};e.templateName&&(o.template_name=e.templateName,e.templateContent&&(o.template_content=e.templateContent),e.templateVariables&&(o.template_vars=e.templateVariables)),e.globalMergeVars&&(t.global_merge_vars=e.globalMergeVars),e.mergeVars&&(t.merge_vars=e.mergeVars),e.sendAt&&(o.send_at=e.sendAt),i.debug("Sending email via Mandrill API",{subject:t.subject,to:t.to});const v={"Content-Type":"application/json"},m=await y(async()=>g(`${s.endpoint}/messages/send.json`,{headers:v,method:"POST",timeout:s.timeout},JSON.stringify(o)),s.retries);if(!m.success)return i.debug("API request failed when sending email",m.error),{error:m.error??new d(a,"Failed to send email"),success:!1};const f=m.data?.body?.[0]?.id??C();return i.debug("Email sent successfully",{messageId:f}),{data:{messageId:f,provider:a,response:m.data,sent:!0,timestamp:new Date},success:!0}}catch(n){return{error:b(a,"send email",n,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{B as default};
@@ -0,0 +1 @@
1
+ import{d as k}from"./create-token-cache-D56KQGVQ.js";import{s as m}from"./headers-to-record-De1Eg951.js";const p=r=>{const{fetchToken:o,headerName:a="Authorization",now:n=Date.now,onToken:s,scheme:t="Bearer",skewMs:c=6e4}=r,h=k(async()=>{const e=await o();return s?.(e),e},{now:n,skewMs:c});return async(e,i)=>{const w=await h(),d=e.headers?m(e.headers):{};return i({...e,headers:{...d,[a]:`${t} ${w.accessToken}`}})}};export{p as oauth2Middleware};
@@ -0,0 +1 @@
1
+ import m from"./EmailError-B-sEf3bp.js";import{e as _}from"./generate-message-id-gXAuMz4g.js";import{m as S}from"./make-request-BlK_B72c.js";import{u as v}from"./retry-3pnxTuNs.js";import{f as A}from"./validate-email-options-mCM9dVug.js";import{defineProvider as C}from"./defineProvider-C9q-7iwt.js";import p from"./RequiredOptionError-DuNNY_a5.js";import{d as x}from"./create-token-cache-D56KQGVQ.js";import{c as M}from"./attachment-processor-CMp7qqMI.js";import{h as P,P as R,c as j}from"./provider-base-C7PuopYK.js";const b="https://login.microsoftonline.com",E=6e4,O=3e4,L=3,q=300,z="https://graph.microsoft.com/.default",D=["https://graph.microsoft.com/Mail.Send","offline_access"],F={accessToken:["clientId","clientSecret","refreshToken","tenantId"],clientCredentials:["refreshToken"],getAccessToken:["accessToken","clientId","clientSecret","refreshToken","tenantId"],refreshToken:[]},N=e=>{let t=e.length;for(;t>0&&e[t-1]==="/";)t-=1;return e.slice(0,t)},U=(e,t)=>{if(e.getAccessToken)return"getAccessToken";if(e.accessToken)return"accessToken";if(e.refreshToken)return"refreshToken";if(e.clientSecret)return"clientCredentials";throw new p(t,["accessToken","getAccessToken","clientSecret","refreshToken"])},$=(e,t,c)=>{const n=e.authMode??U(e,t),h=F[n].filter(a=>e[a]!==void 0);if(h.length>0&&c.warn(`The '${n}' auth mode ignores these configured options: ${h.join(", ")}. Set 'authMode' to pin the intended flow.`),n==="getAccessToken"){const{getAccessToken:a}=e;if(!a)throw new p(t,"getAccessToken");return{getToken:async()=>a(),mode:n}}if(n==="accessToken"){const{accessToken:a}=e;if(!a)throw new p(t,"accessToken");return{getToken:()=>Promise.resolve(a),mode:n}}const{clientId:f,clientSecret:r,refreshToken:i,tenantId:d}=e,o=[];if(d||o.push("tenantId"),f||o.push("clientId"),n==="clientCredentials"&&!r&&o.push("clientSecret"),n==="refreshToken"&&!i&&o.push("refreshToken"),!d||!f)throw new p(t,o);if(n==="clientCredentials"){if(!r)throw new p(t,o);return{clientId:f,clientSecret:r,mode:n,tenantId:d}}if(!i)throw new p(t,o);return{clientId:f,clientSecret:r,mode:n,refreshToken:i,tenantId:d}},B=(e,t,c)=>{if(typeof e!="object"||e===null)throw new m(t,`Token endpoint returned a non-JSON response (status ${String(c)})`);const n=e;if(typeof n.error=="string"){const h=typeof n.error_description=="string"?n.error_description:"no description provided";throw new m(t,`Token request failed: ${n.error} — ${h}`,{code:n.error,hint:"Check the tenantId, clientId and client secret / refresh token in the Azure app registration."})}if(typeof n.access_token!="string")throw new m(t,`Token endpoint response did not contain an access_token (status ${String(c)})`);return{accessToken:n.access_token,expiresIn:typeof n.expires_in=="number"?n.expires_in:q,refreshToken:typeof n.refresh_token=="string"?n.refresh_token:void 0}},H=e=>e===0||e===408||e===429||e>=500,J=(e,t,c,n)=>{if(e.mode==="accessToken"||e.mode==="getAccessToken")return e.getToken;const h=`${N(t.authority??b)}/${e.tenantId}/oauth2/v2.0/token`,f=t.timeout??O,r=t.retries??L,i=t.now??Date.now;let d=e.mode==="refreshToken"?e.refreshToken:void 0;const o=()=>{const s=new URLSearchParams({client_id:e.clientId,scope:(t.scopes??(e.mode==="clientCredentials"?[z]:D)).join(" ")});return e.clientSecret&&s.set("client_secret",e.clientSecret),e.mode==="clientCredentials"?s.set("grant_type","client_credentials"):(s.set("grant_type","refresh_token"),s.set("refresh_token",d)),s.toString()},a=s=>s.data?.statusCode??0,k=async()=>{const s=await S(h,{headers:{"Content-Type":"application/x-www-form-urlencoded"},method:"POST",timeout:f},o());return!s.success&&H(a(s))?s:{data:s.data,success:!0}},T=async s=>{if(d=s,!!t.onRefreshToken)try{await t.onRefreshToken(s)}catch(u){n.error(`Failed to persist the rotated refresh token — the stored token is stale and sending will fail after a restart: ${u instanceof Error?u.message:String(u)}`)}},g=x(async()=>{const s=await v(k,r),u=s.data?.body;if(!s.success&&(typeof u!="object"||u===null))throw s.error instanceof Error?s.error:new m(c,"Token request failed");const w=B(u,c,a(s));return w.refreshToken&&w.refreshToken!==d&&await T(w.refreshToken),{accessToken:w.accessToken,expiresAt:i()+w.expiresIn*1e3}},{now:i,skewMs:t.tokenRefreshSkewMs??E});return async()=>(await g()).accessToken},l="outlook365",G="https://graph.microsoft.com/v1.0",K=3e4,Q=3,y=e=>[e].flat(),I=e=>e.map(t=>({emailAddress:{address:t.email,...t.name?{name:t.name}:{}}})),V=e=>{if(e instanceof m)return e;const t=e instanceof Error?e.message:String(e);return new m(l,`Failed to obtain access token: ${t}`,{cause:e})},ae=C((e={})=>{const t=j(l,e.logger),c=$(e,l,t);if(c.mode==="clientCredentials"&&(e.userId===void 0||e.userId==="me"))throw new m(l,"The app-only (client credentials) flow requires an explicit 'userId'",{hint:"Set 'userId' to the sender's mailbox id or UPN — app-only tokens have no 'me' mailbox."});const n={authMode:c.mode,authority:e.authority??b,clientId:e.clientId,debug:e.debug??!1,endpoint:e.endpoint??G,logger:e.logger,now:e.now,retries:e.retries??Q,saveToSentItems:e.saveToSentItems??!0,scopes:e.scopes,tenantId:e.tenantId,timeout:e.timeout??K,tokenRefreshSkewMs:e.tokenRefreshSkewMs,userId:e.userId??"me"},h=new R,f=J(c,e,l,t);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!1},async initialize(){h.setInitialized()},async isAvailable(){return!0},name:l,options:n,async sendEmail(r){try{const i=A(r);if(i.length>0)return{error:new m(l,`Invalid email options: ${i.join(", ")}`),success:!1};let d;try{d=await f()}catch(T){return{error:V(T),success:!1}}const o={body:{content:r.html??r.text??"",contentType:r.html?"HTML":"Text"},subject:r.subject,toRecipients:I(y(r.to))};r.cc&&(o.ccRecipients=I(y(r.cc))),r.bcc&&(o.bccRecipients=I(y(r.bcc))),r.replyTo&&(o.replyTo=I(y(r.replyTo))),r.importance&&(o.importance=r.importance),r.attachments&&r.attachments.length>0&&(o.attachments=await Promise.all(r.attachments.map(async T=>{const g=await M(T,l);return{"@odata.type":"#microsoft.graph.fileAttachment",contentBytes:g.content,contentType:g.contentType,name:g.filename}})));const a=n.userId==="me"?"me":`users/${n.userId}`,k=await v(async()=>S(`${n.endpoint}/${a}/sendMail`,{headers:{Authorization:`Bearer ${d}`,"Content-Type":"application/json"},method:"POST",timeout:n.timeout},JSON.stringify({message:o,saveToSentItems:n.saveToSentItems})),n.retries);return k.success?{data:{messageId:_(),provider:l,response:k.data,sent:!0,timestamp:new Date},success:!0}:{error:k.error??new m(l,"Failed to send email"),success:!1}}catch(i){return{error:P(l,"send email",i,t),success:!1}}},async validateCredentials(){try{return await f(),!0}catch(r){return t.warn(`Credential validation failed: ${r instanceof Error?r.message:String(r)}`),!1}}}});export{ae as default};
@@ -1 +1 @@
1
- import m from"./EmailError-B-sEf3bp.js";import P from"./RequiredOptionError-DuNNY_a5.js";import{e as y}from"./generate-message-id-gXAuMz4g.js";import{s as A}from"./headers-to-record-De1Eg951.js";import{m as b}from"./make-request-BlK_B72c.js";import{u as g}from"./retry-3pnxTuNs.js";import{a as k,s as z}from"./sanitize-header-DJhgZl3y.js";import{f as j}from"./validate-email-options-mCM9dVug.js";import{defineProvider as E}from"./defineProvider-C9q-7iwt.js";import{P as T,h,c as K}from"./provider-base-C7PuopYK.js";import{p as x}from"./attachment-processor-CMp7qqMI.js";const r="plunk",_="https://api.useplunk.com/v1",S=3e4,q=3,U=E((n={})=>{if(!n.apiKey)throw new P(r,"apiKey");const a={apiKey:n.apiKey,debug:n.debug??!1,endpoint:n.endpoint??_,logger:n.logger,retries:n.retries??q,timeout:n.timeout??S},p=new T,i=K(r,n.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!0,tracking:!0},async getEmail(e){try{if(!e)return{error:new m(r,"Email ID is required to retrieve email details"),success:!1};await p.ensureInitialized(()=>this.initialize(),r);const l={Authorization:`Bearer ${a.apiKey}`,"Content-Type":"application/json"};i.debug("Retrieving email details",{id:e});const s=await g(async()=>b(`${a.endpoint}/emails/${e}`,{headers:l,method:"GET",timeout:a.timeout}),a.retries);return s.success?(i.debug("Email details retrieved successfully"),{data:s.data?.body,success:!0}):(i.debug("API request failed when retrieving email",s.error),{error:new m(r,`Failed to retrieve email: ${s.error instanceof Error?s.error.message:"Unknown error"}`,{cause:s.error}),success:!1})}catch(l){return{error:h(r,"retrieve email",l,i),success:!1}}},async initialize(){await p.ensureInitialized(async()=>{if(!await this.isAvailable())throw new m(r,"Plunk API not available or invalid API key");i.debug("Provider initialized successfully")},r)},async isAvailable(){try{return a.apiKey&&a.apiKey.length>0?(i.debug("API key exists, assuming Plunk is available"),!0):!1}catch(e){return i.debug("Error checking availability:",e),!1}},name:r,options:a,async sendEmail(e){try{const l=j(e);if(l.length>0)return{error:new m(r,`Invalid email options: ${l.join(", ")}`),success:!1};await p.ensureInitialized(()=>this.initialize(),r);const s=o=>Array.isArray(o)?o.map(d=>d.email):[o.email],t={to:e.subscriber??(Array.isArray(e.to)?e.to[0]?.email:e.to.email)};if(e.from&&(t.from=e.from.email,e.from.name&&(t.from_name=e.from.name)),e.subject&&(t.subject=e.subject),e.html?t.body=e.html:e.text&&(t.body=e.text),e.html&&e.text&&(t.text=e.text),e.cc&&(t.cc=s(e.cc)),e.bcc&&(t.bcc=s(e.bcc)),e.replyTo&&(t.reply_to=e.replyTo.email,e.replyTo.name&&(t.reply_to_name=e.replyTo.name)),e.templateId&&(t.template=e.templateId),e.data&&(t.data=e.data),e.subscriberId&&(t.subscriber_id=e.subscriberId),e.headers){const o=A(e.headers),d={};Object.entries(o).forEach(([w,I])=>{d[k(w)]=z(I)}),t.headers=d}e.attachments&&e.attachments.length>0&&(t.attachments=await Promise.all(e.attachments.map(async o=>({content:await x(o,r),filename:o.filename,type:o.contentType??"application/octet-stream"})))),i.debug("Sending email via Plunk API",{subject:t.subject,to:t.to});const v={Authorization:`Bearer ${a.apiKey}`,"Content-Type":"application/json"},c=await g(async()=>b(`${a.endpoint}/send`,{headers:v,method:"POST",timeout:a.timeout},JSON.stringify(t)),a.retries);if(!c.success)return i.debug("API request failed when sending email",c.error),{error:c.error??new m(r,"Failed to send email"),success:!1};const u=c.data,f=u?.body&&typeof u.body=="object"?u.body.id??u.body.messageId??y():y();return i.debug("Email sent successfully",{messageId:f}),{data:{messageId:f,provider:r,response:c.data,sent:!0,timestamp:new Date},success:!0}}catch(l){return{error:h(r,"send email",l,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{U as default};
1
+ import m from"./EmailError-B-sEf3bp.js";import P from"./RequiredOptionError-DuNNY_a5.js";import{e as y}from"./generate-message-id-gXAuMz4g.js";import{s as A}from"./headers-to-record-De1Eg951.js";import{m as b}from"./make-request-BlK_B72c.js";import{u as g}from"./retry-3pnxTuNs.js";import{s as k,a as z}from"./sanitize-header-DtQwAnzg.js";import{f as j}from"./validate-email-options-mCM9dVug.js";import{defineProvider as E}from"./defineProvider-C9q-7iwt.js";import{P as T,h,c as K}from"./provider-base-C7PuopYK.js";import{p as x}from"./attachment-processor-CMp7qqMI.js";const r="plunk",_="https://api.useplunk.com/v1",S=3e4,q=3,U=E((n={})=>{if(!n.apiKey)throw new P(r,"apiKey");const a={apiKey:n.apiKey,debug:n.debug??!1,endpoint:n.endpoint??_,logger:n.logger,retries:n.retries??q,timeout:n.timeout??S},p=new T,i=K(r,n.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!0,tracking:!0},async getEmail(e){try{if(!e)return{error:new m(r,"Email ID is required to retrieve email details"),success:!1};await p.ensureInitialized(()=>this.initialize(),r);const l={Authorization:`Bearer ${a.apiKey}`,"Content-Type":"application/json"};i.debug("Retrieving email details",{id:e});const s=await g(async()=>b(`${a.endpoint}/emails/${e}`,{headers:l,method:"GET",timeout:a.timeout}),a.retries);return s.success?(i.debug("Email details retrieved successfully"),{data:s.data?.body,success:!0}):(i.debug("API request failed when retrieving email",s.error),{error:new m(r,`Failed to retrieve email: ${s.error instanceof Error?s.error.message:"Unknown error"}`,{cause:s.error}),success:!1})}catch(l){return{error:h(r,"retrieve email",l,i),success:!1}}},async initialize(){await p.ensureInitialized(async()=>{if(!await this.isAvailable())throw new m(r,"Plunk API not available or invalid API key");i.debug("Provider initialized successfully")},r)},async isAvailable(){try{return a.apiKey&&a.apiKey.length>0?(i.debug("API key exists, assuming Plunk is available"),!0):!1}catch(e){return i.debug("Error checking availability:",e),!1}},name:r,options:a,async sendEmail(e){try{const l=j(e);if(l.length>0)return{error:new m(r,`Invalid email options: ${l.join(", ")}`),success:!1};await p.ensureInitialized(()=>this.initialize(),r);const s=o=>Array.isArray(o)?o.map(d=>d.email):[o.email],t={to:e.subscriber??(Array.isArray(e.to)?e.to[0]?.email:e.to.email)};if(e.from&&(t.from=e.from.email,e.from.name&&(t.from_name=e.from.name)),e.subject&&(t.subject=e.subject),e.html?t.body=e.html:e.text&&(t.body=e.text),e.html&&e.text&&(t.text=e.text),e.cc&&(t.cc=s(e.cc)),e.bcc&&(t.bcc=s(e.bcc)),e.replyTo&&(t.reply_to=e.replyTo.email,e.replyTo.name&&(t.reply_to_name=e.replyTo.name)),e.templateId&&(t.template=e.templateId),e.data&&(t.data=e.data),e.subscriberId&&(t.subscriber_id=e.subscriberId),e.headers){const o=A(e.headers),d={};Object.entries(o).forEach(([w,I])=>{d[k(w)]=z(I)}),t.headers=d}e.attachments&&e.attachments.length>0&&(t.attachments=await Promise.all(e.attachments.map(async o=>({content:await x(o,r),filename:o.filename,type:o.contentType??"application/octet-stream"})))),i.debug("Sending email via Plunk API",{subject:t.subject,to:t.to});const v={Authorization:`Bearer ${a.apiKey}`,"Content-Type":"application/json"},c=await g(async()=>b(`${a.endpoint}/send`,{headers:v,method:"POST",timeout:a.timeout},JSON.stringify(t)),a.retries);if(!c.success)return i.debug("API request failed when sending email",c.error),{error:c.error??new m(r,"Failed to send email"),success:!1};const u=c.data,f=u?.body&&typeof u.body=="object"?u.body.id??u.body.messageId??y():y();return i.debug("Email sent successfully",{messageId:f}),{data:{messageId:f,provider:r,response:c.data,sent:!0,timestamp:new Date},success:!0}}catch(l){return{error:h(r,"send email",l,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{U as default};
@@ -1 +1 @@
1
- import d from"./EmailError-B-sEf3bp.js";import T from"./RequiredOptionError-DuNNY_a5.js";import{e as P}from"./generate-message-id-gXAuMz4g.js";import{s as w}from"./headers-to-record-De1Eg951.js";import{m as u}from"./make-request-BlK_B72c.js";import{u as f}from"./retry-3pnxTuNs.js";import{s as I,a as A}from"./sanitize-header-DJhgZl3y.js";import{f as C}from"./validate-email-options-mCM9dVug.js";import{defineProvider as S}from"./defineProvider-C9q-7iwt.js";import{P as j,h,c as E}from"./provider-base-C7PuopYK.js";import{e as p,g as v}from"./address-formatter-BWR2Dddx.js";import{b as z}from"./attachment-processor-CMp7qqMI.js";const r="postmark",M="https://api.postmarkapp.com",O=3e4,H=3,U=S((o={})=>{if(!o.serverToken)throw new T(r,"serverToken");const s={debug:o.debug??!1,endpoint:o.endpoint??M,retries:o.retries??H,serverToken:o.serverToken,timeout:o.timeout??O,...o.logger&&{logger:o.logger}},m=new j,i=E(r,o.logger);return{endpoint:s.endpoint,features:{attachments:!0,batchSending:!0,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!0,templates:!0,tracking:!0},async getEmail(e){try{if(!e)return{error:new d(r,"Email ID is required to retrieve email details"),success:!1};await m.ensureInitialized(()=>this.initialize(),r);const a={"Content-Type":"application/json","X-Postmark-Server-Token":s.serverToken};i.debug("Retrieving email details",{id:e});const t=await f(async()=>u(`${s.endpoint}/messages/outbound/${e}/details`,{headers:a,method:"GET",timeout:s.timeout}),s.retries);return t.success?(i.debug("Email details retrieved successfully"),{data:t.data?.body,success:!0}):(i.debug("API request failed when retrieving email",t.error),{error:new d(r,`Failed to retrieve email: ${t.error instanceof Error?t.error.message:"Unknown error"}`,{cause:t.error}),success:!1})}catch(a){return{error:h(r,"retrieve email",a,i),success:!1}}},async initialize(){await m.ensureInitialized(async()=>{if(!await this.isAvailable())throw new d(r,"Postmark API not available or invalid server token");i.debug("Provider initialized successfully")},r)},async isAvailable(){try{const e={"Content-Type":"application/json","X-Postmark-Server-Token":s.serverToken};i.debug("Checking Postmark API availability");const a=await u(`${s.endpoint}/server`,{headers:e,method:"GET",timeout:s.timeout});return i.debug("Postmark API availability check response:",{error:a.error instanceof Error?a.error.message:void 0,statusCode:a.data?.statusCode,success:a.success}),!!(a.success&&a.data&&typeof a.data=="object"&&"statusCode"in a.data&&typeof a.data.statusCode=="number"&&a.data.statusCode>=200&&a.data.statusCode<300)}catch(e){return i.debug("Error checking availability:",e),!1}},name:r,options:s,async sendEmail(e){try{const a=C(e);if(a.length>0)return{error:new d(r,`Invalid email options: ${a.join(", ")}`),success:!1};await m.ensureInitialized(()=>this.initialize(),r);const t={From:v(e.from),Subject:e.subject,To:p(e.to).join(",")};if(e.html&&(t.HtmlBody=e.html),e.text&&(t.TextBody=e.text),e.cc&&(t.Cc=p(e.cc).join(",")),e.bcc&&(t.Bcc=p(e.bcc).join(",")),e.replyTo&&(t.ReplyTo=v(e.replyTo)),e.templateId?(t.TemplateId=e.templateId,e.templateModel&&(t.TemplateModel=e.templateModel)):e.templateAlias&&(t.TemplateAlias=e.templateAlias,e.templateModel&&(t.TemplateModel=e.templateModel)),e.trackOpens!==void 0&&(t.TrackOpens=e.trackOpens),e.trackLinks!==void 0&&(t.TrackLinks=e.trackLinks),e.inlineCss!==void 0&&(t.InlineCss=e.inlineCss),e.messageStream&&(t.MessageStream=e.messageStream),e.metadata&&(t.Metadata=e.metadata),e.tags&&e.tags.length>0){const[l]=e.tags;t.Tag=l}if(e.headers){const l=w(e.headers),c=[];for(const[b,y]of Object.entries(l))c.push({Name:A(b),Value:I(String(y))});c.length>0&&(t.Headers=c)}e.attachments&&e.attachments.length>0&&(t.Attachments=await Promise.all(e.attachments.map(async l=>z(l,r)))),i.debug("Sending email via Postmark API",{subject:t.Subject,to:t.To});const k={"Content-Type":"application/json","X-Postmark-Server-Token":s.serverToken},n=await f(async()=>u(`${s.endpoint}/email`,{headers:k,method:"POST",timeout:s.timeout},JSON.stringify(t)),s.retries);if(!n.success)return i.debug("API request failed when sending email",n.error),{error:n.error??new d(r,"Failed to send email"),success:!1};const g=n.data?.body?.MessageID??P();return i.debug("Email sent successfully",{messageId:g}),{data:{messageId:g,provider:r,response:n.data,sent:!0,timestamp:new Date},success:!0}}catch(a){return{error:h(r,"send email",a,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{U as default};
1
+ import d from"./EmailError-B-sEf3bp.js";import T from"./RequiredOptionError-DuNNY_a5.js";import{e as P}from"./generate-message-id-gXAuMz4g.js";import{s as w}from"./headers-to-record-De1Eg951.js";import{m as u}from"./make-request-BlK_B72c.js";import{u as f}from"./retry-3pnxTuNs.js";import{a as I,s as A}from"./sanitize-header-DtQwAnzg.js";import{f as C}from"./validate-email-options-mCM9dVug.js";import{defineProvider as S}from"./defineProvider-C9q-7iwt.js";import{P as j,h,c as E}from"./provider-base-C7PuopYK.js";import{e as p,g as v}from"./address-formatter-BWR2Dddx.js";import{b as z}from"./attachment-processor-CMp7qqMI.js";const r="postmark",M="https://api.postmarkapp.com",O=3e4,H=3,U=S((o={})=>{if(!o.serverToken)throw new T(r,"serverToken");const s={debug:o.debug??!1,endpoint:o.endpoint??M,retries:o.retries??H,serverToken:o.serverToken,timeout:o.timeout??O,...o.logger&&{logger:o.logger}},m=new j,i=E(r,o.logger);return{endpoint:s.endpoint,features:{attachments:!0,batchSending:!0,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!0,templates:!0,tracking:!0},async getEmail(e){try{if(!e)return{error:new d(r,"Email ID is required to retrieve email details"),success:!1};await m.ensureInitialized(()=>this.initialize(),r);const a={"Content-Type":"application/json","X-Postmark-Server-Token":s.serverToken};i.debug("Retrieving email details",{id:e});const t=await f(async()=>u(`${s.endpoint}/messages/outbound/${e}/details`,{headers:a,method:"GET",timeout:s.timeout}),s.retries);return t.success?(i.debug("Email details retrieved successfully"),{data:t.data?.body,success:!0}):(i.debug("API request failed when retrieving email",t.error),{error:new d(r,`Failed to retrieve email: ${t.error instanceof Error?t.error.message:"Unknown error"}`,{cause:t.error}),success:!1})}catch(a){return{error:h(r,"retrieve email",a,i),success:!1}}},async initialize(){await m.ensureInitialized(async()=>{if(!await this.isAvailable())throw new d(r,"Postmark API not available or invalid server token");i.debug("Provider initialized successfully")},r)},async isAvailable(){try{const e={"Content-Type":"application/json","X-Postmark-Server-Token":s.serverToken};i.debug("Checking Postmark API availability");const a=await u(`${s.endpoint}/server`,{headers:e,method:"GET",timeout:s.timeout});return i.debug("Postmark API availability check response:",{error:a.error instanceof Error?a.error.message:void 0,statusCode:a.data?.statusCode,success:a.success}),!!(a.success&&a.data&&typeof a.data=="object"&&"statusCode"in a.data&&typeof a.data.statusCode=="number"&&a.data.statusCode>=200&&a.data.statusCode<300)}catch(e){return i.debug("Error checking availability:",e),!1}},name:r,options:s,async sendEmail(e){try{const a=C(e);if(a.length>0)return{error:new d(r,`Invalid email options: ${a.join(", ")}`),success:!1};await m.ensureInitialized(()=>this.initialize(),r);const t={From:v(e.from),Subject:e.subject,To:p(e.to).join(",")};if(e.html&&(t.HtmlBody=e.html),e.text&&(t.TextBody=e.text),e.cc&&(t.Cc=p(e.cc).join(",")),e.bcc&&(t.Bcc=p(e.bcc).join(",")),e.replyTo&&(t.ReplyTo=v(e.replyTo)),e.templateId?(t.TemplateId=e.templateId,e.templateModel&&(t.TemplateModel=e.templateModel)):e.templateAlias&&(t.TemplateAlias=e.templateAlias,e.templateModel&&(t.TemplateModel=e.templateModel)),e.trackOpens!==void 0&&(t.TrackOpens=e.trackOpens),e.trackLinks!==void 0&&(t.TrackLinks=e.trackLinks),e.inlineCss!==void 0&&(t.InlineCss=e.inlineCss),e.messageStream&&(t.MessageStream=e.messageStream),e.metadata&&(t.Metadata=e.metadata),e.tags&&e.tags.length>0){const[l]=e.tags;t.Tag=l}if(e.headers){const l=w(e.headers),c=[];for(const[b,y]of Object.entries(l))c.push({Name:A(b),Value:I(String(y))});c.length>0&&(t.Headers=c)}e.attachments&&e.attachments.length>0&&(t.Attachments=await Promise.all(e.attachments.map(async l=>z(l,r)))),i.debug("Sending email via Postmark API",{subject:t.Subject,to:t.To});const k={"Content-Type":"application/json","X-Postmark-Server-Token":s.serverToken},n=await f(async()=>u(`${s.endpoint}/email`,{headers:k,method:"POST",timeout:s.timeout},JSON.stringify(t)),s.retries);if(!n.success)return i.debug("API request failed when sending email",n.error),{error:n.error??new d(r,"Failed to send email"),success:!1};const g=n.data?.body?.MessageID??P();return i.debug("Email sent successfully",{messageId:g}),{data:{messageId:g,provider:r,response:n.data,sent:!0,timestamp:new Date},success:!0}}catch(a){return{error:h(r,"send email",a,i),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{U as default};
@@ -1 +1 @@
1
- const r=/[\r\n]/,s=e=>{const a=e.search(r);return a===-1?e:e.slice(0,a)},n=e=>e.replaceAll(/[\r\n]/g,"");export{n as a,s};
1
+ const r=/[\r\n]/,s=e=>{const a=e.search(r);return a===-1?e:e.slice(0,a)},n=e=>e.replaceAll(/[\r\n]/g,"");export{s as a,n as s};
@@ -1,4 +1,4 @@
1
- import{createRequire as x}from"node:module";import f from"./EmailError-B-sEf3bp.js";import W from"./RequiredOptionError-DuNNY_a5.js";import{F as Q}from"./build-mime-message-B6927SQy.js";import{e as Z}from"./generate-message-id-gXAuMz4g.js";import{f as J}from"./validate-email-options-mCM9dVug.js";import{defineProvider as V}from"./defineProvider-C9q-7iwt.js";const G=x(import.meta.url),O=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,k=h=>{if(typeof O<"u"&&O.versions&&O.versions.node){const[t,A]=O.versions.node.split(".").map(Number);if(t>22||t===22&&A>=3||t===20&&A>=16)return O.getBuiltinModule(h)}return G(h)},{Buffer:I}=k("node:buffer"),{createHmac:B,createHash:X,createSign:Y}=k("node:crypto"),{Socket:q,createConnection:K}=k("node:net"),{connect:E}=k("node:tls"),ee=(h,t)=>new Promise(A=>{const w=new q,y=()=>{w.destroy(),A(!1)};w.setTimeout(1e3),w.on("error",y),w.on("timeout",y),w.connect(t,h,()=>{w.end(),A(!0)})}),l="smtp",te=25,re=465,se=1e4,oe=!1,ae=5,P=3e4,ie=/^\./,pe=V((h={})=>{if(!h.host)throw new W(l,"host");const t={authMethod:h.authMethod??"LOGIN",debug:h.debug??!1,dkim:h.dkim,host:h.host,maxConnections:h.maxConnections??ae,oauth2:h.oauth2,password:h.password,pool:h.pool??!1,port:h.port!==void 0?h.port:h.secure?re:te,rejectUnauthorized:h.rejectUnauthorized??!0,retries:h.retries??0,secure:h.secure??oe,timeout:h.timeout??se,user:h.user,...h.logger&&{logger:h.logger}};let A=!1;const w=[],y=[],S=e=>e.replaceAll(/[\r\n\t\v\f]/g," ").trim(),v=e=>{const u=e.split(`\r
1
+ import{createRequire as x}from"node:module";import f from"./EmailError-B-sEf3bp.js";import W from"./RequiredOptionError-DuNNY_a5.js";import{F as Q}from"./build-mime-message-BW5FQ2Bt.js";import{e as Z}from"./generate-message-id-gXAuMz4g.js";import{f as J}from"./validate-email-options-mCM9dVug.js";import{defineProvider as V}from"./defineProvider-C9q-7iwt.js";const G=x(import.meta.url),O=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,k=h=>{if(typeof O<"u"&&O.versions&&O.versions.node){const[t,A]=O.versions.node.split(".").map(Number);if(t>22||t===22&&A>=3||t===20&&A>=16)return O.getBuiltinModule(h)}return G(h)},{Buffer:I}=k("node:buffer"),{createHmac:B,createHash:X,createSign:Y}=k("node:crypto"),{Socket:q,createConnection:K}=k("node:net"),{connect:E}=k("node:tls"),ee=(h,t)=>new Promise(A=>{const w=new q,y=()=>{w.destroy(),A(!1)};w.setTimeout(1e3),w.on("error",y),w.on("timeout",y),w.connect(t,h,()=>{w.end(),A(!0)})}),l="smtp",te=25,re=465,se=1e4,oe=!1,ae=5,P=3e4,ie=/^\./,pe=V((h={})=>{if(!h.host)throw new W(l,"host");const t={authMethod:h.authMethod??"LOGIN",debug:h.debug??!1,dkim:h.dkim,host:h.host,maxConnections:h.maxConnections??ae,oauth2:h.oauth2,password:h.password,pool:h.pool??!1,port:h.port!==void 0?h.port:h.secure?re:te,rejectUnauthorized:h.rejectUnauthorized??!0,retries:h.retries??0,secure:h.secure??oe,timeout:h.timeout??se,user:h.user,...h.logger&&{logger:h.logger}};let A=!1;const w=[],y=[],S=e=>e.replaceAll(/[\r\n\t\v\f]/g," ").trim(),v=e=>{const u=e.split(`\r
2
2
  `),o={};for(const c of u)if(c.startsWith("250-")||c.startsWith("250 ")){const i=c.slice(4).trim().split(" "),n=i[0];n&&(o[n]=i.slice(1))}return o},p=async(e,u,o)=>new Promise((c,i)=>{const n=Array.isArray(o)?o:[o];let s="",a="";const d=setTimeout(()=>{g(),i(new f(l,`Command timeout after ${t.timeout}ms: ${u?.slice(0,50)}...`))},t.timeout),g=()=>{e.removeListener("data",b),e.removeListener("error",r),d&&clearTimeout(d)},b=m=>{s+=m.toString();const j=s.split(`\r
3
3
  `).filter(Boolean);if(j.length>0){const $=j.at(-1);if($){const U=$.match(/^(\d{3})[\s-]/);if(U){const[,M]=U;a=M,$[3]===" "&&(g(),n.includes(a)?c(s):i(new f(l,`Expected ${n.join(" or ")}, got ${a}: ${s.trim()}`)))}}}},r=m=>{g(),i(new f(l,`Socket error: ${m.message}`,{cause:m}))};e.on("data",b),e.on("error",r),u&&e.write(`${u}\r
4
4
  `)}),C=async()=>{if(t.pool&&w.length>0){const e=w.pop();if(e&&!e.destroyed)return e}return t.pool&&w.length+1>=t.maxConnections?new Promise((e,u)=>{const o={reject:u,resolve:e};o.timeout=setTimeout(()=>{const c=y.indexOf(o);c!==-1&&y.splice(c,1),u(new f(l,`Connection queue timeout after ${P}ms`))},P),y.push(o)}):new Promise((e,u)=>{let o,c=!1,i;const n=()=>{o&&clearTimeout(o)};o=setTimeout(()=>{c||(c=!0,i&&!i.destroyed&&i.destroy(),n(),u(new f(l,`Connection timeout to ${t.host}:${t.port} after ${t.timeout}ms`)))},t.timeout);try{i=t.secure?E({host:t.host,port:t.port,rejectUnauthorized:t.rejectUnauthorized}):K(t.port,t.host),i.on("error",s=>{c||(c=!0,n(),u(new f(l,`Connection error: ${s.message}`,{cause:s})))}),i.once("data",s=>{if(!c&&i){c=!0,n();const a=s.toString();a.slice(0,3)==="220"?e(i):(i.destroy(),u(new f(l,`Unexpected server greeting: ${a.trim()}`)))}})}catch(s){c||(c=!0,n(),u(new f(l,`Failed to create connection: ${s.message}`,{cause:s})))}})},R=async e=>new Promise((u,o)=>{let c,i=!1,n;const s=()=>{c&&clearTimeout(c)};c=setTimeout(()=>{i||(i=!0,n&&!n.destroyed&&n.destroy(),s(),o(new f(l,`TLS connection timeout after ${t.timeout}ms`)))},t.timeout);try{const a={host:t.host,rejectUnauthorized:t.rejectUnauthorized,socket:e};n=E(a),n.on("error",d=>{i||(i=!0,s(),o(new f(l,`TLS connection error: ${d.message}`,{cause:d})))}),n.once("secure",()=>{!i&&n&&(i=!0,s(),u(n))})}catch(a){i||(i=!0,s(),o(new f(l,`Failed to upgrade to TLS: ${a.message}`,{cause:a})))}}),z=e=>{if(e.destroyed||!t.pool){try{e.destroy()}catch{}return}if(y.length>0){const u=y.shift();if(u){clearTimeout(u.timeout),u.resolve(e);return}}w.push(e)},L=async(e,u=!1)=>new Promise(o=>{try{if(u){e.write(`RSET\r
@@ -1 +1 @@
1
- import l from"./EmailError-B-sEf3bp.js";import y from"./RequiredOptionError-DuNNY_a5.js";import{e as b}from"./generate-message-id-gXAuMz4g.js";import{s as k}from"./headers-to-record-De1Eg951.js";import{m as v}from"./make-request-BlK_B72c.js";import{u as w}from"./retry-3pnxTuNs.js";import{a as A,s as z}from"./sanitize-header-DJhgZl3y.js";import{f as _}from"./validate-email-options-mCM9dVug.js";import{defineProvider as j}from"./defineProvider-C9q-7iwt.js";import{P,h as I,c as T}from"./provider-base-C7PuopYK.js";import{n as h}from"./address-formatter-BWR2Dddx.js";const i="zeptomail",O="https://api.zeptomail.com/v1.1",Z=3e4,E=3,L=j((s={})=>{if(!s.token)throw new y(i,"token");if(!s.token.startsWith("Zoho-enczapikey "))throw new l(i,'Token should be in the format "Zoho-enczapikey <your_api_key>"');const o={debug:s.debug??!1,endpoint:s.endpoint??O,logger:s.logger,retries:s.retries??E,timeout:s.timeout??Z,token:s.token},u=new P,n=T(i,s.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!0},async initialize(){await u.ensureInitialized(async()=>{if(!await this.isAvailable())throw new l(i,"Zeptomail API not available or invalid token");n.debug("Provider initialized successfully")},i)},async isAvailable(){try{return o.token&&o.token.startsWith("Zoho-enczapikey ")?(n.debug("Token format is valid, assuming Zeptomail is available"),!0):!1}catch(e){return n.debug("Error checking availability:",e),!1}},name:i,options:o,async sendEmail(e){try{const m=_(e);if(m.length>0)return{error:new l(i,`Invalid email options: ${m.join(", ")}`),success:!1};await u.ensureInitialized(()=>this.initialize(),i);const a={from:h(e.from).address,subject:e.subject};if(Array.isArray(e.to)?a.to=e.to.length===1?e.to[0].email:e.to.map(t=>t.email):a.to=e.to.email,e.text&&(a.textbody=e.text),e.html&&(a.htmlbody=e.html),e.cc&&(Array.isArray(e.cc)?a.cc=e.cc.length===1?e.cc[0].email:e.cc.map(t=>t.email):a.cc=e.cc.email),e.bcc&&(Array.isArray(e.bcc)?a.bcc=e.bcc.length===1?e.bcc[0].email:e.bcc.map(t=>t.email):a.bcc=e.bcc.email),e.replyTo&&(a.reply_to=[h(e.replyTo).address]),e.trackClicks!==void 0&&(a.track_clicks=e.trackClicks),e.trackOpens!==void 0&&(a.track_opens=e.trackOpens),e.clientReference&&(a.client_reference=e.clientReference),e.mimeHeaders&&Object.keys(e.mimeHeaders).length>0){const t={};for(const[r,d]of Object.entries(e.mimeHeaders))t[r]=d;a.mime_headers=t}if(e.headers){const t=k(e.headers);Object.keys(t).length>0&&(a.mime_headers??={},Object.entries(t).forEach(([r,d])=>{a.mime_headers&&(a.mime_headers[A(r)]=z(d))}))}e.attachments&&e.attachments.length>0&&(a.attachments=e.attachments.map(t=>{const r={name:t.filename};return t.content?(r.content=typeof t.content=="string"?t.content:t.content.toString("base64"),t.contentType&&(r.mime_type=t.contentType)):t.path&&(r.file_cache_key=t.path),r})),n.debug("Sending email via Zeptomail API",{subject:a.subject,to:a.to});const g={Accept:"application/json",Authorization:o.token,"Content-Type":"application/json"},c=await w(async()=>v(`${o.endpoint}/email`,{headers:g,method:"POST",timeout:o.timeout},JSON.stringify(a)),o.retries);if(!c.success){n.debug("API request failed",c.error);let t=c.error instanceof Error?c.error.message:"Unknown error";const r=c.data;return r?.body?.message?t+=` Details: ${r.body.message}`:r?.body?.error?.message&&(t+=` Details: ${r.body.error.message}`),{error:new l(i,`Failed to send email: ${t}`,{cause:c.error}),success:!1}}const p=c.data?.body,f=p?.request_id??b();return n.debug("Email sent successfully",{messageId:f}),{data:{messageId:f,provider:i,response:p,sent:!0,timestamp:new Date},success:!0}}catch(m){return{error:I(i,"send email",m,n),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{L as default};
1
+ import l from"./EmailError-B-sEf3bp.js";import y from"./RequiredOptionError-DuNNY_a5.js";import{e as b}from"./generate-message-id-gXAuMz4g.js";import{s as k}from"./headers-to-record-De1Eg951.js";import{m as v}from"./make-request-BlK_B72c.js";import{u as w}from"./retry-3pnxTuNs.js";import{s as A,a as z}from"./sanitize-header-DtQwAnzg.js";import{f as _}from"./validate-email-options-mCM9dVug.js";import{defineProvider as j}from"./defineProvider-C9q-7iwt.js";import{P,h as I,c as T}from"./provider-base-C7PuopYK.js";import{n as h}from"./address-formatter-BWR2Dddx.js";const i="zeptomail",O="https://api.zeptomail.com/v1.1",Z=3e4,E=3,L=j((s={})=>{if(!s.token)throw new y(i,"token");if(!s.token.startsWith("Zoho-enczapikey "))throw new l(i,'Token should be in the format "Zoho-enczapikey <your_api_key>"');const o={debug:s.debug??!1,endpoint:s.endpoint??O,logger:s.logger,retries:s.retries??E,timeout:s.timeout??Z,token:s.token},u=new P,n=T(i,s.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!0},async initialize(){await u.ensureInitialized(async()=>{if(!await this.isAvailable())throw new l(i,"Zeptomail API not available or invalid token");n.debug("Provider initialized successfully")},i)},async isAvailable(){try{return o.token&&o.token.startsWith("Zoho-enczapikey ")?(n.debug("Token format is valid, assuming Zeptomail is available"),!0):!1}catch(e){return n.debug("Error checking availability:",e),!1}},name:i,options:o,async sendEmail(e){try{const m=_(e);if(m.length>0)return{error:new l(i,`Invalid email options: ${m.join(", ")}`),success:!1};await u.ensureInitialized(()=>this.initialize(),i);const a={from:h(e.from).address,subject:e.subject};if(Array.isArray(e.to)?a.to=e.to.length===1?e.to[0].email:e.to.map(t=>t.email):a.to=e.to.email,e.text&&(a.textbody=e.text),e.html&&(a.htmlbody=e.html),e.cc&&(Array.isArray(e.cc)?a.cc=e.cc.length===1?e.cc[0].email:e.cc.map(t=>t.email):a.cc=e.cc.email),e.bcc&&(Array.isArray(e.bcc)?a.bcc=e.bcc.length===1?e.bcc[0].email:e.bcc.map(t=>t.email):a.bcc=e.bcc.email),e.replyTo&&(a.reply_to=[h(e.replyTo).address]),e.trackClicks!==void 0&&(a.track_clicks=e.trackClicks),e.trackOpens!==void 0&&(a.track_opens=e.trackOpens),e.clientReference&&(a.client_reference=e.clientReference),e.mimeHeaders&&Object.keys(e.mimeHeaders).length>0){const t={};for(const[r,d]of Object.entries(e.mimeHeaders))t[r]=d;a.mime_headers=t}if(e.headers){const t=k(e.headers);Object.keys(t).length>0&&(a.mime_headers??={},Object.entries(t).forEach(([r,d])=>{a.mime_headers&&(a.mime_headers[A(r)]=z(d))}))}e.attachments&&e.attachments.length>0&&(a.attachments=e.attachments.map(t=>{const r={name:t.filename};return t.content?(r.content=typeof t.content=="string"?t.content:t.content.toString("base64"),t.contentType&&(r.mime_type=t.contentType)):t.path&&(r.file_cache_key=t.path),r})),n.debug("Sending email via Zeptomail API",{subject:a.subject,to:a.to});const g={Accept:"application/json",Authorization:o.token,"Content-Type":"application/json"},c=await w(async()=>v(`${o.endpoint}/email`,{headers:g,method:"POST",timeout:o.timeout},JSON.stringify(a)),o.retries);if(!c.success){n.debug("API request failed",c.error);let t=c.error instanceof Error?c.error.message:"Unknown error";const r=c.data;return r?.body?.message?t+=` Details: ${r.body.message}`:r?.body?.error?.message&&(t+=` Details: ${r.body.error.message}`),{error:new l(i,`Failed to send email: ${t}`,{cause:c.error}),success:!1}}const p=c.data?.body,f=p?.request_id??b();return n.debug("Email sent successfully",{messageId:f}),{data:{messageId:f,provider:i,response:p,sent:!0,timestamp:new Date},success:!0}}catch(m){return{error:I(i,"send email",m,n),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{L as default};
@@ -0,0 +1,56 @@
1
+ import { P as ProviderFactory } from "../../packem_shared/provider.d-J-y6iogK.js";
2
+ export type { a as Provider } from "../../packem_shared/provider.d-J-y6iogK.js";
3
+ import { B as BaseConfig, E as EmailOptions } from "../../packem_shared/types.d-ejzh-xBP.js";
4
+ import 'node:buffer';
5
+ /**
6
+ * AutoSend configuration.
7
+ */
8
+ interface AutoSendConfig extends BaseConfig {
9
+ /**
10
+ * AutoSend API key (sent as a Bearer token).
11
+ */
12
+ apiKey: string;
13
+ /**
14
+ * API endpoint override (default `https://api.autosend.com/v1`).
15
+ */
16
+ endpoint?: string;
17
+ }
18
+ /**
19
+ * AutoSend-specific email options.
20
+ *
21
+ * See the [send reference](https://docs.autosend.com/api-reference/mails/send). AutoSend's
22
+ * `/mails/send` takes exactly one `to` recipient — pass a single address, and use `cc`/`bcc`
23
+ * for additional ones.
24
+ */
25
+ interface AutoSendEmailOptions extends EmailOptions {
26
+ /**
27
+ * Sends even if the recipient is on the suppression list. Use sparingly: suppressions exist
28
+ * to protect the sending domain's reputation.
29
+ */
30
+ bypassSuppressions?: boolean;
31
+ /**
32
+ * Values substituted into Handlebars placeholders (`{{ name }}`) in the template or `html`.
33
+ */
34
+ dynamicData?: Record<string, unknown>;
35
+ /**
36
+ * An AutoSend template id, used instead of `html` / `text`.
37
+ */
38
+ templateId?: string;
39
+ /**
40
+ * Enables click tracking for this message.
41
+ */
42
+ trackingClick?: boolean;
43
+ /**
44
+ * Enables open tracking for this message.
45
+ */
46
+ trackingOpen?: boolean;
47
+ /**
48
+ * The unsubscribe group this message belongs to.
49
+ */
50
+ unsubscribeGroupId?: string;
51
+ }
52
+ /**
53
+ * AutoSend provider — sends through the [AutoSend send endpoint](https://docs.autosend.com/api-reference/mails/send).
54
+ */
55
+ declare const autoSendProvider: ProviderFactory<AutoSendConfig, unknown, AutoSendEmailOptions>;
56
+ export { type AutoSendConfig, type AutoSendEmailOptions, type ProviderFactory, autoSendProvider };
@@ -0,0 +1 @@
1
+ import{default as r}from"../../packem_shared/autoSendProvider-Bz3g6aZi.js";export{r as autoSendProvider};
@@ -1 +1 @@
1
- import{default as a}from"../../packem_shared/awsSesProvider-BGZJUIep.js";export{a as awsSesProvider};
1
+ import{default as a}from"../../packem_shared/awsSesProvider-962hIcbo.js";export{a as awsSesProvider};
@@ -1 +1 @@
1
- import{default as e}from"../../packem_shared/cloudflareEmailProvider-Bv-ty-74.js";export{e as cloudflareEmailProvider};
1
+ import{default as e}from"../../packem_shared/cloudflareEmailProvider-B8mOEl3N.js";export{e as cloudflareEmailProvider};
@@ -1 +1 @@
1
- import{default as e}from"../../packem_shared/mailCrabProvider-CPtBT6Th.js";export{e as mailCrabProvider};
1
+ import{default as e}from"../../packem_shared/mailCrabProvider-DRE5snM9.js";export{e as mailCrabProvider};
@@ -1 +1 @@
1
- import{default as r}from"../../packem_shared/mailPaceProvider-CJEvOFBh.js";export{r as mailPaceProvider};
1
+ import{default as r}from"../../packem_shared/mailPaceProvider-DZent57J.js";export{r as mailPaceProvider};
@@ -1 +1 @@
1
- import{default as d}from"../../packem_shared/mandrillProvider-DWPFh_Sj.js";export{d as mandrillProvider};
1
+ import{default as d}from"../../packem_shared/mandrillProvider-DSsAknmA.js";export{d as mandrillProvider};
@@ -3,11 +3,25 @@ export type { a as Provider } from "../../packem_shared/provider.d-J-y6iogK.js";
3
3
  import { M as MaybePromise, B as BaseConfig, E as EmailOptions } from "../../packem_shared/types.d-ejzh-xBP.js";
4
4
  import 'node:buffer';
5
5
  /**
6
+ * Which OAuth2 flow a config resolves to.
7
+ */
8
+ type Outlook365AuthMode = "accessToken" | "clientCredentials" | "getAccessToken" | "refreshToken";
9
+ /**
6
10
  * Outlook365 / Microsoft Graph configuration.
7
11
  *
8
- * Authentication is delegated: supply a static `accessToken` or an async
9
- * `getAccessToken` (e.g. backed by `@azure/msal-node`). The provider never bundles an
10
- * auth SDK, so it stays dependency-light and runtime-agnostic.
12
+ * Four authentication modes are supported, in precedence order:
13
+ *
14
+ * 1. `getAccessToken` bring your own async token source (e.g. `@azure/msal-node`).
15
+ * 2. `accessToken` — a static token, for scripts and tests.
16
+ * 3. `refreshToken` — delegated flow; the provider exchanges the refresh token for access tokens and caches them. Requires `tenantId` + `clientId`.
17
+ * 4. `clientCredentials` (selected by supplying `clientSecret`) — app-only flow. Requires `tenantId` + `clientId`, and `userId` must name a real mailbox, since app-only tokens have no `me`.
18
+ *
19
+ * A confidential-client delegated config and an app-only config with a leftover `refreshToken`
20
+ * are indistinguishable — both carry `tenantId`, `clientId`, `clientSecret` and `refreshToken`.
21
+ * Set {@link Outlook365Config.authMode} to pin the flow when both are present.
22
+ *
23
+ * The built-in flows talk to the Azure AD token endpoint over `fetch` — no auth SDK is
24
+ * bundled, so the provider stays dependency-light and runtime-agnostic.
11
25
  */
12
26
  interface Outlook365Config extends BaseConfig {
13
27
  /**
@@ -16,6 +30,28 @@ interface Outlook365Config extends BaseConfig {
16
30
  */
17
31
  accessToken?: string;
18
32
  /**
33
+ * Pins the authentication flow instead of inferring it from which credentials are present.
34
+ * Use it when a config could match more than one flow — most notably `clientCredentials`
35
+ * vs `refreshToken` when both a client secret and a refresh token are supplied.
36
+ */
37
+ authMode?: Outlook365AuthMode;
38
+ /**
39
+ * Azure AD login authority (default `https://login.microsoftonline.com`). Override for
40
+ * sovereign clouds, e.g. `https://login.microsoftonline.us`.
41
+ */
42
+ authority?: string;
43
+ /**
44
+ * Application (client) id of the Azure AD app registration. Required by the
45
+ * `refreshToken` and `clientSecret` flows.
46
+ */
47
+ clientId?: string;
48
+ /**
49
+ * Client secret of the Azure AD app registration. Supplying this without a
50
+ * {@link Outlook365Config.refreshToken} selects the app-only (client credentials) flow.
51
+ * It is also sent with the delegated flow when the app is a confidential client.
52
+ */
53
+ clientSecret?: string;
54
+ /**
19
55
  * API endpoint override (default `https://graph.microsoft.com/v1.0`).
20
56
  */
21
57
  endpoint?: string;
@@ -24,11 +60,50 @@ interface Outlook365Config extends BaseConfig {
24
60
  */
25
61
  getAccessToken?: () => MaybePromise<string>;
26
62
  /**
63
+ * Time source in milliseconds — injectable for tests. Defaults to `Date.now`.
64
+ */
65
+ now?: () => number;
66
+ /**
67
+ * Called whenever Azure AD rotates the refresh token, so it can be persisted. Awaited
68
+ * before the access token is handed out, so a rejected promise is reported rather than
69
+ * surfacing as an unhandled rejection.
70
+ *
71
+ * The rotated token is adopted in-process regardless of whether persisting succeeds — the
72
+ * previous token is already dead at Azure AD, so the new one is the only usable value. A
73
+ * persist failure is logged rather than failing the send, but the stored token is then
74
+ * stale and sending will break on restart.
75
+ * @param refreshToken The new refresh token.
76
+ */
77
+ onRefreshToken?: (refreshToken: string) => MaybePromise<void>;
78
+ /**
79
+ * A long-lived OAuth2 refresh token, selecting the delegated flow. Obtain it via the
80
+ * authorization-code flow with the `offline_access` scope.
81
+ */
82
+ refreshToken?: string;
83
+ /**
27
84
  * Whether to keep a copy in the Sent Items folder (default true).
28
85
  */
29
86
  saveToSentItems?: boolean;
30
87
  /**
88
+ * Scope override for the built-in flows. Defaults to
89
+ * `["https://graph.microsoft.com/.default"]` for the app-only flow and
90
+ * `["https://graph.microsoft.com/Mail.Send", "offline_access"]` for the delegated flow.
91
+ */
92
+ scopes?: string[];
93
+ /**
94
+ * Azure AD tenant id (or `common` / `organizations` for the delegated flow). Required by
95
+ * the `refreshToken` and `clientSecret` flows.
96
+ */
97
+ tenantId?: string;
98
+ /**
99
+ * Renew the access token this many milliseconds before it expires (default 60000).
100
+ * Negative values are clamped to 0. A value larger than the token lifetime disables
101
+ * caching, costing one token request per send.
102
+ */
103
+ tokenRefreshSkewMs?: number;
104
+ /**
31
105
  * The mailbox to send as: a user id/UPN. Defaults to `me` (the token's own mailbox).
106
+ * The app-only flow has no `me`, so it requires an explicit value.
32
107
  */
33
108
  userId?: string;
34
109
  }
@@ -43,6 +118,9 @@ interface Outlook365EmailOptions extends EmailOptions {
43
118
  }
44
119
  /**
45
120
  * Outlook365 provider — sends email through the Microsoft Graph `sendMail` endpoint.
121
+ *
122
+ * Authenticates with a caller-supplied token (`accessToken` / `getAccessToken`), the delegated
123
+ * refresh-token flow, or the app-only client-credentials flow. See {@link Outlook365Config}.
46
124
  */
47
- declare const outlook365Provider: ProviderFactory<Outlook365Config>;
48
- export { type Outlook365Config, type Outlook365EmailOptions, type ProviderFactory, outlook365Provider };
125
+ declare const outlook365Provider: ProviderFactory<Outlook365Config, unknown, Outlook365EmailOptions>;
126
+ export { type Outlook365AuthMode, type Outlook365Config, type Outlook365EmailOptions, type ProviderFactory, outlook365Provider };
@@ -1 +1 @@
1
- import{default as e}from"../../packem_shared/outlook365Provider-63ggDpqV.js";export{e as outlook365Provider};
1
+ import{default as e}from"../../packem_shared/outlook365Provider-CkjXkY-7.js";export{e as outlook365Provider};
@@ -1 +1 @@
1
- import{default as o}from"../../packem_shared/plunkProvider-yTlrJVEp.js";export{o as plunkProvider};
1
+ import{default as o}from"../../packem_shared/plunkProvider-D3T2T-2V.js";export{o as plunkProvider};
@@ -1 +1 @@
1
- import{default as a}from"../../packem_shared/postmarkProvider-CDx85Yge.js";export{a as postmarkProvider};
1
+ import{default as a}from"../../packem_shared/postmarkProvider-vspVSSOp.js";export{a as postmarkProvider};
@@ -1 +1 @@
1
- import{default as o}from"../../packem_shared/smtpProvider-Bm0yP97W.js";export{o as smtpProvider};
1
+ import{default as o}from"../../packem_shared/smtpProvider-5MI3-EPh.js";export{o as smtpProvider};
@@ -1 +1 @@
1
- import{default as r}from"../../packem_shared/zeptomailProvider-DKBPSHPj.js";export{r as zeptomailProvider};
1
+ import{default as r}from"../../packem_shared/zeptomailProvider-DUesgbC-.js";export{r as zeptomailProvider};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Rewrites `cid:` references in `src`/`href` attributes using a resolver.
3
+ *
4
+ * Useful for turning inline (Content-ID) image references into hosted URLs for previews/webmail, or
5
+ * for normalizing them. Returning `undefined` from the resolver leaves that reference unchanged.
6
+ * @param html The HTML email.
7
+ * @param resolver Maps a Content-ID to a replacement URL (or `undefined` to keep it).
8
+ * @returns The rewritten HTML.
9
+ */
10
+ declare const rewriteCidLinks: (html: string, resolver: (cid: string) => string | undefined) => string;
11
+ /**
12
+ * Collects the Content-IDs referenced via `cid:` in `src`/`href` attributes.
13
+ * @param html The HTML email.
14
+ * @returns The referenced Content-IDs (de-duplicated, in first-seen order).
15
+ */
16
+ declare const extractCidReferences: (html: string) => string[];
17
+ export { extractCidReferences, rewriteCidLinks };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Inlines `&lt;style>`/linked CSS into element `style` attributes for maximum email-client
3
+ * compatibility, via [juice](https://github.com/Automattic/juice).
4
+ *
5
+ * `juice` is an optional peer dependency, and this helper is published as its own subpath
6
+ * (`@visulima/email/render/css-inline`). Importing this module resolves `juice` eagerly, so install
7
+ * it (`pnpm add juice`) before importing — consumers who never inline CSS simply never import this
8
+ * entry, which keeps `juice` out of edge/worker bundles.
9
+ * @param html The HTML email.
10
+ * @param options Options forwarded to `juice` (e.g. `preserveImportant`, `removeStyleTags`).
11
+ * @returns The HTML with CSS inlined.
12
+ * @throws {EmailError} When inlining fails.
13
+ */
14
+ declare const inlineCss: (html: string, options?: Record<string, unknown>) => string;
15
+ export { inlineCss as default };
@@ -0,0 +1 @@
1
+ import t from"juice";import n from"../packem_shared/EmailError-B-sEf3bp.js";const i=(r,o)=>{const a=t.default??t;try{return a(r,o)}catch(e){throw new n("render",`Failed to inline CSS: ${e.message}`,{cause:e})}};export{i as default};
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Options for {@link addDarkModeSupport}.
3
+ */
4
+ interface DarkModeOptions {
5
+ /**
6
+ * Extra CSS to wrap in a `@media (prefers-color-scheme: dark)` block (the dark-mode overrides).
7
+ */
8
+ styles?: string;
9
+ }
10
+ /**
11
+ * Adds dark-mode hooks to an HTML email: the `color-scheme` / `supported-color-schemes` meta tags and,
12
+ * when provided, a `@media (prefers-color-scheme: dark)` style block.
13
+ *
14
+ * Injected into `&lt;head>` (created after `&lt;html>` if absent, otherwise prepended).
15
+ * @param html The HTML email.
16
+ * @param options Dark-mode options. See {@link DarkModeOptions}.
17
+ * @returns The HTML with dark-mode support added.
18
+ */
19
+ declare const addDarkModeSupport: (html: string, options?: DarkModeOptions) => string;
20
+ export { DarkModeOptions, addDarkModeSupport };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Options for {@link injectPreheader}.
3
+ */
4
+ interface PreheaderOptions {
5
+ /**
6
+ * Append invisible padding characters so the preheader text isn't followed by leaked body content
7
+ * in the inbox preview.
8
+ * @default true
9
+ */
10
+ spacer?: boolean;
11
+ }
12
+ /**
13
+ * Injects a hidden preheader (inbox preview text) at the start of the HTML body.
14
+ *
15
+ * The preheader is wrapped in a `display:none` element with `mso-hide:all`, followed by zero-width
16
+ * padding so the preview shows only your text. Inserted right after `&lt;body>` (or prepended if no
17
+ * body tag is present).
18
+ * @param html The HTML email.
19
+ * @param preheader The preview text.
20
+ * @param options Injection options. See {@link PreheaderOptions}.
21
+ * @returns The HTML with the preheader injected.
22
+ */
23
+ declare const injectPreheader: (html: string, preheader: string, options?: PreheaderOptions) => string;
24
+ export { PreheaderOptions, injectPreheader };
@@ -1 +1 @@
1
- import{emailMatchers as a,registerEmailMatchers as o,toHaveSentMatching as r,toHaveSentTo as i,toHaveSentWithAttachment as m,toHaveSentWithSubject as h}from"../packem_shared/emailMatchers-DZDkrZ_3.js";import{toEmailSnapshot as c}from"../packem_shared/toEmailSnapshot-DeRqM5SJ.js";import{createTestEmail as s}from"../packem_shared/createTestEmail-D3XPGiHY.js";export{s as createTestEmail,a as emailMatchers,o as registerEmailMatchers,c as toEmailSnapshot,r as toHaveSentMatching,i as toHaveSentTo,m as toHaveSentWithAttachment,h as toHaveSentWithSubject};
1
+ import{emailMatchers as a,registerEmailMatchers as o,toHaveSentMatching as r,toHaveSentTo as i,toHaveSentWithAttachment as m,toHaveSentWithSubject as h}from"../packem_shared/emailMatchers-DZDkrZ_3.js";import{toEmailSnapshot as c}from"../packem_shared/toEmailSnapshot-DeRqM5SJ.js";import{createTestEmail as s}from"../packem_shared/createTestEmail-f12yLlWn.js";export{s as createTestEmail,a as emailMatchers,o as registerEmailMatchers,c as toEmailSnapshot,r as toHaveSentMatching,i as toHaveSentTo,m as toHaveSentWithAttachment,h as toHaveSentWithSubject};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visulima/email",
3
- "version": "1.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "A comprehensive email library with multi-provider support, crypto utilities, and template engines",
5
5
  "keywords": [
6
6
  "ahasend",
@@ -63,11 +63,6 @@
63
63
  ],
64
64
  "homepage": "https://visulima.com/packages/email",
65
65
  "bugs": "https://github.com/visulima/visulima/issues",
66
- "license": "MIT",
67
- "author": {
68
- "name": "Daniel Bannert",
69
- "email": "d.bannert@anolilab.de"
70
- },
71
66
  "repository": {
72
67
  "type": "git",
73
68
  "url": "git+https://github.com/visulima/visulima.git",
@@ -83,13 +78,13 @@
83
78
  "url": "https://anolilab.com/support"
84
79
  }
85
80
  ],
86
- "files": [
87
- "dist",
88
- "README.md",
89
- "CHANGELOG.md"
90
- ],
91
- "type": "module",
81
+ "license": "MIT",
82
+ "author": {
83
+ "name": "Daniel Bannert",
84
+ "email": "d.bannert@anolilab.de"
85
+ },
92
86
  "sideEffects": false,
87
+ "type": "module",
93
88
  "exports": {
94
89
  ".": {
95
90
  "types": "./dist/index.d.ts",
@@ -127,6 +122,10 @@
127
122
  "types": "./dist/template-engines/i18n.d.ts",
128
123
  "default": "./dist/template-engines/i18n.js"
129
124
  },
125
+ "./providers/autosend": {
126
+ "types": "./dist/providers/autosend/index.d.ts",
127
+ "default": "./dist/providers/autosend/index.js"
128
+ },
130
129
  "./providers/aws-ses": {
131
130
  "types": "./dist/providers/aws-ses/index.d.ts",
132
131
  "default": "./dist/providers/aws-ses/index.js"
@@ -179,9 +178,21 @@
179
178
  "types": "./dist/crypto/index.d.ts",
180
179
  "default": "./dist/crypto/index.js"
181
180
  },
182
- "./render": {
183
- "types": "./dist/render/index.d.ts",
184
- "default": "./dist/render/index.js"
181
+ "./render/cid": {
182
+ "types": "./dist/render/cid.d.ts",
183
+ "default": "./dist/render/cid.js"
184
+ },
185
+ "./render/css-inline": {
186
+ "types": "./dist/render/css-inline.d.ts",
187
+ "default": "./dist/render/css-inline.js"
188
+ },
189
+ "./render/dark-mode": {
190
+ "types": "./dist/render/dark-mode.d.ts",
191
+ "default": "./dist/render/dark-mode.js"
192
+ },
193
+ "./render/preheader": {
194
+ "types": "./dist/render/preheader.d.ts",
195
+ "default": "./dist/render/preheader.js"
185
196
  },
186
197
  "./webhooks": {
187
198
  "types": "./dist/webhooks/index.d.ts",
@@ -353,10 +364,11 @@
353
364
  },
354
365
  "./package.json": "./package.json"
355
366
  },
356
- "publishConfig": {
357
- "access": "public",
358
- "provenance": true
359
- },
367
+ "files": [
368
+ "dist",
369
+ "README.md",
370
+ "CHANGELOG.md"
371
+ ],
360
372
  "dependencies": {
361
373
  "html-to-text": "^10.0.0",
362
374
  "ical-generator": "11.0.0",
@@ -421,5 +433,9 @@
421
433
  },
422
434
  "engines": {
423
435
  "node": "^22.14.0 || >=24.10.0"
436
+ },
437
+ "publishConfig": {
438
+ "access": "public",
439
+ "provenance": true
424
440
  }
425
441
  }
@@ -1 +0,0 @@
1
- import{createRequire as i}from"node:module";import r from"./EmailError-B-sEf3bp.js";const a=i(import.meta.url),n=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,c=o=>{if(typeof n<"u"&&n.versions&&n.versions.node){const[s,t]=n.versions.node.split(".").map(Number);if(s>22||s===22&&t>=3||s===20&&t>=16)return n.getBuiltinModule(o)}return a(o)},{createRequire:u}=c("node:module"),d=u(import.meta.url),p=(o,s)=>{let t;try{const e=d("juice");t=e.default??e}catch(e){throw e instanceof Error&&(e.code==="MODULE_NOT_FOUND"||e.message.includes("Cannot find module")||e.message.includes("Cannot find package"))?new r("render","juice is not installed. Please install it: pnpm add juice",{cause:e}):new r("render",`Failed to load juice: ${e.message}`,{cause:e})}try{return t(o,s)}catch(e){throw new r("render",`Failed to inline CSS: ${e.message}`,{cause:e})}};export{p as default};
@@ -1 +0,0 @@
1
- import{s as u}from"./headers-to-record-De1Eg951.js";const p=o=>{const{fetchToken:r,headerName:s="Authorization",now:t=Date.now,onToken:n,scheme:c="Bearer",skewMs:i=6e4}=o;let e;const h=async()=>(e&&(e.expiresAt===void 0||e.expiresAt-i>t())&&e||(e=await r(),n?.(e)),e);return async(a,d)=>{const w=await h(),k=a.headers?u(a.headers):{};return d({...a,headers:{...k,[s]:`${c} ${w.accessToken}`}})}};export{p as oauth2Middleware};
@@ -1 +0,0 @@
1
- import u from"./EmailError-B-sEf3bp.js";import h from"./RequiredOptionError-DuNNY_a5.js";import{e as y}from"./generate-message-id-gXAuMz4g.js";import{m as k}from"./make-request-BlK_B72c.js";import{u as v}from"./retry-3pnxTuNs.js";import{f as A}from"./validate-email-options-mCM9dVug.js";import{defineProvider as b}from"./defineProvider-C9q-7iwt.js";import{c as w}from"./attachment-processor-CMp7qqMI.js";import{h as I,P as S,c as P}from"./provider-base-C7PuopYK.js";const a="outlook365",j="https://graph.microsoft.com/v1.0",R=3e4,x=3,o=t=>[t].flat(),c=t=>t.map(s=>({emailAddress:{address:s.email,...s.name?{name:s.name}:{}}})),q=b((t={})=>{if(!t.accessToken&&!t.getAccessToken)throw new h(a,["accessToken","getAccessToken"]);const s={accessToken:t.accessToken,debug:t.debug??!1,endpoint:t.endpoint??j,getAccessToken:t.getAccessToken,logger:t.logger,retries:t.retries??x,saveToSentItems:t.saveToSentItems??!0,timeout:t.timeout??R,userId:t.userId??"me"},p=new S,f=P(a,t.logger),g=async()=>s.getAccessToken?s.getAccessToken():s.accessToken;return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!1,tracking:!1},async initialize(){p.setInitialized()},async isAvailable(){return!!(s.accessToken??s.getAccessToken)},name:a,options:s,async sendEmail(e){try{const n=A(e);if(n.length>0)return{error:new u(a,`Invalid email options: ${n.join(", ")}`),success:!1};let d;try{d=await g()}catch(m){return{error:new u(a,"Failed to obtain access token",{cause:m}),success:!1}}const r={body:{content:e.html??e.text??"",contentType:e.html?"HTML":"Text"},subject:e.subject,toRecipients:c(o(e.to))};e.cc&&(r.ccRecipients=c(o(e.cc))),e.bcc&&(r.bccRecipients=c(o(e.bcc))),e.replyTo&&(r.replyTo=c(o(e.replyTo))),e.importance&&(r.importance=e.importance),e.attachments&&e.attachments.length>0&&(r.attachments=await Promise.all(e.attachments.map(async m=>{const l=await w(m,a);return{"@odata.type":"#microsoft.graph.fileAttachment",contentBytes:l.content,contentType:l.contentType,name:l.filename}})));const T=s.userId==="me"?"me":`users/${s.userId}`,i=await v(async()=>k(`${s.endpoint}/${T}/sendMail`,{headers:{Authorization:`Bearer ${d}`,"Content-Type":"application/json"},method:"POST",timeout:s.timeout},JSON.stringify({message:r,saveToSentItems:s.saveToSentItems})),s.retries);return i.success?{data:{messageId:y(),provider:a,response:i.data,sent:!0,timestamp:new Date},success:!0}:{error:i.error??new u(a,"Failed to send email"),success:!1}}catch(n){return{error:I(a,"send email",n,f),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{q as default};
@@ -1 +0,0 @@
1
- import{rewriteCidLinks as i}from"./extractCidReferences-BuoTREMp.js";import d from"./inlineCss-BQ7d2Cyz.js";import{addDarkModeSupport as t}from"./addDarkModeSupport-DZYxULjl.js";import{injectPreheader as s}from"./injectPreheader-CF9WHZ7J.js";const c=(e,r={})=>{let o=e;return r.inlineCss&&(o=d(o,typeof r.inlineCss=="object"?r.inlineCss:void 0)),r.preheader!==void 0&&(o=s(o,r.preheader,r.preheaderOptions)),r.darkMode&&(o=t(o,typeof r.darkMode=="object"?r.darkMode:void 0)),r.cidResolver&&(o=i(o,r.cidResolver)),o};export{c as postProcessHtml};
@@ -1,107 +0,0 @@
1
- /**
2
- * Rewrites `cid:` references in `src`/`href` attributes using a resolver.
3
- *
4
- * Useful for turning inline (Content-ID) image references into hosted URLs for previews/webmail, or
5
- * for normalizing them. Returning `undefined` from the resolver leaves that reference unchanged.
6
- * @param html The HTML email.
7
- * @param resolver Maps a Content-ID to a replacement URL (or `undefined` to keep it).
8
- * @returns The rewritten HTML.
9
- */
10
- declare const rewriteCidLinks: (html: string, resolver: (cid: string) => string | undefined) => string;
11
- /**
12
- * Collects the Content-IDs referenced via `cid:` in `src`/`href` attributes.
13
- * @param html The HTML email.
14
- * @returns The referenced Content-IDs (de-duplicated, in first-seen order).
15
- */
16
- declare const extractCidReferences: (html: string) => string[];
17
- /**
18
- * Inlines `&lt;style>`/linked CSS into element `style` attributes for maximum email-client
19
- * compatibility, via [juice](https://github.com/Automattic/juice).
20
- *
21
- * `juice` is an optional peer dependency — install it (`pnpm add juice`) to use this. It is loaded
22
- * lazily (via `createRequire`) so importing the render entry point doesn't fail when `juice` is absent.
23
- * @param html The HTML email.
24
- * @param options Options forwarded to `juice` (e.g. `preserveImportant`, `removeStyleTags`).
25
- * @returns The HTML with CSS inlined.
26
- * @throws {EmailError} When `juice` is not installed or inlining fails.
27
- */
28
- declare const inlineCss: (html: string, options?: Record<string, unknown>) => string;
29
- /**
30
- * Options for {@link addDarkModeSupport}.
31
- */
32
- interface DarkModeOptions {
33
- /**
34
- * Extra CSS to wrap in a `@media (prefers-color-scheme: dark)` block (the dark-mode overrides).
35
- */
36
- styles?: string;
37
- }
38
- /**
39
- * Adds dark-mode hooks to an HTML email: the `color-scheme` / `supported-color-schemes` meta tags and,
40
- * when provided, a `@media (prefers-color-scheme: dark)` style block.
41
- *
42
- * Injected into `&lt;head>` (created after `&lt;html>` if absent, otherwise prepended).
43
- * @param html The HTML email.
44
- * @param options Dark-mode options. See {@link DarkModeOptions}.
45
- * @returns The HTML with dark-mode support added.
46
- */
47
- declare const addDarkModeSupport: (html: string, options?: DarkModeOptions) => string;
48
- /**
49
- * Options for {@link injectPreheader}.
50
- */
51
- interface PreheaderOptions {
52
- /**
53
- * Append invisible padding characters so the preheader text isn't followed by leaked body content
54
- * in the inbox preview.
55
- * @default true
56
- */
57
- spacer?: boolean;
58
- }
59
- /**
60
- * Injects a hidden preheader (inbox preview text) at the start of the HTML body.
61
- *
62
- * The preheader is wrapped in a `display:none` element with `mso-hide:all`, followed by zero-width
63
- * padding so the preview shows only your text. Inserted right after `&lt;body>` (or prepended if no
64
- * body tag is present).
65
- * @param html The HTML email.
66
- * @param preheader The preview text.
67
- * @param options Injection options. See {@link PreheaderOptions}.
68
- * @returns The HTML with the preheader injected.
69
- */
70
- declare const injectPreheader: (html: string, preheader: string, options?: PreheaderOptions) => string;
71
- /**
72
- * Options for {@link postProcessHtml}. Each step runs only when its option is set; the order is
73
- * CSS-inline → preheader → dark-mode → CID rewrite.
74
- */
75
- interface PostProcessOptions {
76
- /**
77
- * Rewrite `cid:` references using this resolver (see {@link rewriteCidLinks}).
78
- */
79
- cidResolver?: (cid: string) => string | undefined;
80
- /**
81
- * Add dark-mode hooks. `true` adds the meta tags only; an object also injects dark CSS.
82
- */
83
- darkMode?: DarkModeOptions | boolean;
84
- /**
85
- * Inline CSS via `juice`. `true` uses defaults; an object forwards options to `juice`.
86
- */
87
- inlineCss?: Record<string, unknown> | boolean;
88
- /**
89
- * Inject hidden preview text at the top of the body.
90
- */
91
- preheader?: string;
92
- /**
93
- * Options for the preheader injection.
94
- */
95
- preheaderOptions?: PreheaderOptions;
96
- }
97
- /**
98
- * Runs an HTML email through the selected post-processing steps.
99
- *
100
- * A convenience pipeline over {@link inlineCss}, {@link injectPreheader}, {@link addDarkModeSupport} and
101
- * {@link rewriteCidLinks}. Only the steps whose options are provided run.
102
- * @param html The HTML email.
103
- * @param options Which steps to apply. See {@link PostProcessOptions}.
104
- * @returns The processed HTML.
105
- */
106
- declare const postProcessHtml: (html: string, options?: PostProcessOptions) => string;
107
- export { type DarkModeOptions, type PostProcessOptions, type PreheaderOptions, addDarkModeSupport, extractCidReferences, injectPreheader, inlineCss, postProcessHtml, rewriteCidLinks };
@@ -1 +0,0 @@
1
- import{extractCidReferences as o,rewriteCidLinks as t}from"../packem_shared/extractCidReferences-BuoTREMp.js";import{default as s}from"../packem_shared/inlineCss-BQ7d2Cyz.js";import{addDarkModeSupport as f}from"../packem_shared/addDarkModeSupport-DZYxULjl.js";import{postProcessHtml as a}from"../packem_shared/postProcessHtml-DqKi2Ucg.js";import{injectPreheader as x}from"../packem_shared/injectPreheader-CF9WHZ7J.js";export{f as addDarkModeSupport,o as extractCidReferences,x as injectPreheader,s as inlineCss,a as postProcessHtml,t as rewriteCidLinks};