@strapi/provider-email-sendmail 5.45.1 → 5.46.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.
package/README.md CHANGED
@@ -23,14 +23,25 @@ npm install @strapi/provider-email-sendmail --save
23
23
 
24
24
  ## Configuration
25
25
 
26
- | Variable | Type | Description | Required | Default |
27
- | ----------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------ | -------- | --------- |
28
- | provider | string | The name of the provider you use | yes | |
29
- | providerOptions | object | Will be directly given to `require('sendmail')`. Please refer to [sendmail](https://www.npmjs.com/package/sendmail) doc. | no | {} |
30
- | settings | object | Settings | no | {} |
31
- | settings.defaultFrom | string | Default sender mail address | no | undefined |
32
- | settings.defaultReplyTo | string \| array | Default address or addresses the receiver is asked to reply to | no | undefined |
33
- | providerOptions.dkim | object \| boolean | DKIM parameters having two properties: { privateKey, keySelector } | no | false |
26
+ This provider implements the same **direct SMTP delivery** model as the historical `sendmail` npm package (MX lookup per recipient domain, optional DKIM, development mode to target a local SMTP capture server). It uses **Nodemailer** for MIME generation and SMTP transport instead of the unmaintained `sendmail` / `mailcomposer` stack.
27
+
28
+ | Variable | Type | Description | Required | Default |
29
+ | ------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | --------- |
30
+ | provider | string | The name of the provider you use | yes | |
31
+ | providerOptions | object | Options below (same names as the legacy `sendmail` package where applicable). | no | {} |
32
+ | settings | object | Settings | no | {} |
33
+ | settings.defaultFrom | string | Default sender mail address | no | undefined |
34
+ | settings.defaultReplyTo | string \| array | Default address or addresses the receiver is asked to reply to | no | undefined |
35
+ | providerOptions.dkim | object \| boolean | DKIM parameters: `{ privateKey, keySelector? }` (passed to Nodemailer’s DKIM signing). | no | false |
36
+ | providerOptions.silent | boolean | Suppress default console logging from the provider (default merged to `true` unless overridden). | no | (merged) |
37
+ | providerOptions.devPort | number | If set to a **positive** port, delivery targets `devHost:devPort` instead of performing MX DNS (e.g. MailHog / local test SMTP). **The connection uses this port** (same as the legacy package). | no | -1 |
38
+ | providerOptions.devHost | string | Host for development mode (default `localhost`). | no | localhost |
39
+ | providerOptions.smtpPort | number | Outbound SMTP port when **not** in `devPort` mode (default **25**). | no | 25 |
40
+ | providerOptions.smtpHost | string | Extra hostname tried after MX records for each domain (legacy behavior). | no | -1 |
41
+
42
+ MIME is now produced with **Nodemailer** instead of the old `mailcomposer` stack, so the raw message may not match the legacy package byte-for-byte; routing and documented `providerOptions` stay the same.
43
+
44
+ You can pass through **additional Nodemailer mail fields** on each `send()` (for example `headers`, `messageId`, `textEncoding`, `priority`) if you need finer control.
34
45
 
35
46
  > :warning: The Shipper Email (or defaultfrom) may also need to be changed in the `Email Templates` tab on the admin panel for emails to send properly
36
47
 
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Address parsing and grouping — aligned with the legacy `sendmail` npm package
3
+ * (guileen/node-sendmail) behavior for recipient grouping and domain extraction.
4
+ */
5
+ /** Extract bare email from `Name <email@domain>` or return trimmed input (linear time, no regex). */
6
+ export declare function extractEmail(address: string): string;
7
+ /** Split address lists (legacy package accepted both string and array). */
8
+ export declare function parseAddressList(addresses: string | string[] | undefined): string[];
9
+ /** Domain part of an email address (after the last `@`). */
10
+ export declare function getHostFromAddress(email: string): string | undefined;
11
+ /** Group recipient addresses by recipient domain (MX routing key). */
12
+ export declare function groupRecipientsByDomain(recipients: string[]): Record<string, string[]>;
13
+ /** Collect all recipients from to / cc / bcc (same sources as legacy sendmail). */
14
+ export declare function collectRecipients(mail: {
15
+ to?: string | string[];
16
+ cc?: string | string[];
17
+ bcc?: string | string[];
18
+ }): string[];
19
+ //# sourceMappingURL=addressing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addressing.d.ts","sourceRoot":"","sources":["../src/addressing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qGAAqG;AACrG,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAWpD;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,CAWnF;AAWD,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOpE;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAUtF;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB,GAAG,MAAM,EAAE,CAMX"}
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Address parsing and grouping — aligned with the legacy `sendmail` npm package
5
+ * (guileen/node-sendmail) behavior for recipient grouping and domain extraction.
6
+ */ /** Extract bare email from `Name <email@domain>` or return trimmed input (linear time, no regex). */ function extractEmail(address) {
7
+ const trimmed = address.trim();
8
+ const open = trimmed.indexOf('<');
9
+ if (open === -1) {
10
+ return trimmed;
11
+ }
12
+ const close = trimmed.indexOf('>', open + 1);
13
+ if (close === -1) {
14
+ return trimmed;
15
+ }
16
+ return trimmed.slice(open + 1, close).trim();
17
+ }
18
+ /** Split address lists (legacy package accepted both string and array). */ function parseAddressList(addresses) {
19
+ if (!addresses) {
20
+ return [];
21
+ }
22
+ if (Array.isArray(addresses)) {
23
+ return addresses.map((a)=>extractEmail(String(a))).filter((a)=>a.length > 0);
24
+ }
25
+ return addresses.split(',').map((a)=>extractEmail(a)).filter((a)=>a.length > 0);
26
+ }
27
+ /** Legacy sendmail host extraction regex from guileen/node-sendmail@1.6.1. */ const LEGACY_HOST_REGEX = /[^@]+@([\w\d\-.]+)/;
28
+ /**
29
+ * Do not run the legacy regex on unbounded input (defense in depth; the pattern is not ReDoS-prone,
30
+ * but capping work is cheap and matches RFC 5321 practical address size expectations).
31
+ */ const MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX = 320;
32
+ /** Domain part of an email address (after the last `@`). */ function getHostFromAddress(email) {
33
+ const normalized = extractEmail(email);
34
+ if (normalized.length > MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX) {
35
+ return undefined;
36
+ }
37
+ const match = LEGACY_HOST_REGEX.exec(normalized);
38
+ return match?.[1];
39
+ }
40
+ /** Group recipient addresses by recipient domain (MX routing key). */ function groupRecipientsByDomain(recipients) {
41
+ const groups = {};
42
+ for (const raw of recipients){
43
+ const host = String(getHostFromAddress(raw));
44
+ if (!groups[host]) {
45
+ groups[host] = [];
46
+ }
47
+ groups[host].push(raw);
48
+ }
49
+ return groups;
50
+ }
51
+ /** Collect all recipients from to / cc / bcc (same sources as legacy sendmail). */ function collectRecipients(mail) {
52
+ return [
53
+ ...parseAddressList(mail.to),
54
+ ...parseAddressList(mail.cc),
55
+ ...parseAddressList(mail.bcc)
56
+ ];
57
+ }
58
+
59
+ exports.collectRecipients = collectRecipients;
60
+ exports.extractEmail = extractEmail;
61
+ exports.getHostFromAddress = getHostFromAddress;
62
+ exports.groupRecipientsByDomain = groupRecipientsByDomain;
63
+ exports.parseAddressList = parseAddressList;
64
+ //# sourceMappingURL=addressing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addressing.js","sources":["../src/addressing.ts"],"sourcesContent":["/**\n * Address parsing and grouping — aligned with the legacy `sendmail` npm package\n * (guileen/node-sendmail) behavior for recipient grouping and domain extraction.\n */\n\n/** Extract bare email from `Name <email@domain>` or return trimmed input (linear time, no regex). */\nexport function extractEmail(address: string): string {\n const trimmed = address.trim();\n const open = trimmed.indexOf('<');\n if (open === -1) {\n return trimmed;\n }\n const close = trimmed.indexOf('>', open + 1);\n if (close === -1) {\n return trimmed;\n }\n return trimmed.slice(open + 1, close).trim();\n}\n\n/** Split address lists (legacy package accepted both string and array). */\nexport function parseAddressList(addresses: string | string[] | undefined): string[] {\n if (!addresses) {\n return [];\n }\n if (Array.isArray(addresses)) {\n return addresses.map((a) => extractEmail(String(a))).filter((a) => a.length > 0);\n }\n return addresses\n .split(',')\n .map((a) => extractEmail(a))\n .filter((a) => a.length > 0);\n}\n\n/** Legacy sendmail host extraction regex from guileen/node-sendmail@1.6.1. */\nconst LEGACY_HOST_REGEX = /[^@]+@([\\w\\d\\-.]+)/;\n\n/**\n * Do not run the legacy regex on unbounded input (defense in depth; the pattern is not ReDoS-prone,\n * but capping work is cheap and matches RFC 5321 practical address size expectations).\n */\nconst MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX = 320;\n\n/** Domain part of an email address (after the last `@`). */\nexport function getHostFromAddress(email: string): string | undefined {\n const normalized = extractEmail(email);\n if (normalized.length > MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX) {\n return undefined;\n }\n const match = LEGACY_HOST_REGEX.exec(normalized);\n return match?.[1];\n}\n\n/** Group recipient addresses by recipient domain (MX routing key). */\nexport function groupRecipientsByDomain(recipients: string[]): Record<string, string[]> {\n const groups: Record<string, string[]> = {};\n for (const raw of recipients) {\n const host = String(getHostFromAddress(raw));\n if (!groups[host]) {\n groups[host] = [];\n }\n groups[host].push(raw);\n }\n return groups;\n}\n\n/** Collect all recipients from to / cc / bcc (same sources as legacy sendmail). */\nexport function collectRecipients(mail: {\n to?: string | string[];\n cc?: string | string[];\n bcc?: string | string[];\n}): string[] {\n return [\n ...parseAddressList(mail.to),\n ...parseAddressList(mail.cc),\n ...parseAddressList(mail.bcc),\n ];\n}\n"],"names":["extractEmail","address","trimmed","trim","open","indexOf","close","slice","parseAddressList","addresses","Array","isArray","map","a","String","filter","length","split","LEGACY_HOST_REGEX","MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX","getHostFromAddress","email","normalized","undefined","match","exec","groupRecipientsByDomain","recipients","groups","raw","host","push","collectRecipients","mail","to","cc","bcc"],"mappings":";;AAAA;;;AAGC,0GAGM,SAASA,aAAaC,OAAe,EAAA;IAC1C,MAAMC,OAAAA,GAAUD,QAAQE,IAAI,EAAA;IAC5B,MAAMC,IAAAA,GAAOF,OAAAA,CAAQG,OAAO,CAAC,GAAA,CAAA;IAC7B,IAAID,IAAAA,KAAS,EAAC,EAAG;QACf,OAAOF,OAAAA;AACT,IAAA;AACA,IAAA,MAAMI,KAAAA,GAAQJ,OAAAA,CAAQG,OAAO,CAAC,KAAKD,IAAAA,GAAO,CAAA,CAAA;IAC1C,IAAIE,KAAAA,KAAU,EAAC,EAAG;QAChB,OAAOJ,OAAAA;AACT,IAAA;AACA,IAAA,OAAOA,QAAQK,KAAK,CAACH,IAAAA,GAAO,CAAA,EAAGE,OAAOH,IAAI,EAAA;AAC5C;AAEA,4EACO,SAASK,gBAAAA,CAAiBC,SAAwC,EAAA;AACvE,IAAA,IAAI,CAACA,SAAAA,EAAW;AACd,QAAA,OAAO,EAAE;AACX,IAAA;IACA,IAAIC,KAAAA,CAAMC,OAAO,CAACF,SAAAA,CAAAA,EAAY;AAC5B,QAAA,OAAOA,SAAAA,CAAUG,GAAG,CAAC,CAACC,IAAMb,YAAAA,CAAac,MAAAA,CAAOD,CAAAA,CAAAA,CAAAA,CAAAA,CAAKE,MAAM,CAAC,CAACF,CAAAA,GAAMA,CAAAA,CAAEG,MAAM,GAAG,CAAA,CAAA;AAChF,IAAA;AACA,IAAA,OAAOP,UACJQ,KAAK,CAAC,GAAA,CAAA,CACNL,GAAG,CAAC,CAACC,CAAAA,GAAMb,YAAAA,CAAaa,CAAAA,CAAAA,CAAAA,CACxBE,MAAM,CAAC,CAACF,CAAAA,GAAMA,CAAAA,CAAEG,MAAM,GAAG,CAAA,CAAA;AAC9B;AAEA,+EACA,MAAME,iBAAAA,GAAoB,oBAAA;AAE1B;;;AAGC,IACD,MAAMC,mCAAAA,GAAsC,GAAA;AAE5C,6DACO,SAASC,kBAAAA,CAAmBC,KAAa,EAAA;AAC9C,IAAA,MAAMC,aAAatB,YAAAA,CAAaqB,KAAAA,CAAAA;IAChC,IAAIC,UAAAA,CAAWN,MAAM,GAAGG,mCAAAA,EAAqC;QAC3D,OAAOI,SAAAA;AACT,IAAA;IACA,MAAMC,KAAAA,GAAQN,iBAAAA,CAAkBO,IAAI,CAACH,UAAAA,CAAAA;IACrC,OAAOE,KAAAA,GAAQ,CAAA,CAAE;AACnB;AAEA,uEACO,SAASE,uBAAAA,CAAwBC,UAAoB,EAAA;AAC1D,IAAA,MAAMC,SAAmC,EAAC;IAC1C,KAAK,MAAMC,OAAOF,UAAAA,CAAY;QAC5B,MAAMG,IAAAA,GAAOhB,OAAOM,kBAAAA,CAAmBS,GAAAA,CAAAA,CAAAA;AACvC,QAAA,IAAI,CAACD,MAAM,CAACE,IAAAA,CAAK,EAAE;YACjBF,MAAM,CAACE,IAAAA,CAAK,GAAG,EAAE;AACnB,QAAA;AACAF,QAAAA,MAAM,CAACE,IAAAA,CAAK,CAACC,IAAI,CAACF,GAAAA,CAAAA;AACpB,IAAA;IACA,OAAOD,MAAAA;AACT;AAEA,oFACO,SAASI,iBAAAA,CAAkBC,IAIjC,EAAA;IACC,OAAO;AACFzB,QAAAA,GAAAA,gBAAAA,CAAiByB,KAAKC,EAAE,CAAA;AACxB1B,QAAAA,GAAAA,gBAAAA,CAAiByB,KAAKE,EAAE,CAAA;AACxB3B,QAAAA,GAAAA,gBAAAA,CAAiByB,KAAKG,GAAG;AAC7B,KAAA;AACH;;;;;;;;"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Address parsing and grouping — aligned with the legacy `sendmail` npm package
3
+ * (guileen/node-sendmail) behavior for recipient grouping and domain extraction.
4
+ */ /** Extract bare email from `Name <email@domain>` or return trimmed input (linear time, no regex). */ function extractEmail(address) {
5
+ const trimmed = address.trim();
6
+ const open = trimmed.indexOf('<');
7
+ if (open === -1) {
8
+ return trimmed;
9
+ }
10
+ const close = trimmed.indexOf('>', open + 1);
11
+ if (close === -1) {
12
+ return trimmed;
13
+ }
14
+ return trimmed.slice(open + 1, close).trim();
15
+ }
16
+ /** Split address lists (legacy package accepted both string and array). */ function parseAddressList(addresses) {
17
+ if (!addresses) {
18
+ return [];
19
+ }
20
+ if (Array.isArray(addresses)) {
21
+ return addresses.map((a)=>extractEmail(String(a))).filter((a)=>a.length > 0);
22
+ }
23
+ return addresses.split(',').map((a)=>extractEmail(a)).filter((a)=>a.length > 0);
24
+ }
25
+ /** Legacy sendmail host extraction regex from guileen/node-sendmail@1.6.1. */ const LEGACY_HOST_REGEX = /[^@]+@([\w\d\-.]+)/;
26
+ /**
27
+ * Do not run the legacy regex on unbounded input (defense in depth; the pattern is not ReDoS-prone,
28
+ * but capping work is cheap and matches RFC 5321 practical address size expectations).
29
+ */ const MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX = 320;
30
+ /** Domain part of an email address (after the last `@`). */ function getHostFromAddress(email) {
31
+ const normalized = extractEmail(email);
32
+ if (normalized.length > MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX) {
33
+ return undefined;
34
+ }
35
+ const match = LEGACY_HOST_REGEX.exec(normalized);
36
+ return match?.[1];
37
+ }
38
+ /** Group recipient addresses by recipient domain (MX routing key). */ function groupRecipientsByDomain(recipients) {
39
+ const groups = {};
40
+ for (const raw of recipients){
41
+ const host = String(getHostFromAddress(raw));
42
+ if (!groups[host]) {
43
+ groups[host] = [];
44
+ }
45
+ groups[host].push(raw);
46
+ }
47
+ return groups;
48
+ }
49
+ /** Collect all recipients from to / cc / bcc (same sources as legacy sendmail). */ function collectRecipients(mail) {
50
+ return [
51
+ ...parseAddressList(mail.to),
52
+ ...parseAddressList(mail.cc),
53
+ ...parseAddressList(mail.bcc)
54
+ ];
55
+ }
56
+
57
+ export { collectRecipients, extractEmail, getHostFromAddress, groupRecipientsByDomain, parseAddressList };
58
+ //# sourceMappingURL=addressing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addressing.mjs","sources":["../src/addressing.ts"],"sourcesContent":["/**\n * Address parsing and grouping — aligned with the legacy `sendmail` npm package\n * (guileen/node-sendmail) behavior for recipient grouping and domain extraction.\n */\n\n/** Extract bare email from `Name <email@domain>` or return trimmed input (linear time, no regex). */\nexport function extractEmail(address: string): string {\n const trimmed = address.trim();\n const open = trimmed.indexOf('<');\n if (open === -1) {\n return trimmed;\n }\n const close = trimmed.indexOf('>', open + 1);\n if (close === -1) {\n return trimmed;\n }\n return trimmed.slice(open + 1, close).trim();\n}\n\n/** Split address lists (legacy package accepted both string and array). */\nexport function parseAddressList(addresses: string | string[] | undefined): string[] {\n if (!addresses) {\n return [];\n }\n if (Array.isArray(addresses)) {\n return addresses.map((a) => extractEmail(String(a))).filter((a) => a.length > 0);\n }\n return addresses\n .split(',')\n .map((a) => extractEmail(a))\n .filter((a) => a.length > 0);\n}\n\n/** Legacy sendmail host extraction regex from guileen/node-sendmail@1.6.1. */\nconst LEGACY_HOST_REGEX = /[^@]+@([\\w\\d\\-.]+)/;\n\n/**\n * Do not run the legacy regex on unbounded input (defense in depth; the pattern is not ReDoS-prone,\n * but capping work is cheap and matches RFC 5321 practical address size expectations).\n */\nconst MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX = 320;\n\n/** Domain part of an email address (after the last `@`). */\nexport function getHostFromAddress(email: string): string | undefined {\n const normalized = extractEmail(email);\n if (normalized.length > MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX) {\n return undefined;\n }\n const match = LEGACY_HOST_REGEX.exec(normalized);\n return match?.[1];\n}\n\n/** Group recipient addresses by recipient domain (MX routing key). */\nexport function groupRecipientsByDomain(recipients: string[]): Record<string, string[]> {\n const groups: Record<string, string[]> = {};\n for (const raw of recipients) {\n const host = String(getHostFromAddress(raw));\n if (!groups[host]) {\n groups[host] = [];\n }\n groups[host].push(raw);\n }\n return groups;\n}\n\n/** Collect all recipients from to / cc / bcc (same sources as legacy sendmail). */\nexport function collectRecipients(mail: {\n to?: string | string[];\n cc?: string | string[];\n bcc?: string | string[];\n}): string[] {\n return [\n ...parseAddressList(mail.to),\n ...parseAddressList(mail.cc),\n ...parseAddressList(mail.bcc),\n ];\n}\n"],"names":["extractEmail","address","trimmed","trim","open","indexOf","close","slice","parseAddressList","addresses","Array","isArray","map","a","String","filter","length","split","LEGACY_HOST_REGEX","MAX_INPUT_LEN_FOR_LEGACY_HOST_REGEX","getHostFromAddress","email","normalized","undefined","match","exec","groupRecipientsByDomain","recipients","groups","raw","host","push","collectRecipients","mail","to","cc","bcc"],"mappings":"AAAA;;;AAGC,0GAGM,SAASA,aAAaC,OAAe,EAAA;IAC1C,MAAMC,OAAAA,GAAUD,QAAQE,IAAI,EAAA;IAC5B,MAAMC,IAAAA,GAAOF,OAAAA,CAAQG,OAAO,CAAC,GAAA,CAAA;IAC7B,IAAID,IAAAA,KAAS,EAAC,EAAG;QACf,OAAOF,OAAAA;AACT,IAAA;AACA,IAAA,MAAMI,KAAAA,GAAQJ,OAAAA,CAAQG,OAAO,CAAC,KAAKD,IAAAA,GAAO,CAAA,CAAA;IAC1C,IAAIE,KAAAA,KAAU,EAAC,EAAG;QAChB,OAAOJ,OAAAA;AACT,IAAA;AACA,IAAA,OAAOA,QAAQK,KAAK,CAACH,IAAAA,GAAO,CAAA,EAAGE,OAAOH,IAAI,EAAA;AAC5C;AAEA,4EACO,SAASK,gBAAAA,CAAiBC,SAAwC,EAAA;AACvE,IAAA,IAAI,CAACA,SAAAA,EAAW;AACd,QAAA,OAAO,EAAE;AACX,IAAA;IACA,IAAIC,KAAAA,CAAMC,OAAO,CAACF,SAAAA,CAAAA,EAAY;AAC5B,QAAA,OAAOA,SAAAA,CAAUG,GAAG,CAAC,CAACC,IAAMb,YAAAA,CAAac,MAAAA,CAAOD,CAAAA,CAAAA,CAAAA,CAAAA,CAAKE,MAAM,CAAC,CAACF,CAAAA,GAAMA,CAAAA,CAAEG,MAAM,GAAG,CAAA,CAAA;AAChF,IAAA;AACA,IAAA,OAAOP,UACJQ,KAAK,CAAC,GAAA,CAAA,CACNL,GAAG,CAAC,CAACC,CAAAA,GAAMb,YAAAA,CAAaa,CAAAA,CAAAA,CAAAA,CACxBE,MAAM,CAAC,CAACF,CAAAA,GAAMA,CAAAA,CAAEG,MAAM,GAAG,CAAA,CAAA;AAC9B;AAEA,+EACA,MAAME,iBAAAA,GAAoB,oBAAA;AAE1B;;;AAGC,IACD,MAAMC,mCAAAA,GAAsC,GAAA;AAE5C,6DACO,SAASC,kBAAAA,CAAmBC,KAAa,EAAA;AAC9C,IAAA,MAAMC,aAAatB,YAAAA,CAAaqB,KAAAA,CAAAA;IAChC,IAAIC,UAAAA,CAAWN,MAAM,GAAGG,mCAAAA,EAAqC;QAC3D,OAAOI,SAAAA;AACT,IAAA;IACA,MAAMC,KAAAA,GAAQN,iBAAAA,CAAkBO,IAAI,CAACH,UAAAA,CAAAA;IACrC,OAAOE,KAAAA,GAAQ,CAAA,CAAE;AACnB;AAEA,uEACO,SAASE,uBAAAA,CAAwBC,UAAoB,EAAA;AAC1D,IAAA,MAAMC,SAAmC,EAAC;IAC1C,KAAK,MAAMC,OAAOF,UAAAA,CAAY;QAC5B,MAAMG,IAAAA,GAAOhB,OAAOM,kBAAAA,CAAmBS,GAAAA,CAAAA,CAAAA;AACvC,QAAA,IAAI,CAACD,MAAM,CAACE,IAAAA,CAAK,EAAE;YACjBF,MAAM,CAACE,IAAAA,CAAK,GAAG,EAAE;AACnB,QAAA;AACAF,QAAAA,MAAM,CAACE,IAAAA,CAAK,CAACC,IAAI,CAACF,GAAAA,CAAAA;AACpB,IAAA;IACA,OAAOD,MAAAA;AACT;AAEA,oFACO,SAASI,iBAAAA,CAAkBC,IAIjC,EAAA;IACC,OAAO;AACFzB,QAAAA,GAAAA,gBAAAA,CAAiByB,KAAKC,EAAE,CAAA;AACxB1B,QAAAA,GAAAA,gBAAAA,CAAiByB,KAAKE,EAAE,CAAA;AACxB3B,QAAAA,GAAAA,gBAAAA,CAAiByB,KAAKG,GAAG;AAC7B,KAAA;AACH;;;;"}
@@ -0,0 +1,15 @@
1
+ import type { SendMailOptions } from 'nodemailer';
2
+ import type { ProviderSendmailOptions } from './types';
3
+ /**
4
+ * Build list of SMTP peers to try for a recipient domain (MX resolution or dev server),
5
+ * matching guileen/node-sendmail `connectMx` + `smtpHost` append behavior.
6
+ */
7
+ export declare function resolveMxHosts(domain: string, options: ProviderSendmailOptions): Promise<Array<{
8
+ exchange: string;
9
+ }>>;
10
+ /**
11
+ * Direct SMTP delivery (per recipient domain, per MX with fallback), replacing the
12
+ * unmaintained `sendmail` npm package while preserving the same routing semantics.
13
+ */
14
+ export declare function sendDirectSmtp(mail: SendMailOptions, providerOptions: ProviderSendmailOptions): Promise<void>;
15
+ //# sourceMappingURL=direct-smtp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-smtp.d.ts","sourceRoot":"","sources":["../src/direct-smtp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,YAAY,CAAC;AASnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAiCvD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CA+BtC;AA0CD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,eAAe,EACrB,eAAe,EAAE,uBAAuB,GACvC,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
@@ -0,0 +1,162 @@
1
+ 'use strict';
2
+
3
+ var promises = require('dns/promises');
4
+ var os = require('os');
5
+ var nodemailer = require('nodemailer');
6
+ var addressing = require('./addressing.js');
7
+ var logger = require('./logger.js');
8
+
9
+ /**
10
+ * Mirrors legacy `const devPort = options.devPort || -1` (guileen/node-sendmail).
11
+ * `0` is falsy → `-1` (MX mode). `true` is truthy and was passed to `createConnection` (Node
12
+ * coerces port `true` to `1`).
13
+ */ function getEffectiveDevPort(options) {
14
+ const v = options.devPort;
15
+ if (v === undefined || v === false || v === null) {
16
+ return -1;
17
+ }
18
+ if (v === true) {
19
+ return 1;
20
+ }
21
+ if (typeof v === 'number') {
22
+ return v || -1;
23
+ }
24
+ return -1;
25
+ }
26
+ /**
27
+ * Legacy `sendmail` connects with `createConnection(devPort, devHost)` in dev mode — the
28
+ * dev port is the SMTP port. Otherwise use `smtpPort` (default 25).
29
+ */ function getOutboundSmtpPort(options) {
30
+ const dev = getEffectiveDevPort(options);
31
+ if (dev !== -1) {
32
+ return dev;
33
+ }
34
+ return options.smtpPort || 25;
35
+ }
36
+ /**
37
+ * Build list of SMTP peers to try for a recipient domain (MX resolution or dev server),
38
+ * matching guileen/node-sendmail `connectMx` + `smtpHost` append behavior.
39
+ */ async function resolveMxHosts(domain, options) {
40
+ const devPort = getEffectiveDevPort(options);
41
+ const devHost = options.devHost || 'localhost';
42
+ if (devPort !== -1) {
43
+ return [
44
+ {
45
+ exchange: devHost
46
+ }
47
+ ];
48
+ }
49
+ let records;
50
+ try {
51
+ records = await promises.resolveMx(domain);
52
+ } catch (err) {
53
+ const e = err instanceof Error ? err : new Error(String(err));
54
+ throw new Error(`can not resolve Mx of <${domain}>: ${e.message}`);
55
+ }
56
+ if (!records || records.length === 0) {
57
+ throw new Error(`can not resolve Mx of <${domain}>`);
58
+ }
59
+ records.sort((a, b)=>a.priority - b.priority);
60
+ // Mirror legacy `const smtpHost = options.smtpHost || -1` behavior: falsy (eg 0) disables.
61
+ const smtpHost = options.smtpHost || -1;
62
+ if (smtpHost !== -1) {
63
+ records.push({
64
+ exchange: String(smtpHost),
65
+ priority: 9999
66
+ });
67
+ }
68
+ return records.map((r)=>({
69
+ exchange: r.exchange.replace(/\.$/, '')
70
+ }));
71
+ }
72
+ async function trySendViaHost(exchange, smtpPort, srcHost, fromEnvelope, recipients, mail, dkim, options) {
73
+ const transporter = nodemailer.createTransport({
74
+ host: exchange,
75
+ port: smtpPort,
76
+ secure: false,
77
+ // Legacy sendmail@1.6.1 uses plain SMTP sockets and does not attempt STARTTLS.
78
+ ignoreTLS: true,
79
+ requireTLS: false,
80
+ name: srcHost,
81
+ tls: {
82
+ rejectUnauthorized: options.rejectUnauthorized
83
+ },
84
+ connectionTimeout: 60000,
85
+ greetingTimeout: 30000,
86
+ socketTimeout: 60000
87
+ });
88
+ try {
89
+ return await transporter.sendMail({
90
+ ...mail,
91
+ envelope: {
92
+ from: fromEnvelope,
93
+ to: recipients
94
+ },
95
+ dkim
96
+ });
97
+ } finally{
98
+ transporter.close();
99
+ }
100
+ }
101
+ /**
102
+ * Direct SMTP delivery (per recipient domain, per MX with fallback), replacing the
103
+ * unmaintained `sendmail` npm package while preserving the same routing semantics.
104
+ */ async function sendDirectSmtp(mail, providerOptions) {
105
+ const logger$1 = logger.createLogger(providerOptions);
106
+ const smtpPort = getOutboundSmtpPort(providerOptions);
107
+ const fromHeader = String(mail.from || '');
108
+ const fromAddr = addressing.extractEmail(fromHeader);
109
+ const fromHost = addressing.getHostFromAddress(fromAddr);
110
+ const srcHost = fromHost || os.hostname() || 'localhost';
111
+ const dkimOpt = providerOptions.dkim;
112
+ const dkim = dkimOpt && typeof dkimOpt === 'object' && 'privateKey' in dkimOpt ? {
113
+ domainName: srcHost,
114
+ keySelector: dkimOpt.keySelector || 'dkim',
115
+ privateKey: dkimOpt.privateKey
116
+ } : undefined;
117
+ const recipients = addressing.collectRecipients({
118
+ to: mail.to,
119
+ cc: mail.cc,
120
+ bcc: mail.bcc
121
+ });
122
+ if (recipients.length === 0) {
123
+ throw new Error('No recipients defined');
124
+ }
125
+ const groups = addressing.groupRecipientsByDomain(recipients);
126
+ const fromEnvelope = fromAddr;
127
+ let anyDomainDelivered = false;
128
+ for (const domain of Object.keys(groups)){
129
+ const domainRecipients = groups[domain];
130
+ let hosts;
131
+ try {
132
+ hosts = await resolveMxHosts(domain, providerOptions);
133
+ } catch (err) {
134
+ logger$1.error('Sendmail provider: MX resolution failed', err);
135
+ throw err instanceof Error ? err : new Error(String(err));
136
+ }
137
+ let lastError;
138
+ let sent = false;
139
+ for (const { exchange } of hosts){
140
+ try {
141
+ await trySendViaHost(exchange, smtpPort, srcHost, fromEnvelope, domainRecipients, mail, dkim, providerOptions);
142
+ sent = true;
143
+ break;
144
+ } catch (err) {
145
+ lastError = err instanceof Error ? err : new Error(String(err));
146
+ logger$1.error(`Sendmail provider: failed to send via ${exchange}:${smtpPort}`, lastError);
147
+ }
148
+ }
149
+ if (sent) {
150
+ anyDomainDelivered = true;
151
+ } else {
152
+ logger$1.error(`Sendmail provider: failed to deliver for domain ${domain}`, lastError);
153
+ }
154
+ }
155
+ if (!anyDomainDelivered) {
156
+ throw new Error('Failed to deliver mail for all recipient domains');
157
+ }
158
+ }
159
+
160
+ exports.resolveMxHosts = resolveMxHosts;
161
+ exports.sendDirectSmtp = sendDirectSmtp;
162
+ //# sourceMappingURL=direct-smtp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-smtp.js","sources":["../src/direct-smtp.ts"],"sourcesContent":["import { resolveMx as dnsResolveMx } from 'dns/promises';\nimport { hostname as osHostname } from 'os';\nimport nodemailer from 'nodemailer';\nimport type { SentMessageInfo, SendMailOptions } from 'nodemailer';\n\nimport {\n collectRecipients,\n extractEmail,\n getHostFromAddress,\n groupRecipientsByDomain,\n} from './addressing';\nimport { createLogger } from './logger';\nimport type { ProviderSendmailOptions } from './types';\n\n/**\n * Mirrors legacy `const devPort = options.devPort || -1` (guileen/node-sendmail).\n * `0` is falsy → `-1` (MX mode). `true` is truthy and was passed to `createConnection` (Node\n * coerces port `true` to `1`).\n */\nfunction getEffectiveDevPort(options: ProviderSendmailOptions): number {\n const v = options.devPort;\n if (v === undefined || v === false || v === null) {\n return -1;\n }\n if (v === true) {\n return 1;\n }\n if (typeof v === 'number') {\n return v || -1;\n }\n return -1;\n}\n\n/**\n * Legacy `sendmail` connects with `createConnection(devPort, devHost)` in dev mode — the\n * dev port is the SMTP port. Otherwise use `smtpPort` (default 25).\n */\nfunction getOutboundSmtpPort(options: ProviderSendmailOptions): number {\n const dev = getEffectiveDevPort(options);\n if (dev !== -1) {\n return dev;\n }\n return options.smtpPort || 25;\n}\n\n/**\n * Build list of SMTP peers to try for a recipient domain (MX resolution or dev server),\n * matching guileen/node-sendmail `connectMx` + `smtpHost` append behavior.\n */\nexport async function resolveMxHosts(\n domain: string,\n options: ProviderSendmailOptions\n): Promise<Array<{ exchange: string }>> {\n const devPort = getEffectiveDevPort(options);\n const devHost = options.devHost || 'localhost';\n\n if (devPort !== -1) {\n return [{ exchange: devHost }];\n }\n\n let records: Awaited<ReturnType<typeof dnsResolveMx>>;\n try {\n records = await dnsResolveMx(domain);\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n throw new Error(`can not resolve Mx of <${domain}>: ${e.message}`);\n }\n\n if (!records || records.length === 0) {\n throw new Error(`can not resolve Mx of <${domain}>`);\n }\n\n records.sort((a, b) => a.priority - b.priority);\n\n // Mirror legacy `const smtpHost = options.smtpHost || -1` behavior: falsy (eg 0) disables.\n const smtpHost = options.smtpHost || -1;\n if (smtpHost !== -1) {\n records.push({ exchange: String(smtpHost), priority: 9999 });\n }\n\n return records.map((r) => ({\n exchange: r.exchange.replace(/\\.$/, ''),\n }));\n}\n\nasync function trySendViaHost(\n exchange: string,\n smtpPort: number,\n srcHost: string,\n fromEnvelope: string,\n recipients: string[],\n mail: SendMailOptions,\n dkim: SendMailOptions['dkim'],\n options: ProviderSendmailOptions\n): Promise<SentMessageInfo> {\n const transporter = nodemailer.createTransport({\n host: exchange,\n port: smtpPort,\n secure: false,\n // Legacy sendmail@1.6.1 uses plain SMTP sockets and does not attempt STARTTLS.\n ignoreTLS: true,\n requireTLS: false,\n name: srcHost,\n tls: {\n rejectUnauthorized: options.rejectUnauthorized,\n },\n connectionTimeout: 60_000,\n greetingTimeout: 30_000,\n socketTimeout: 60_000,\n });\n\n try {\n return await transporter.sendMail({\n ...mail,\n envelope: {\n from: fromEnvelope,\n to: recipients,\n },\n dkim,\n });\n } finally {\n transporter.close();\n }\n}\n\n/**\n * Direct SMTP delivery (per recipient domain, per MX with fallback), replacing the\n * unmaintained `sendmail` npm package while preserving the same routing semantics.\n */\nexport async function sendDirectSmtp(\n mail: SendMailOptions,\n providerOptions: ProviderSendmailOptions\n): Promise<void> {\n const logger = createLogger(providerOptions);\n const smtpPort = getOutboundSmtpPort(providerOptions);\n\n const fromHeader = String(mail.from || '');\n const fromAddr = extractEmail(fromHeader);\n const fromHost = getHostFromAddress(fromAddr);\n const srcHost = fromHost || osHostname() || 'localhost';\n\n const dkimOpt = providerOptions.dkim;\n const dkim: SendMailOptions['dkim'] =\n dkimOpt && typeof dkimOpt === 'object' && 'privateKey' in dkimOpt\n ? {\n domainName: srcHost,\n keySelector: dkimOpt.keySelector || 'dkim',\n privateKey: dkimOpt.privateKey,\n }\n : undefined;\n\n const recipients = collectRecipients({\n to: mail.to as string | string[] | undefined,\n cc: mail.cc as string | string[] | undefined,\n bcc: mail.bcc as string | string[] | undefined,\n });\n\n if (recipients.length === 0) {\n throw new Error('No recipients defined');\n }\n\n const groups = groupRecipientsByDomain(recipients);\n const fromEnvelope = fromAddr;\n\n let anyDomainDelivered = false;\n\n for (const domain of Object.keys(groups)) {\n const domainRecipients = groups[domain];\n let hosts: Array<{ exchange: string }>;\n try {\n hosts = await resolveMxHosts(domain, providerOptions);\n } catch (err) {\n logger.error('Sendmail provider: MX resolution failed', err);\n throw err instanceof Error ? err : new Error(String(err));\n }\n\n let lastError: Error | undefined;\n let sent = false;\n\n for (const { exchange } of hosts) {\n try {\n await trySendViaHost(\n exchange,\n smtpPort,\n srcHost,\n fromEnvelope,\n domainRecipients,\n mail,\n dkim,\n providerOptions\n );\n sent = true;\n break;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n logger.error(`Sendmail provider: failed to send via ${exchange}:${smtpPort}`, lastError);\n }\n }\n\n if (sent) {\n anyDomainDelivered = true;\n } else {\n logger.error(`Sendmail provider: failed to deliver for domain ${domain}`, lastError);\n }\n }\n\n if (!anyDomainDelivered) {\n throw new Error('Failed to deliver mail for all recipient domains');\n }\n}\n"],"names":["getEffectiveDevPort","options","v","devPort","undefined","getOutboundSmtpPort","dev","smtpPort","resolveMxHosts","domain","devHost","exchange","records","dnsResolveMx","err","e","Error","String","message","length","sort","a","b","priority","smtpHost","push","map","r","replace","trySendViaHost","srcHost","fromEnvelope","recipients","mail","dkim","transporter","nodemailer","createTransport","host","port","secure","ignoreTLS","requireTLS","name","tls","rejectUnauthorized","connectionTimeout","greetingTimeout","socketTimeout","sendMail","envelope","from","to","close","sendDirectSmtp","providerOptions","logger","createLogger","fromHeader","fromAddr","extractEmail","fromHost","getHostFromAddress","osHostname","dkimOpt","domainName","keySelector","privateKey","collectRecipients","cc","bcc","groups","groupRecipientsByDomain","anyDomainDelivered","Object","keys","domainRecipients","hosts","error","lastError","sent"],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { resolveMx } from 'dns/promises';
2
+ import { hostname } from 'os';
3
+ import nodemailer from 'nodemailer';
4
+ import { extractEmail, getHostFromAddress, collectRecipients, groupRecipientsByDomain } from './addressing.mjs';
5
+ import { createLogger } from './logger.mjs';
6
+
7
+ /**
8
+ * Mirrors legacy `const devPort = options.devPort || -1` (guileen/node-sendmail).
9
+ * `0` is falsy → `-1` (MX mode). `true` is truthy and was passed to `createConnection` (Node
10
+ * coerces port `true` to `1`).
11
+ */ function getEffectiveDevPort(options) {
12
+ const v = options.devPort;
13
+ if (v === undefined || v === false || v === null) {
14
+ return -1;
15
+ }
16
+ if (v === true) {
17
+ return 1;
18
+ }
19
+ if (typeof v === 'number') {
20
+ return v || -1;
21
+ }
22
+ return -1;
23
+ }
24
+ /**
25
+ * Legacy `sendmail` connects with `createConnection(devPort, devHost)` in dev mode — the
26
+ * dev port is the SMTP port. Otherwise use `smtpPort` (default 25).
27
+ */ function getOutboundSmtpPort(options) {
28
+ const dev = getEffectiveDevPort(options);
29
+ if (dev !== -1) {
30
+ return dev;
31
+ }
32
+ return options.smtpPort || 25;
33
+ }
34
+ /**
35
+ * Build list of SMTP peers to try for a recipient domain (MX resolution or dev server),
36
+ * matching guileen/node-sendmail `connectMx` + `smtpHost` append behavior.
37
+ */ async function resolveMxHosts(domain, options) {
38
+ const devPort = getEffectiveDevPort(options);
39
+ const devHost = options.devHost || 'localhost';
40
+ if (devPort !== -1) {
41
+ return [
42
+ {
43
+ exchange: devHost
44
+ }
45
+ ];
46
+ }
47
+ let records;
48
+ try {
49
+ records = await resolveMx(domain);
50
+ } catch (err) {
51
+ const e = err instanceof Error ? err : new Error(String(err));
52
+ throw new Error(`can not resolve Mx of <${domain}>: ${e.message}`);
53
+ }
54
+ if (!records || records.length === 0) {
55
+ throw new Error(`can not resolve Mx of <${domain}>`);
56
+ }
57
+ records.sort((a, b)=>a.priority - b.priority);
58
+ // Mirror legacy `const smtpHost = options.smtpHost || -1` behavior: falsy (eg 0) disables.
59
+ const smtpHost = options.smtpHost || -1;
60
+ if (smtpHost !== -1) {
61
+ records.push({
62
+ exchange: String(smtpHost),
63
+ priority: 9999
64
+ });
65
+ }
66
+ return records.map((r)=>({
67
+ exchange: r.exchange.replace(/\.$/, '')
68
+ }));
69
+ }
70
+ async function trySendViaHost(exchange, smtpPort, srcHost, fromEnvelope, recipients, mail, dkim, options) {
71
+ const transporter = nodemailer.createTransport({
72
+ host: exchange,
73
+ port: smtpPort,
74
+ secure: false,
75
+ // Legacy sendmail@1.6.1 uses plain SMTP sockets and does not attempt STARTTLS.
76
+ ignoreTLS: true,
77
+ requireTLS: false,
78
+ name: srcHost,
79
+ tls: {
80
+ rejectUnauthorized: options.rejectUnauthorized
81
+ },
82
+ connectionTimeout: 60000,
83
+ greetingTimeout: 30000,
84
+ socketTimeout: 60000
85
+ });
86
+ try {
87
+ return await transporter.sendMail({
88
+ ...mail,
89
+ envelope: {
90
+ from: fromEnvelope,
91
+ to: recipients
92
+ },
93
+ dkim
94
+ });
95
+ } finally{
96
+ transporter.close();
97
+ }
98
+ }
99
+ /**
100
+ * Direct SMTP delivery (per recipient domain, per MX with fallback), replacing the
101
+ * unmaintained `sendmail` npm package while preserving the same routing semantics.
102
+ */ async function sendDirectSmtp(mail, providerOptions) {
103
+ const logger = createLogger(providerOptions);
104
+ const smtpPort = getOutboundSmtpPort(providerOptions);
105
+ const fromHeader = String(mail.from || '');
106
+ const fromAddr = extractEmail(fromHeader);
107
+ const fromHost = getHostFromAddress(fromAddr);
108
+ const srcHost = fromHost || hostname() || 'localhost';
109
+ const dkimOpt = providerOptions.dkim;
110
+ const dkim = dkimOpt && typeof dkimOpt === 'object' && 'privateKey' in dkimOpt ? {
111
+ domainName: srcHost,
112
+ keySelector: dkimOpt.keySelector || 'dkim',
113
+ privateKey: dkimOpt.privateKey
114
+ } : undefined;
115
+ const recipients = collectRecipients({
116
+ to: mail.to,
117
+ cc: mail.cc,
118
+ bcc: mail.bcc
119
+ });
120
+ if (recipients.length === 0) {
121
+ throw new Error('No recipients defined');
122
+ }
123
+ const groups = groupRecipientsByDomain(recipients);
124
+ const fromEnvelope = fromAddr;
125
+ let anyDomainDelivered = false;
126
+ for (const domain of Object.keys(groups)){
127
+ const domainRecipients = groups[domain];
128
+ let hosts;
129
+ try {
130
+ hosts = await resolveMxHosts(domain, providerOptions);
131
+ } catch (err) {
132
+ logger.error('Sendmail provider: MX resolution failed', err);
133
+ throw err instanceof Error ? err : new Error(String(err));
134
+ }
135
+ let lastError;
136
+ let sent = false;
137
+ for (const { exchange } of hosts){
138
+ try {
139
+ await trySendViaHost(exchange, smtpPort, srcHost, fromEnvelope, domainRecipients, mail, dkim, providerOptions);
140
+ sent = true;
141
+ break;
142
+ } catch (err) {
143
+ lastError = err instanceof Error ? err : new Error(String(err));
144
+ logger.error(`Sendmail provider: failed to send via ${exchange}:${smtpPort}`, lastError);
145
+ }
146
+ }
147
+ if (sent) {
148
+ anyDomainDelivered = true;
149
+ } else {
150
+ logger.error(`Sendmail provider: failed to deliver for domain ${domain}`, lastError);
151
+ }
152
+ }
153
+ if (!anyDomainDelivered) {
154
+ throw new Error('Failed to deliver mail for all recipient domains');
155
+ }
156
+ }
157
+
158
+ export { resolveMxHosts, sendDirectSmtp };
159
+ //# sourceMappingURL=direct-smtp.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-smtp.mjs","sources":["../src/direct-smtp.ts"],"sourcesContent":["import { resolveMx as dnsResolveMx } from 'dns/promises';\nimport { hostname as osHostname } from 'os';\nimport nodemailer from 'nodemailer';\nimport type { SentMessageInfo, SendMailOptions } from 'nodemailer';\n\nimport {\n collectRecipients,\n extractEmail,\n getHostFromAddress,\n groupRecipientsByDomain,\n} from './addressing';\nimport { createLogger } from './logger';\nimport type { ProviderSendmailOptions } from './types';\n\n/**\n * Mirrors legacy `const devPort = options.devPort || -1` (guileen/node-sendmail).\n * `0` is falsy → `-1` (MX mode). `true` is truthy and was passed to `createConnection` (Node\n * coerces port `true` to `1`).\n */\nfunction getEffectiveDevPort(options: ProviderSendmailOptions): number {\n const v = options.devPort;\n if (v === undefined || v === false || v === null) {\n return -1;\n }\n if (v === true) {\n return 1;\n }\n if (typeof v === 'number') {\n return v || -1;\n }\n return -1;\n}\n\n/**\n * Legacy `sendmail` connects with `createConnection(devPort, devHost)` in dev mode — the\n * dev port is the SMTP port. Otherwise use `smtpPort` (default 25).\n */\nfunction getOutboundSmtpPort(options: ProviderSendmailOptions): number {\n const dev = getEffectiveDevPort(options);\n if (dev !== -1) {\n return dev;\n }\n return options.smtpPort || 25;\n}\n\n/**\n * Build list of SMTP peers to try for a recipient domain (MX resolution or dev server),\n * matching guileen/node-sendmail `connectMx` + `smtpHost` append behavior.\n */\nexport async function resolveMxHosts(\n domain: string,\n options: ProviderSendmailOptions\n): Promise<Array<{ exchange: string }>> {\n const devPort = getEffectiveDevPort(options);\n const devHost = options.devHost || 'localhost';\n\n if (devPort !== -1) {\n return [{ exchange: devHost }];\n }\n\n let records: Awaited<ReturnType<typeof dnsResolveMx>>;\n try {\n records = await dnsResolveMx(domain);\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n throw new Error(`can not resolve Mx of <${domain}>: ${e.message}`);\n }\n\n if (!records || records.length === 0) {\n throw new Error(`can not resolve Mx of <${domain}>`);\n }\n\n records.sort((a, b) => a.priority - b.priority);\n\n // Mirror legacy `const smtpHost = options.smtpHost || -1` behavior: falsy (eg 0) disables.\n const smtpHost = options.smtpHost || -1;\n if (smtpHost !== -1) {\n records.push({ exchange: String(smtpHost), priority: 9999 });\n }\n\n return records.map((r) => ({\n exchange: r.exchange.replace(/\\.$/, ''),\n }));\n}\n\nasync function trySendViaHost(\n exchange: string,\n smtpPort: number,\n srcHost: string,\n fromEnvelope: string,\n recipients: string[],\n mail: SendMailOptions,\n dkim: SendMailOptions['dkim'],\n options: ProviderSendmailOptions\n): Promise<SentMessageInfo> {\n const transporter = nodemailer.createTransport({\n host: exchange,\n port: smtpPort,\n secure: false,\n // Legacy sendmail@1.6.1 uses plain SMTP sockets and does not attempt STARTTLS.\n ignoreTLS: true,\n requireTLS: false,\n name: srcHost,\n tls: {\n rejectUnauthorized: options.rejectUnauthorized,\n },\n connectionTimeout: 60_000,\n greetingTimeout: 30_000,\n socketTimeout: 60_000,\n });\n\n try {\n return await transporter.sendMail({\n ...mail,\n envelope: {\n from: fromEnvelope,\n to: recipients,\n },\n dkim,\n });\n } finally {\n transporter.close();\n }\n}\n\n/**\n * Direct SMTP delivery (per recipient domain, per MX with fallback), replacing the\n * unmaintained `sendmail` npm package while preserving the same routing semantics.\n */\nexport async function sendDirectSmtp(\n mail: SendMailOptions,\n providerOptions: ProviderSendmailOptions\n): Promise<void> {\n const logger = createLogger(providerOptions);\n const smtpPort = getOutboundSmtpPort(providerOptions);\n\n const fromHeader = String(mail.from || '');\n const fromAddr = extractEmail(fromHeader);\n const fromHost = getHostFromAddress(fromAddr);\n const srcHost = fromHost || osHostname() || 'localhost';\n\n const dkimOpt = providerOptions.dkim;\n const dkim: SendMailOptions['dkim'] =\n dkimOpt && typeof dkimOpt === 'object' && 'privateKey' in dkimOpt\n ? {\n domainName: srcHost,\n keySelector: dkimOpt.keySelector || 'dkim',\n privateKey: dkimOpt.privateKey,\n }\n : undefined;\n\n const recipients = collectRecipients({\n to: mail.to as string | string[] | undefined,\n cc: mail.cc as string | string[] | undefined,\n bcc: mail.bcc as string | string[] | undefined,\n });\n\n if (recipients.length === 0) {\n throw new Error('No recipients defined');\n }\n\n const groups = groupRecipientsByDomain(recipients);\n const fromEnvelope = fromAddr;\n\n let anyDomainDelivered = false;\n\n for (const domain of Object.keys(groups)) {\n const domainRecipients = groups[domain];\n let hosts: Array<{ exchange: string }>;\n try {\n hosts = await resolveMxHosts(domain, providerOptions);\n } catch (err) {\n logger.error('Sendmail provider: MX resolution failed', err);\n throw err instanceof Error ? err : new Error(String(err));\n }\n\n let lastError: Error | undefined;\n let sent = false;\n\n for (const { exchange } of hosts) {\n try {\n await trySendViaHost(\n exchange,\n smtpPort,\n srcHost,\n fromEnvelope,\n domainRecipients,\n mail,\n dkim,\n providerOptions\n );\n sent = true;\n break;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n logger.error(`Sendmail provider: failed to send via ${exchange}:${smtpPort}`, lastError);\n }\n }\n\n if (sent) {\n anyDomainDelivered = true;\n } else {\n logger.error(`Sendmail provider: failed to deliver for domain ${domain}`, lastError);\n }\n }\n\n if (!anyDomainDelivered) {\n throw new Error('Failed to deliver mail for all recipient domains');\n }\n}\n"],"names":["getEffectiveDevPort","options","v","devPort","undefined","getOutboundSmtpPort","dev","smtpPort","resolveMxHosts","domain","devHost","exchange","records","dnsResolveMx","err","e","Error","String","message","length","sort","a","b","priority","smtpHost","push","map","r","replace","trySendViaHost","srcHost","fromEnvelope","recipients","mail","dkim","transporter","nodemailer","createTransport","host","port","secure","ignoreTLS","requireTLS","name","tls","rejectUnauthorized","connectionTimeout","greetingTimeout","socketTimeout","sendMail","envelope","from","to","close","sendDirectSmtp","providerOptions","logger","createLogger","fromHeader","fromAddr","extractEmail","fromHost","getHostFromAddress","osHostname","dkimOpt","domainName","keySelector","privateKey","collectRecipients","cc","bcc","groups","groupRecipientsByDomain","anyDomainDelivered","Object","keys","domainRecipients","hosts","error","lastError","sent"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,24 +1,20 @@
1
- import { Options } from 'sendmail';
2
- interface Settings {
3
- defaultFrom: string;
4
- defaultReplyTo: string;
5
- }
1
+ import type { ProviderSendmailOptions, Settings } from './types';
6
2
  interface SendOptions {
7
3
  from?: string;
8
4
  to: string;
9
- cc: string;
10
- bcc: string;
5
+ cc?: string;
6
+ bcc?: string;
11
7
  replyTo?: string;
12
8
  subject: string;
13
- text: string;
14
- html: string;
9
+ text?: string;
10
+ html?: string;
15
11
  [key: string]: unknown;
16
12
  }
17
- type ProviderOptions = Options;
18
13
  declare const _default: {
19
- init(providerOptions: ProviderOptions, settings: Settings): {
14
+ init(providerOptions: ProviderSendmailOptions, settings: Settings): {
20
15
  send(options: SendOptions): Promise<void>;
21
16
  };
22
17
  };
23
18
  export default _default;
19
+ export type { ProviderSendmailOptions, Settings } from './types';
24
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAwB,EAAE,OAAO,EAAa,MAAM,UAAU,CAAC;AAE/D,UAAU,QAAQ;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,KAAK,eAAe,GAAG,OAAO,CAAC;;0BAGP,eAAe,YAAY,QAAQ;sBAOvC,WAAW,GAAG,QAAQ,IAAI,CAAC;;;AAR/C,wBAmCE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjE,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;;0BAGuB,uBAAuB,YAAY,QAAQ;sBAO/C,WAAW,GAAG,QAAQ,IAAI,CAAC;;;AAR/C,wBA2BE;AAEF,YAAY,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,36 +1,28 @@
1
1
  'use strict';
2
2
 
3
- var sendmailFactory = require('sendmail');
3
+ var directSmtp = require('./direct-smtp.js');
4
4
 
5
5
  var index = {
6
6
  init (providerOptions, settings) {
7
- const sendmail = sendmailFactory({
7
+ const mergedOptions = {
8
8
  silent: true,
9
9
  ...providerOptions
10
- });
10
+ };
11
11
  return {
12
12
  send (options) {
13
- return new Promise((resolve, reject)=>{
14
- const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
15
- const msg = {
16
- from: from || settings.defaultFrom,
17
- to,
18
- cc,
19
- bcc,
20
- replyTo: replyTo || settings.defaultReplyTo,
21
- subject,
22
- text,
23
- html,
24
- ...rest
25
- };
26
- sendmail(msg, (err)=>{
27
- if (err) {
28
- reject(err);
29
- } else {
30
- resolve();
31
- }
32
- });
33
- });
13
+ const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
14
+ const mail = {
15
+ from: from || settings.defaultFrom,
16
+ to,
17
+ cc,
18
+ bcc,
19
+ replyTo: replyTo || settings.defaultReplyTo,
20
+ subject,
21
+ text,
22
+ html,
23
+ ...rest
24
+ };
25
+ return directSmtp.sendDirectSmtp(mail, mergedOptions);
34
26
  }
35
27
  };
36
28
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import sendmailFactory, { Options, MailInput } from 'sendmail';\n\ninterface Settings {\n defaultFrom: string;\n defaultReplyTo: string;\n}\n\ninterface SendOptions {\n from?: string;\n to: string;\n cc: string;\n bcc: string;\n replyTo?: string;\n subject: string;\n text: string;\n html: string;\n [key: string]: unknown;\n}\n\ntype ProviderOptions = Options;\n\nexport default {\n init(providerOptions: ProviderOptions, settings: Settings) {\n const sendmail = sendmailFactory({\n silent: true,\n ...providerOptions,\n });\n\n return {\n send(options: SendOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;\n\n const msg: MailInput = {\n from: from || settings.defaultFrom,\n to,\n cc,\n bcc,\n replyTo: replyTo || settings.defaultReplyTo,\n subject,\n text,\n html,\n ...rest,\n };\n\n sendmail(msg, (err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n },\n };\n },\n};\n"],"names":["init","providerOptions","settings","sendmail","sendmailFactory","silent","send","options","Promise","resolve","reject","from","to","cc","bcc","replyTo","subject","text","html","rest","msg","defaultFrom","defaultReplyTo","err"],"mappings":";;;;AAqBA,YAAe;IACbA,IAAAA,CAAAA,CAAKC,eAAgC,EAAEC,QAAkB,EAAA;AACvD,QAAA,MAAMC,WAAWC,eAAAA,CAAgB;YAC/BC,MAAAA,EAAQ,IAAA;AACR,YAAA,GAAGJ;AACL,SAAA,CAAA;QAEA,OAAO;AACLK,YAAAA,IAAAA,CAAAA,CAAKC,OAAoB,EAAA;gBACvB,OAAO,IAAIC,OAAAA,CAAQ,CAACC,OAAAA,EAASC,MAAAA,GAAAA;AAC3B,oBAAA,MAAM,EAAEC,IAAI,EAAEC,EAAE,EAAEC,EAAE,EAAEC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,IAAI,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGZ,OAAAA;AAErE,oBAAA,MAAMa,GAAAA,GAAiB;wBACrBT,IAAAA,EAAMA,IAAAA,IAAQT,SAASmB,WAAW;AAClCT,wBAAAA,EAAAA;AACAC,wBAAAA,EAAAA;AACAC,wBAAAA,GAAAA;wBACAC,OAAAA,EAASA,OAAAA,IAAWb,SAASoB,cAAc;AAC3CN,wBAAAA,OAAAA;AACAC,wBAAAA,IAAAA;AACAC,wBAAAA,IAAAA;AACA,wBAAA,GAAGC;AACL,qBAAA;AAEAhB,oBAAAA,QAAAA,CAASiB,KAAK,CAACG,GAAAA,GAAAA;AACb,wBAAA,IAAIA,GAAAA,EAAK;4BACPb,MAAAA,CAAOa,GAAAA,CAAAA;wBACT,CAAA,MAAO;AACLd,4BAAAA,OAAAA,EAAAA;AACF,wBAAA;AACF,oBAAA,CAAA,CAAA;AACF,gBAAA,CAAA,CAAA;AACF,YAAA;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { SendMailOptions } from 'nodemailer';\n\nimport { sendDirectSmtp } from './direct-smtp';\nimport type { ProviderSendmailOptions, Settings } from './types';\n\ninterface SendOptions {\n from?: string;\n to: string;\n cc?: string;\n bcc?: string;\n replyTo?: string;\n subject: string;\n text?: string;\n html?: string;\n [key: string]: unknown;\n}\n\nexport default {\n init(providerOptions: ProviderSendmailOptions, settings: Settings) {\n const mergedOptions: ProviderSendmailOptions = {\n silent: true,\n ...providerOptions,\n };\n\n return {\n send(options: SendOptions): Promise<void> {\n const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;\n\n const mail: SendMailOptions = {\n from: from || settings.defaultFrom,\n to,\n cc,\n bcc,\n replyTo: replyTo || settings.defaultReplyTo,\n subject,\n text,\n html,\n ...(rest as Record<string, unknown>),\n };\n\n return sendDirectSmtp(mail, mergedOptions);\n },\n };\n },\n};\n\nexport type { ProviderSendmailOptions, Settings } from './types';\n"],"names":["init","providerOptions","settings","mergedOptions","silent","send","options","from","to","cc","bcc","replyTo","subject","text","html","rest","mail","defaultFrom","defaultReplyTo","sendDirectSmtp"],"mappings":";;;;AAiBA,YAAe;IACbA,IAAAA,CAAAA,CAAKC,eAAwC,EAAEC,QAAkB,EAAA;AAC/D,QAAA,MAAMC,aAAAA,GAAyC;YAC7CC,MAAAA,EAAQ,IAAA;AACR,YAAA,GAAGH;AACL,SAAA;QAEA,OAAO;AACLI,YAAAA,IAAAA,CAAAA,CAAKC,OAAoB,EAAA;AACvB,gBAAA,MAAM,EAAEC,IAAI,EAAEC,EAAE,EAAEC,EAAE,EAAEC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,IAAI,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGT,OAAAA;AAErE,gBAAA,MAAMU,IAAAA,GAAwB;oBAC5BT,IAAAA,EAAMA,IAAAA,IAAQL,SAASe,WAAW;AAClCT,oBAAAA,EAAAA;AACAC,oBAAAA,EAAAA;AACAC,oBAAAA,GAAAA;oBACAC,OAAAA,EAASA,OAAAA,IAAWT,SAASgB,cAAc;AAC3CN,oBAAAA,OAAAA;AACAC,oBAAAA,IAAAA;AACAC,oBAAAA,IAAAA;AACA,oBAAA,GAAIC;AACN,iBAAA;AAEA,gBAAA,OAAOI,0BAAeH,IAAAA,EAAMb,aAAAA,CAAAA;AAC9B,YAAA;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
package/dist/index.mjs CHANGED
@@ -1,34 +1,26 @@
1
- import sendmailFactory from 'sendmail';
1
+ import { sendDirectSmtp } from './direct-smtp.mjs';
2
2
 
3
3
  var index = {
4
4
  init (providerOptions, settings) {
5
- const sendmail = sendmailFactory({
5
+ const mergedOptions = {
6
6
  silent: true,
7
7
  ...providerOptions
8
- });
8
+ };
9
9
  return {
10
10
  send (options) {
11
- return new Promise((resolve, reject)=>{
12
- const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
13
- const msg = {
14
- from: from || settings.defaultFrom,
15
- to,
16
- cc,
17
- bcc,
18
- replyTo: replyTo || settings.defaultReplyTo,
19
- subject,
20
- text,
21
- html,
22
- ...rest
23
- };
24
- sendmail(msg, (err)=>{
25
- if (err) {
26
- reject(err);
27
- } else {
28
- resolve();
29
- }
30
- });
31
- });
11
+ const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
12
+ const mail = {
13
+ from: from || settings.defaultFrom,
14
+ to,
15
+ cc,
16
+ bcc,
17
+ replyTo: replyTo || settings.defaultReplyTo,
18
+ subject,
19
+ text,
20
+ html,
21
+ ...rest
22
+ };
23
+ return sendDirectSmtp(mail, mergedOptions);
32
24
  }
33
25
  };
34
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import sendmailFactory, { Options, MailInput } from 'sendmail';\n\ninterface Settings {\n defaultFrom: string;\n defaultReplyTo: string;\n}\n\ninterface SendOptions {\n from?: string;\n to: string;\n cc: string;\n bcc: string;\n replyTo?: string;\n subject: string;\n text: string;\n html: string;\n [key: string]: unknown;\n}\n\ntype ProviderOptions = Options;\n\nexport default {\n init(providerOptions: ProviderOptions, settings: Settings) {\n const sendmail = sendmailFactory({\n silent: true,\n ...providerOptions,\n });\n\n return {\n send(options: SendOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;\n\n const msg: MailInput = {\n from: from || settings.defaultFrom,\n to,\n cc,\n bcc,\n replyTo: replyTo || settings.defaultReplyTo,\n subject,\n text,\n html,\n ...rest,\n };\n\n sendmail(msg, (err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n },\n };\n },\n};\n"],"names":["init","providerOptions","settings","sendmail","sendmailFactory","silent","send","options","Promise","resolve","reject","from","to","cc","bcc","replyTo","subject","text","html","rest","msg","defaultFrom","defaultReplyTo","err"],"mappings":";;AAqBA,YAAe;IACbA,IAAAA,CAAAA,CAAKC,eAAgC,EAAEC,QAAkB,EAAA;AACvD,QAAA,MAAMC,WAAWC,eAAAA,CAAgB;YAC/BC,MAAAA,EAAQ,IAAA;AACR,YAAA,GAAGJ;AACL,SAAA,CAAA;QAEA,OAAO;AACLK,YAAAA,IAAAA,CAAAA,CAAKC,OAAoB,EAAA;gBACvB,OAAO,IAAIC,OAAAA,CAAQ,CAACC,OAAAA,EAASC,MAAAA,GAAAA;AAC3B,oBAAA,MAAM,EAAEC,IAAI,EAAEC,EAAE,EAAEC,EAAE,EAAEC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,IAAI,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGZ,OAAAA;AAErE,oBAAA,MAAMa,GAAAA,GAAiB;wBACrBT,IAAAA,EAAMA,IAAAA,IAAQT,SAASmB,WAAW;AAClCT,wBAAAA,EAAAA;AACAC,wBAAAA,EAAAA;AACAC,wBAAAA,GAAAA;wBACAC,OAAAA,EAASA,OAAAA,IAAWb,SAASoB,cAAc;AAC3CN,wBAAAA,OAAAA;AACAC,wBAAAA,IAAAA;AACAC,wBAAAA,IAAAA;AACA,wBAAA,GAAGC;AACL,qBAAA;AAEAhB,oBAAAA,QAAAA,CAASiB,KAAK,CAACG,GAAAA,GAAAA;AACb,wBAAA,IAAIA,GAAAA,EAAK;4BACPb,MAAAA,CAAOa,GAAAA,CAAAA;wBACT,CAAA,MAAO;AACLd,4BAAAA,OAAAA,EAAAA;AACF,wBAAA;AACF,oBAAA,CAAA,CAAA;AACF,gBAAA,CAAA,CAAA;AACF,YAAA;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import type { SendMailOptions } from 'nodemailer';\n\nimport { sendDirectSmtp } from './direct-smtp';\nimport type { ProviderSendmailOptions, Settings } from './types';\n\ninterface SendOptions {\n from?: string;\n to: string;\n cc?: string;\n bcc?: string;\n replyTo?: string;\n subject: string;\n text?: string;\n html?: string;\n [key: string]: unknown;\n}\n\nexport default {\n init(providerOptions: ProviderSendmailOptions, settings: Settings) {\n const mergedOptions: ProviderSendmailOptions = {\n silent: true,\n ...providerOptions,\n };\n\n return {\n send(options: SendOptions): Promise<void> {\n const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;\n\n const mail: SendMailOptions = {\n from: from || settings.defaultFrom,\n to,\n cc,\n bcc,\n replyTo: replyTo || settings.defaultReplyTo,\n subject,\n text,\n html,\n ...(rest as Record<string, unknown>),\n };\n\n return sendDirectSmtp(mail, mergedOptions);\n },\n };\n },\n};\n\nexport type { ProviderSendmailOptions, Settings } from './types';\n"],"names":["init","providerOptions","settings","mergedOptions","silent","send","options","from","to","cc","bcc","replyTo","subject","text","html","rest","mail","defaultFrom","defaultReplyTo","sendDirectSmtp"],"mappings":";;AAiBA,YAAe;IACbA,IAAAA,CAAAA,CAAKC,eAAwC,EAAEC,QAAkB,EAAA;AAC/D,QAAA,MAAMC,aAAAA,GAAyC;YAC7CC,MAAAA,EAAQ,IAAA;AACR,YAAA,GAAGH;AACL,SAAA;QAEA,OAAO;AACLI,YAAAA,IAAAA,CAAAA,CAAKC,OAAoB,EAAA;AACvB,gBAAA,MAAM,EAAEC,IAAI,EAAEC,EAAE,EAAEC,EAAE,EAAEC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,IAAI,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGT,OAAAA;AAErE,gBAAA,MAAMU,IAAAA,GAAwB;oBAC5BT,IAAAA,EAAMA,IAAAA,IAAQL,SAASe,WAAW;AAClCT,oBAAAA,EAAAA;AACAC,oBAAAA,EAAAA;AACAC,oBAAAA,GAAAA;oBACAC,OAAAA,EAASA,OAAAA,IAAWT,SAASgB,cAAc;AAC3CN,oBAAAA,OAAAA;AACAC,oBAAAA,IAAAA;AACAC,oBAAAA,IAAAA;AACA,oBAAA,GAAIC;AACN,iBAAA;AAEA,gBAAA,OAAOI,eAAeH,IAAAA,EAAMb,aAAAA,CAAAA;AAC9B,YAAA;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
@@ -0,0 +1,15 @@
1
+ import type { ProviderSendmailOptions } from './types';
2
+ interface Logger {
3
+ debug: (...args: unknown[]) => void;
4
+ info: (...args: unknown[]) => void;
5
+ warn: (...args: unknown[]) => void;
6
+ error: (...args: unknown[]) => void;
7
+ }
8
+ /**
9
+ * Matches guileen/node-sendmail: `options.logger` wins over `silent` — if a custom logger is
10
+ * set, it is used as-is. Only when there is no custom logger does `silent` suppress output.
11
+ * Strapi merges `{ silent: true, ...providerOptions }` so explicit `silent: false` still applies.
12
+ */
13
+ export declare function createLogger(options: ProviderSendmailOptions): Logger;
14
+ export {};
15
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,UAAU,MAAM;IACd,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACpC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACrC;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAsBrE"}
package/dist/logger.js ADDED
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ function noop() {}
4
+ /**
5
+ * Matches guileen/node-sendmail: `options.logger` wins over `silent` — if a custom logger is
6
+ * set, it is used as-is. Only when there is no custom logger does `silent` suppress output.
7
+ * Strapi merges `{ silent: true, ...providerOptions }` so explicit `silent: false` still applies.
8
+ */ function createLogger(options) {
9
+ if (options.logger) {
10
+ const l = options.logger;
11
+ return {
12
+ debug: l.debug ? l.debug.bind(l) : noop,
13
+ info: l.info ? l.info.bind(l) : noop,
14
+ warn: l.warn ? l.warn.bind(l) : noop,
15
+ error: l.error ? l.error.bind(l) : noop
16
+ };
17
+ }
18
+ const silent = options.silent === true;
19
+ if (silent) {
20
+ return {
21
+ debug: noop,
22
+ info: noop,
23
+ warn: noop,
24
+ error: noop
25
+ };
26
+ }
27
+ return {
28
+ debug: console.log,
29
+ info: console.info,
30
+ warn: console.warn,
31
+ error: console.error
32
+ };
33
+ }
34
+
35
+ exports.createLogger = createLogger;
36
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sources":["../src/logger.ts"],"sourcesContent":["import type { ProviderSendmailOptions } from './types';\n\ninterface Logger {\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\nfunction noop() {}\n\n/**\n * Matches guileen/node-sendmail: `options.logger` wins over `silent` — if a custom logger is\n * set, it is used as-is. Only when there is no custom logger does `silent` suppress output.\n * Strapi merges `{ silent: true, ...providerOptions }` so explicit `silent: false` still applies.\n */\nexport function createLogger(options: ProviderSendmailOptions): Logger {\n if (options.logger) {\n const l = options.logger;\n return {\n debug: l.debug ? l.debug.bind(l) : noop,\n info: l.info ? l.info.bind(l) : noop,\n warn: l.warn ? l.warn.bind(l) : noop,\n error: l.error ? l.error.bind(l) : noop,\n };\n }\n\n const silent = options.silent === true;\n if (silent) {\n return { debug: noop, info: noop, warn: noop, error: noop };\n }\n\n return {\n debug: console.log,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n}\n"],"names":["noop","createLogger","options","logger","l","debug","bind","info","warn","error","silent","console","log"],"mappings":";;AASA,SAASA,IAAAA,GAAAA,CAAQ;AAEjB;;;;IAKO,SAASC,YAAAA,CAAaC,OAAgC,EAAA;IAC3D,IAAIA,OAAAA,CAAQC,MAAM,EAAE;QAClB,MAAMC,CAAAA,GAAIF,QAAQC,MAAM;QACxB,OAAO;YACLE,KAAAA,EAAOD,CAAAA,CAAEC,KAAK,GAAGD,CAAAA,CAAEC,KAAK,CAACC,IAAI,CAACF,CAAAA,CAAAA,GAAKJ,IAAAA;YACnCO,IAAAA,EAAMH,CAAAA,CAAEG,IAAI,GAAGH,CAAAA,CAAEG,IAAI,CAACD,IAAI,CAACF,CAAAA,CAAAA,GAAKJ,IAAAA;YAChCQ,IAAAA,EAAMJ,CAAAA,CAAEI,IAAI,GAAGJ,CAAAA,CAAEI,IAAI,CAACF,IAAI,CAACF,CAAAA,CAAAA,GAAKJ,IAAAA;YAChCS,KAAAA,EAAOL,CAAAA,CAAEK,KAAK,GAAGL,CAAAA,CAAEK,KAAK,CAACH,IAAI,CAACF,CAAAA,CAAAA,GAAKJ;AACrC,SAAA;AACF,IAAA;IAEA,MAAMU,MAAAA,GAASR,OAAAA,CAAQQ,MAAM,KAAK,IAAA;AAClC,IAAA,IAAIA,MAAAA,EAAQ;QACV,OAAO;YAAEL,KAAAA,EAAOL,IAAAA;YAAMO,IAAAA,EAAMP,IAAAA;YAAMQ,IAAAA,EAAMR,IAAAA;YAAMS,KAAAA,EAAOT;AAAK,SAAA;AAC5D,IAAA;IAEA,OAAO;AACLK,QAAAA,KAAAA,EAAOM,QAAQC,GAAG;AAClBL,QAAAA,IAAAA,EAAMI,QAAQJ,IAAI;AAClBC,QAAAA,IAAAA,EAAMG,QAAQH,IAAI;AAClBC,QAAAA,KAAAA,EAAOE,QAAQF;AACjB,KAAA;AACF;;;;"}
@@ -0,0 +1,34 @@
1
+ function noop() {}
2
+ /**
3
+ * Matches guileen/node-sendmail: `options.logger` wins over `silent` — if a custom logger is
4
+ * set, it is used as-is. Only when there is no custom logger does `silent` suppress output.
5
+ * Strapi merges `{ silent: true, ...providerOptions }` so explicit `silent: false` still applies.
6
+ */ function createLogger(options) {
7
+ if (options.logger) {
8
+ const l = options.logger;
9
+ return {
10
+ debug: l.debug ? l.debug.bind(l) : noop,
11
+ info: l.info ? l.info.bind(l) : noop,
12
+ warn: l.warn ? l.warn.bind(l) : noop,
13
+ error: l.error ? l.error.bind(l) : noop
14
+ };
15
+ }
16
+ const silent = options.silent === true;
17
+ if (silent) {
18
+ return {
19
+ debug: noop,
20
+ info: noop,
21
+ warn: noop,
22
+ error: noop
23
+ };
24
+ }
25
+ return {
26
+ debug: console.log,
27
+ info: console.info,
28
+ warn: console.warn,
29
+ error: console.error
30
+ };
31
+ }
32
+
33
+ export { createLogger };
34
+ //# sourceMappingURL=logger.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.mjs","sources":["../src/logger.ts"],"sourcesContent":["import type { ProviderSendmailOptions } from './types';\n\ninterface Logger {\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\nfunction noop() {}\n\n/**\n * Matches guileen/node-sendmail: `options.logger` wins over `silent` — if a custom logger is\n * set, it is used as-is. Only when there is no custom logger does `silent` suppress output.\n * Strapi merges `{ silent: true, ...providerOptions }` so explicit `silent: false` still applies.\n */\nexport function createLogger(options: ProviderSendmailOptions): Logger {\n if (options.logger) {\n const l = options.logger;\n return {\n debug: l.debug ? l.debug.bind(l) : noop,\n info: l.info ? l.info.bind(l) : noop,\n warn: l.warn ? l.warn.bind(l) : noop,\n error: l.error ? l.error.bind(l) : noop,\n };\n }\n\n const silent = options.silent === true;\n if (silent) {\n return { debug: noop, info: noop, warn: noop, error: noop };\n }\n\n return {\n debug: console.log,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n}\n"],"names":["noop","createLogger","options","logger","l","debug","bind","info","warn","error","silent","console","log"],"mappings":"AASA,SAASA,IAAAA,GAAAA,CAAQ;AAEjB;;;;IAKO,SAASC,YAAAA,CAAaC,OAAgC,EAAA;IAC3D,IAAIA,OAAAA,CAAQC,MAAM,EAAE;QAClB,MAAMC,CAAAA,GAAIF,QAAQC,MAAM;QACxB,OAAO;YACLE,KAAAA,EAAOD,CAAAA,CAAEC,KAAK,GAAGD,CAAAA,CAAEC,KAAK,CAACC,IAAI,CAACF,CAAAA,CAAAA,GAAKJ,IAAAA;YACnCO,IAAAA,EAAMH,CAAAA,CAAEG,IAAI,GAAGH,CAAAA,CAAEG,IAAI,CAACD,IAAI,CAACF,CAAAA,CAAAA,GAAKJ,IAAAA;YAChCQ,IAAAA,EAAMJ,CAAAA,CAAEI,IAAI,GAAGJ,CAAAA,CAAEI,IAAI,CAACF,IAAI,CAACF,CAAAA,CAAAA,GAAKJ,IAAAA;YAChCS,KAAAA,EAAOL,CAAAA,CAAEK,KAAK,GAAGL,CAAAA,CAAEK,KAAK,CAACH,IAAI,CAACF,CAAAA,CAAAA,GAAKJ;AACrC,SAAA;AACF,IAAA;IAEA,MAAMU,MAAAA,GAASR,OAAAA,CAAQQ,MAAM,KAAK,IAAA;AAClC,IAAA,IAAIA,MAAAA,EAAQ;QACV,OAAO;YAAEL,KAAAA,EAAOL,IAAAA;YAAMO,IAAAA,EAAMP,IAAAA;YAAMQ,IAAAA,EAAMR,IAAAA;YAAMS,KAAAA,EAAOT;AAAK,SAAA;AAC5D,IAAA;IAEA,OAAO;AACLK,QAAAA,KAAAA,EAAOM,QAAQC,GAAG;AAClBL,QAAAA,IAAAA,EAAMI,QAAQJ,IAAI;AAClBC,QAAAA,IAAAA,EAAMG,QAAQH,IAAI;AAClBC,QAAAA,KAAAA,EAAOE,QAAQF;AACjB,KAAA;AACF;;;;"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Options passed through from Strapi `plugin::email` config `providerOptions`,
3
+ * historically compatible with `require('sendmail')` (guileen/node-sendmail).
4
+ */
5
+ export interface ProviderSendmailOptions {
6
+ logger?: {
7
+ debug?: (...args: unknown[]) => void;
8
+ info?: (...args: unknown[]) => void;
9
+ warn?: (...args: unknown[]) => void;
10
+ error?: (...args: unknown[]) => void;
11
+ };
12
+ silent?: boolean;
13
+ dkim?: boolean | {
14
+ privateKey: string;
15
+ keySelector?: string;
16
+ };
17
+ /** Development / testing: connect to `devHost:devPort` instead of resolving MX. */
18
+ devPort?: number | boolean;
19
+ devHost?: string;
20
+ /** SMTP port for outbound delivery (default 25). */
21
+ smtpPort?: number;
22
+ /** Extra SMTP host to try after MX records (same as legacy `sendmail` package). */
23
+ smtpHost?: string | number;
24
+ rejectUnauthorized?: boolean;
25
+ autoEHLO?: boolean;
26
+ }
27
+ export interface Settings {
28
+ defaultFrom: string;
29
+ defaultReplyTo?: string;
30
+ }
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACrC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACpC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;KACtC,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EACD,OAAO,GACP;QACE,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACN,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/provider-email-sendmail",
3
- "version": "5.45.1",
3
+ "version": "5.46.0",
4
4
  "description": "Sendmail provider for strapi email",
5
5
  "keywords": [
6
6
  "email",
@@ -41,16 +41,16 @@
41
41
  "build:types": "run -T tsc -p tsconfig.build.json --emitDeclarationOnly",
42
42
  "clean": "run -T rimraf ./dist",
43
43
  "lint": "run -T eslint .",
44
+ "test:unit": "run -T jest --watchman=false",
44
45
  "watch": "run -T rollup -c -w"
45
46
  },
46
47
  "dependencies": {
47
- "@strapi/utils": "5.45.1",
48
- "sendmail": "^1.6.1"
48
+ "nodemailer": "8.0.5"
49
49
  },
50
50
  "devDependencies": {
51
- "@types/sendmail": "1.4.4",
52
- "eslint-config-custom": "5.45.1",
53
- "tsconfig": "5.45.1"
51
+ "@types/nodemailer": "7.0.11",
52
+ "eslint-config-custom": "5.46.0",
53
+ "tsconfig": "5.46.0"
54
54
  },
55
55
  "engines": {
56
56
  "node": ">=20.0.0 <=24.x.x",