nodemailer 10.0.9 → 10.0.11

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 (90) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -1
  3. package/dist/cjs/addressparser/index.d.ts +16 -1
  4. package/dist/cjs/addressparser/index.js +1 -17
  5. package/dist/cjs/base64/index.js +2 -1
  6. package/dist/cjs/dkim/index.d.ts +13 -1
  7. package/dist/cjs/dkim/message-parser.d.ts +10 -1
  8. package/dist/cjs/dkim/message-parser.js +12 -5
  9. package/dist/cjs/dkim/relaxed-body.d.ts +10 -1
  10. package/dist/cjs/errors.d.ts +3 -2
  11. package/dist/cjs/fetch/cookies.d.ts +12 -1
  12. package/dist/cjs/fetch/index.d.ts +11 -0
  13. package/dist/cjs/fetch/index.js +5 -5
  14. package/dist/cjs/json-transport/index.d.ts +14 -4
  15. package/dist/cjs/json-transport/index.js +2 -0
  16. package/dist/cjs/mail-composer/index.d.ts +8 -3
  17. package/dist/cjs/mail-composer/index.js +3 -1
  18. package/dist/cjs/mailer/index.d.ts +36 -24
  19. package/dist/cjs/mailer/mail-message.d.ts +11 -4
  20. package/dist/cjs/mailer/mail-message.js +2 -1
  21. package/dist/cjs/mime-funcs/index.d.ts +5 -2
  22. package/dist/cjs/mime-funcs/index.js +1 -1
  23. package/dist/cjs/mime-node/index.d.ts +5 -2
  24. package/dist/cjs/nodemailer.d.ts +25 -14
  25. package/dist/cjs/nodemailer.js +1 -0
  26. package/dist/cjs/package-info.d.ts +1 -1
  27. package/dist/cjs/package-info.js +1 -1
  28. package/dist/cjs/qp/index.d.ts +2 -0
  29. package/dist/cjs/qp/index.js +10 -1
  30. package/dist/cjs/sendmail-transport/index.d.ts +2 -0
  31. package/dist/cjs/ses-transport/index.d.ts +33 -1
  32. package/dist/cjs/shared/index.d.ts +18 -6
  33. package/dist/cjs/shared/index.js +4 -2
  34. package/dist/cjs/smtp-connection/http-proxy-client.d.ts +2 -2
  35. package/dist/cjs/smtp-connection/http-proxy-client.js +6 -4
  36. package/dist/cjs/smtp-connection/index.d.ts +56 -18
  37. package/dist/cjs/smtp-connection/index.js +126 -69
  38. package/dist/cjs/smtp-pool/index.d.ts +4 -2
  39. package/dist/cjs/smtp-pool/index.js +8 -6
  40. package/dist/cjs/smtp-pool/pool-resource.js +1 -3
  41. package/dist/cjs/smtp-transport/index.d.ts +13 -5
  42. package/dist/cjs/smtp-transport/index.js +9 -7
  43. package/dist/cjs/stream-transport/index.d.ts +2 -0
  44. package/dist/cjs/xoauth2/index.d.ts +11 -3
  45. package/dist/cjs/xoauth2/index.js +14 -10
  46. package/dist/esm/addressparser/index.d.ts +16 -1
  47. package/dist/esm/addressparser/index.js +2 -17
  48. package/dist/esm/base64/index.js +2 -1
  49. package/dist/esm/dkim/index.d.ts +13 -1
  50. package/dist/esm/dkim/message-parser.d.ts +10 -1
  51. package/dist/esm/dkim/message-parser.js +14 -6
  52. package/dist/esm/dkim/relaxed-body.d.ts +10 -1
  53. package/dist/esm/dkim/relaxed-body.js +2 -1
  54. package/dist/esm/errors.d.ts +3 -2
  55. package/dist/esm/fetch/cookies.d.ts +12 -1
  56. package/dist/esm/fetch/cookies.js +2 -1
  57. package/dist/esm/fetch/index.d.ts +11 -0
  58. package/dist/esm/fetch/index.js +5 -5
  59. package/dist/esm/json-transport/index.d.ts +14 -4
  60. package/dist/esm/json-transport/index.js +2 -0
  61. package/dist/esm/mail-composer/index.d.ts +8 -3
  62. package/dist/esm/mail-composer/index.js +3 -1
  63. package/dist/esm/mailer/index.d.ts +36 -24
  64. package/dist/esm/mailer/mail-message.d.ts +11 -4
  65. package/dist/esm/mailer/mail-message.js +2 -1
  66. package/dist/esm/mime-funcs/index.d.ts +5 -2
  67. package/dist/esm/mime-funcs/index.js +1 -1
  68. package/dist/esm/mime-node/index.d.ts +5 -2
  69. package/dist/esm/nodemailer.d.ts +25 -14
  70. package/dist/esm/package-info.d.ts +1 -1
  71. package/dist/esm/package-info.js +1 -1
  72. package/dist/esm/qp/index.d.ts +2 -0
  73. package/dist/esm/qp/index.js +10 -1
  74. package/dist/esm/sendmail-transport/index.d.ts +2 -0
  75. package/dist/esm/ses-transport/index.d.ts +33 -1
  76. package/dist/esm/shared/index.d.ts +18 -6
  77. package/dist/esm/shared/index.js +4 -2
  78. package/dist/esm/smtp-connection/http-proxy-client.d.ts +2 -2
  79. package/dist/esm/smtp-connection/http-proxy-client.js +6 -4
  80. package/dist/esm/smtp-connection/index.d.ts +56 -18
  81. package/dist/esm/smtp-connection/index.js +126 -69
  82. package/dist/esm/smtp-pool/index.d.ts +4 -2
  83. package/dist/esm/smtp-pool/index.js +8 -6
  84. package/dist/esm/smtp-pool/pool-resource.js +1 -3
  85. package/dist/esm/smtp-transport/index.d.ts +13 -5
  86. package/dist/esm/smtp-transport/index.js +9 -7
  87. package/dist/esm/stream-transport/index.d.ts +2 -0
  88. package/dist/esm/xoauth2/index.d.ts +11 -3
  89. package/dist/esm/xoauth2/index.js +14 -10
  90. package/package.json +13 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [10.0.11](https://github.com/nodemailer/nodemailer/compare/v10.0.10...v10.0.11) (2026-09-27)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **fetch:** report a form body that can not be encoded through the returned stream ([74d40bf](https://github.com/nodemailer/nodemailer/commit/74d40bf1e4553bc0568b471250a9251bcb569b00))
9
+ * keep the CommonJS entry point and the services subpath compatible with the pre-TypeScript build ([52901ef](https://github.com/nodemailer/nodemailer/commit/52901ef3725ad179aa56276495a60f53b2c83516))
10
+ * **qp:** keep wrap() terminating for short line lengths and a trailing incomplete escape ([8fa140b](https://github.com/nodemailer/nodemailer/commit/8fa140b11c62cb1202eac84d35bb3ba28bc3b1a1))
11
+ * **smtp-connection:** fail a password login cleanly when the server offers only XOAUTH2 ([90abf7d](https://github.com/nodemailer/nodemailer/commit/90abf7d11db5ebfeb4292b62c1fff969741c7d33))
12
+ * **types:** restore the layout of @types/nodemailer in the bundled declarations ([ac2e40f](https://github.com/nodemailer/nodemailer/commit/ac2e40ffc69427e0eb33ce3945fae76c4c828c8d))
13
+
14
+ ## [10.0.10](https://github.com/nodemailer/nodemailer/compare/v10.0.9...v10.0.10) (2026-09-14)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * derive the attachment filename from the basename of a Windows path ([c7cc7ce](https://github.com/nodemailer/nodemailer/commit/c7cc7ce41a3602441747476a2a2c4a8ff466a83e))
20
+ * **dkim:** unfold folded header lines in linear time ([28a5909](https://github.com/nodemailer/nodemailer/commit/28a5909cec27646cb001dc7e97a8f5d26c973078))
21
+ * **smtp-connection:** reassemble multiline replies in linear time ([f2d82fa](https://github.com/nodemailer/nodemailer/commit/f2d82fa84d47015a7bbb4253da61eeb778c658b1))
22
+
3
23
  ## [10.0.9](https://github.com/nodemailer/nodemailer/compare/v10.0.8...v10.0.9) (2026-09-12)
4
24
 
5
25
 
package/README.md CHANGED
@@ -72,7 +72,7 @@ let configOptions = {
72
72
 
73
73
  #### I have an issue with TypeScript types
74
74
 
75
- Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter<SMTPTransport.SentMessageInfo>` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply.
75
+ Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter<SMTPTransport.SentMessageInfo>` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. The modules under `nodemailer/lib/` are declared with a default export, so import a class as `import SMTPTransport from 'nodemailer/lib/smtp-transport'` (with `esModuleInterop` in a CommonJS project). The `import SMTPTransport = require(...)` and `import * as SMTPTransport from ...` forms still resolve the type aliases such as `SMTPTransport.Options`, but they refer to the module rather than to the class, so the class itself has to be imported with a default import. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply.
76
76
 
77
77
  #### I have a different problem
78
78
 
@@ -42,4 +42,19 @@ export type Address = MailboxAddress | GroupAddress;
42
42
  * @param options._depth Internal recursion depth counter (do not set manually)
43
43
  * @return An array of address objects
44
44
  */
45
- export default function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
45
+ declare function addressparser(str: string | null | undefined, options: AddressParserOptions & {
46
+ flatten: true;
47
+ }): MailboxAddress[];
48
+ declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
49
+ /**
50
+ * Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working
51
+ */
52
+ type AddressEntry = Address;
53
+ declare namespace addressparser {
54
+ type Address = MailboxAddress;
55
+ type Group = GroupAddress;
56
+ type AddressOrGroup = AddressEntry;
57
+ }
58
+ /** The names @types/nodemailer used for the group entry and for the union of both entry types */
59
+ export type { GroupAddress as Group, Address as AddressOrGroup };
60
+ export default addressparser;
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = addressparser;
4
3
  /**
5
4
  * Restores the quoting of a local part that was read out of a quoted string.
6
5
  *
@@ -583,22 +582,6 @@ class Tokenizer {
583
582
  * malicious input that could cause stack overflow.
584
583
  */
585
584
  const MAX_NESTED_GROUP_DEPTH = 50;
586
- /**
587
- * Parses structured e-mail addresses from an address field
588
- *
589
- * Example:
590
- *
591
- * 'Name <address@domain>'
592
- *
593
- * will be converted to
594
- *
595
- * [{name: 'Name', address: 'address@domain'}]
596
- *
597
- * @param str Address field
598
- * @param options Optional options object
599
- * @param options._depth Internal recursion depth counter (do not set manually)
600
- * @return An array of address objects
601
- */
602
585
  function addressparser(str, options) {
603
586
  options = options || {};
604
587
  const depth = options._depth || 0;
@@ -667,5 +650,6 @@ function addressparser(str, options) {
667
650
  }
668
651
  return parsedAddresses;
669
652
  }
653
+ exports.default = addressparser;
670
654
  module.exports = exports.default;
671
655
  Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });
@@ -25,7 +25,8 @@ function encode(buffer) {
25
25
  */
26
26
  function wrap(str, lineLength) {
27
27
  str = (str || '').toString();
28
- lineLength = lineLength || 76;
28
+ // a negative length would step backwards through the input and never finish
29
+ lineLength = Math.max(Number(lineLength) || 76, 1);
29
30
  if (str.length <= lineLength) {
30
31
  return str;
31
32
  }
@@ -30,11 +30,23 @@ declare class DKIM {
30
30
  constructor(options: DKIMOptions);
31
31
  sign(input: Readable | Buffer | string, extraOptions?: DKIMOptions): DKIMSignedStream;
32
32
  }
33
+ /** The signer options without any key material */
34
+ export type DKIMOptionalOptions = Omit<DKIMOptions, 'keys' | 'domainName' | 'keySelector' | 'privateKey'>;
35
+ /** The signer options for a single key given as domainName, keySelector and privateKey */
36
+ export type DKIMSingleKeyOptions = Omit<DKIMOptions, 'keys'>;
37
+ /** The signer options for one or more keys given through `keys` */
38
+ export type DKIMMultipleKeysOptions = DKIMOptionalOptions & {
39
+ keys: DKIMKey | DKIMKey[];
40
+ };
33
41
  /**
34
42
  * Type aliases in the layout of @types/nodemailer, so `DKIM.Options` style references keep working
35
43
  */
36
44
  declare namespace DKIM {
37
45
  type Options = DKIMOptions;
38
- type SingleKeyOptions = Omit<DKIMOptions, 'keys'>;
46
+ type OptionalOptions = DKIMOptionalOptions;
47
+ type SingleKeyOptions = DKIMSingleKeyOptions;
48
+ type MultipleKeysOptions = DKIMMultipleKeysOptions;
39
49
  }
50
+ /** The same aliases as module level exports, for `import * as DKIM` and `import DKIM = require()` */
51
+ export type { DKIMOptions as Options, DKIMOptionalOptions as OptionalOptions, DKIMSingleKeyOptions as SingleKeyOptions, DKIMMultipleKeysOptions as MultipleKeysOptions };
40
52
  export default DKIM;
@@ -13,7 +13,7 @@ export interface MessageParserHeaderLine {
13
13
  * from the rest of the body. Headers are emitted with the 'headers' event. Message
14
14
  * body is passed on as the resulting stream.
15
15
  */
16
- export default class MessageParser extends Transform {
16
+ declare class MessageParser extends Transform {
17
17
  lastBytes: Buffer;
18
18
  headersParsed: boolean;
19
19
  headerBytes: number;
@@ -37,3 +37,12 @@ export default class MessageParser extends Transform {
37
37
  checkHeaders(data: Buffer): boolean;
38
38
  parseHeaders(): MessageParserHeaderLine[];
39
39
  }
40
+ /**
41
+ * Type aliases in the layout of @types/nodemailer, so `MessageParser.Header` style references keep working
42
+ */
43
+ declare namespace MessageParser {
44
+ type Header = MessageParserHeaderLine;
45
+ }
46
+ /** The same alias as a module level export, for `import * as MessageParser` and `import MessageParser = require()` */
47
+ export type { MessageParserHeaderLine as Header };
48
+ export default MessageParser;
@@ -126,11 +126,18 @@ class MessageParser extends node_stream_1.Transform {
126
126
  // signature covers exactly the bytes the receiving side canonicalizes
127
127
  // Only SP and HTAB fold a line, and only they are trimmed from the field name, the
128
128
  // same whitespace the relaxed canonicalization in sign.ts works with
129
- const lines = (this.rawHeaders || Buffer.alloc(0)).toString('binary').split(/\r?\n/);
130
- for (let i = lines.length - 1; i > 0; i--) {
131
- if (/^[ \t]/.test(lines[i])) {
132
- lines[i - 1] += '\n' + lines[i];
133
- lines.splice(i, 1);
129
+ const rawLines = (this.rawHeaders || Buffer.alloc(0)).toString('binary').split(/\r?\n/);
130
+ // Unfold in a single forward pass and only ever test a freshly split line for the
131
+ // continuation prefix. Testing an already merged line instead would rescan a string
132
+ // that grows with every continuation line, so a header folded into many continuation
133
+ // lines (a large recipient list, for example) would take quadratic time to unfold
134
+ const lines = [];
135
+ for (const rawLine of rawLines) {
136
+ if (lines.length && /^[ \t]/.test(rawLine)) {
137
+ lines[lines.length - 1] += '\n' + rawLine;
138
+ }
139
+ else {
140
+ lines.push(rawLine);
134
141
  }
135
142
  }
136
143
  return lines
@@ -17,7 +17,7 @@ export interface RelaxedBodyOptions {
17
17
  * a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive,
18
18
  * so a line of any length costs constant memory.
19
19
  */
20
- export default class RelaxedBody extends Transform {
20
+ declare class RelaxedBody extends Transform {
21
21
  bodyHash: crypto.Hash;
22
22
  /** Bytes of the original body seen so far */
23
23
  byteLength: number;
@@ -25,3 +25,12 @@ export default class RelaxedBody extends Transform {
25
25
  constructor(options?: RelaxedBodyOptions);
26
26
  updateHash(chunk: Buffer, final?: boolean): void;
27
27
  }
28
+ /**
29
+ * Type aliases in the layout of @types/nodemailer, so `RelaxedBody.Options` style references keep working
30
+ */
31
+ declare namespace RelaxedBody {
32
+ type Options = RelaxedBodyOptions;
33
+ }
34
+ /** The same alias as a module level export, for `import * as RelaxedBody` and `import RelaxedBody = require()` */
35
+ export type { RelaxedBodyOptions as Options };
36
+ export default RelaxedBody;
@@ -64,9 +64,10 @@ export declare const EFETCH = "EFETCH";
64
64
  /**
65
65
  * An Error together with the properties Nodemailer attaches to the errors it
66
66
  * hands to callers. Every property is optional, the set that is present
67
- * depends on where the error originated.
67
+ * depends on where the error originated. Socket level errors keep the errno
68
+ * and syscall fields Node.js sets on them.
68
69
  */
69
- export interface NodemailerError extends Error {
70
+ export interface NodemailerError extends NodeJS.ErrnoException {
70
71
  /** Nodemailer error code, see ERROR_CODES */
71
72
  code?: string | undefined;
72
73
  /** SMTP command that was in flight when the server replied with an error */
@@ -17,13 +17,14 @@ export interface Cookie {
17
17
  secure?: boolean | undefined;
18
18
  httponly?: boolean | undefined;
19
19
  }
20
+ type CookieEntry = Cookie;
20
21
  /**
21
22
  * Creates a biskviit cookie jar for managing cookie values in memory
22
23
  *
23
24
  * @constructor
24
25
  * @param [options] Optional options object
25
26
  */
26
- export default class Cookies {
27
+ declare class Cookies {
27
28
  options: CookiesOptions;
28
29
  cookies: Cookie[];
29
30
  constructor(options?: CookiesOptions);
@@ -94,3 +95,13 @@ export default class Cookies {
94
95
  */
95
96
  getPath(pathname?: string | null): string;
96
97
  }
98
+ /**
99
+ * Type aliases in the layout of @types/nodemailer, so `Cookies.Cookie` style references keep working
100
+ */
101
+ declare namespace Cookies {
102
+ type Options = CookiesOptions;
103
+ type Cookie = CookieEntry;
104
+ }
105
+ /** The same alias as a module level export, for `import * as Cookies` and `import Cookies = require()` */
106
+ export type { CookiesOptions as Options };
107
+ export default Cookies;
@@ -48,4 +48,15 @@ declare function nmfetch(url: string, options?: FetchOptions): FetchResponse;
48
48
  declare namespace nmfetch {
49
49
  var Cookies: typeof import("./cookies.js").default;
50
50
  }
51
+ type CookiesJar = Cookies;
52
+ /**
53
+ * Type aliases in the layout of @types/nodemailer, so `fetch.Options` style references keep working
54
+ */
55
+ declare namespace nmfetch {
56
+ type Options = FetchOptions;
57
+ type WritableResponse = FetchResponse;
58
+ type Cookies = CookiesJar;
59
+ }
60
+ /** The same aliases as module level exports, for `import * as fetch` and `import fetch = require()` */
61
+ export type { FetchOptions as Options, FetchResponse as WritableResponse, Cookies };
51
62
  export default nmfetch;
@@ -193,14 +193,14 @@ function nmfetch(url, options) {
193
193
  .join('&'));
194
194
  }
195
195
  catch (E) {
196
- if (finished) {
197
- return undefined;
198
- }
196
+ // the caller attaches its error listener once nmfetch has returned, so
197
+ // the error is emitted on the next tick and the stream is handed back
198
+ // the way every other failure is reported
199
199
  finished = true;
200
200
  E.code = errors.EFETCH;
201
201
  E.sourceUrl = url;
202
- fetchRes.emit('error', E);
203
- return undefined;
202
+ setImmediate(() => fetchRes.emit('error', E));
203
+ return fetchRes;
204
204
  }
205
205
  }
206
206
  else {
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from '../shared/index.js';
2
2
  import type { MimeNodeEnvelope } from '../mime-node/index.js';
3
- import type { default as MailMessage, MailMessageData } from '../mailer/mail-message.js';
3
+ import type MailMessage from '../mailer/mail-message.js';
4
4
  import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions } from '../mailer/index.js';
5
5
  /**
6
6
  * Options for the JSON transport
@@ -12,16 +12,23 @@ export interface JSONTransportOptions extends TransportOptions {
12
12
  skipEncoding?: boolean | undefined;
13
13
  }
14
14
  /**
15
- * The value the JSON transport hands to the send callback
15
+ * The value the JSON transport hands to the send callback. M is the type of the message
16
+ * field: a JSON string by default, the message object itself when skipEncoding is set
16
17
  */
17
- export interface JSONSentMessageInfo extends SentMessageInfo {
18
+ export interface JSONSentMessageInfo<M = string> extends SentMessageInfo {
18
19
  /** The envelope the message was generated with */
19
20
  envelope: MimeNodeEnvelope;
20
21
  /** Message-ID value of the message */
21
22
  messageId: string;
22
23
  /** The normalized message as a JSON string, or as the object itself when skipEncoding is set */
23
- message: string | MailMessageData;
24
+ message: M;
24
25
  }
26
+ /**
27
+ * The value the JSON transport hands to the send callback when skipEncoding is set: the
28
+ * message field holds the message object. Typed loosely so that a transporter created with
29
+ * skipEncoding still fits a variable declared with the plain result type
30
+ */
31
+ export type JSONSentMessageObjectInfo = JSONSentMessageInfo<any>;
25
32
  /**
26
33
  * Generates a Transport object to generate JSON output
27
34
  *
@@ -50,5 +57,8 @@ declare namespace JSONTransport {
50
57
  type Options = JSONTransportOptions;
51
58
  type MailOptions = SendMailOptions;
52
59
  type SentMessageInfo = JSONSentMessageInfo;
60
+ type SentMessageObjectInfo = JSONSentMessageObjectInfo;
53
61
  }
62
+ /** The same aliases as module level exports, for `import * as JSONTransport` and `import JSONTransport = require()` */
63
+ export type { JSONTransportOptions as Options, SendMailOptions as MailOptions, JSONSentMessageInfo as SentMessageInfo, JSONSentMessageObjectInfo as SentMessageObjectInfo };
54
64
  export default JSONTransport;
@@ -83,6 +83,8 @@ class JSONTransport {
83
83
  }
84
84
  delete data.envelope;
85
85
  delete data.normalizedHeaders;
86
+ // the message field is the object itself with skipEncoding, the
87
+ // createTransport overload for that option types the result accordingly
86
88
  return done(null, {
87
89
  envelope,
88
90
  messageId,
@@ -72,6 +72,11 @@ export type MailComposerListHeaderEntry = string | {
72
72
  export interface MailComposerListHeaders {
73
73
  [key: string]: MailComposerListHeaderEntry | (MailComposerListHeaderEntry | MailComposerListHeaderEntry[])[];
74
74
  }
75
+ /**
76
+ * Encoding for the non-ascii header values: quoted-printable ('Q', the default) or base64
77
+ * ('B'). Only the first letter is read, so the short forms work as well
78
+ */
79
+ export type MailComposerTextEncoding = 'quoted-printable' | 'base64' | 'Q' | 'B';
75
80
  /**
76
81
  * Mail options, the message data MailComposer builds the MIME tree from. The address
77
82
  * fields, subject, messageId, date, inReplyTo and references become headers of the root
@@ -114,7 +119,7 @@ export interface MailComposerOptions {
114
119
  /** Content-Transfer-Encoding to force for the text/* nodes that do not set their own */
115
120
  encoding?: string | undefined;
116
121
  /** Header string encoding, 'Q' (the default) or 'B', 'quoted-printable' and 'base64' are accepted as well */
117
- textEncoding?: string | undefined;
122
+ textEncoding?: MailComposerTextEncoding | undefined;
118
123
  /** Pregenerated rfc822 message, used as is instead of building one */
119
124
  raw?: MimeNodeContent | undefined;
120
125
  /** Reject content that points to a URL */
@@ -129,8 +134,6 @@ export interface MailComposerOptions {
129
134
  baseBoundary?: string | undefined;
130
135
  /** 'win' for CRLF and 'linux' for LF line breaks in the generated message, kept as is when not set */
131
136
  newline?: string | undefined;
132
- /** Keep the Bcc header in the generated message, listed for completeness, the transports set it on the message directly */
133
- keepBcc?: boolean | undefined;
134
137
  /** Method to normalize header keys for custom caseing */
135
138
  normalizeHeaderKey?: MimeNodeOptions['normalizeHeaderKey'] | undefined;
136
139
  /** 'high', 'normal' or 'low', sets the priority headers, read by the mailer */
@@ -166,4 +169,6 @@ declare class MailComposer {
166
169
  declare namespace MailComposer {
167
170
  type Options = MailComposerOptions;
168
171
  }
172
+ /** The same alias as a module level export, for `import * as MailComposer` and `import MailComposer = require()` */
173
+ export type { MailComposerOptions as Options };
169
174
  export default MailComposer;
@@ -151,8 +151,10 @@ class MailComposer {
151
151
  data.filename = attachment.filename;
152
152
  }
153
153
  else if (!isMessageNode && attachment.filename !== false) {
154
+ // a backslash separates as well, so a Windows path does not put the sender's directories in the headers
154
155
  data.filename =
155
- (attachment.path || attachment.href || '').split('/').pop().split('?').shift() || 'attachment-' + (i + 1);
156
+ (attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() ||
157
+ 'attachment-' + (i + 1);
156
158
  if (data.filename.indexOf('.') < 0) {
157
159
  data.filename += '.' + mimeFuncs.detectExtension(data.contentType);
158
160
  }
@@ -4,8 +4,8 @@ import DKIM, { type DKIMOptions } from '../dkim/index.js';
4
4
  import MailMessage, { type MailDefaults, type SendMailOptions } from './mail-message.js';
5
5
  import net from 'node:net';
6
6
  import type { ConnectionOptions } from 'node:tls';
7
- import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders } from '../mail-composer/index.js';
8
- import type { NodemailerError, ResultCallback } from '../errors.js';
7
+ import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders, MailComposerTextEncoding } from '../mail-composer/index.js';
8
+ import type { Callback, NodemailerError, ResultCallback } from '../errors.js';
9
9
  import type { ParsedUrl } from '../shared/url.js';
10
10
  import type { MimeNodeAddress, MimeNodeEnvelope, MimeNodeEnvelopeInput, MimeNodeHeaders, MimeNodeOptions } from '../mime-node/index.js';
11
11
  import type { XOAuth2ProvisionCallback } from '../xoauth2/index.js';
@@ -15,9 +15,10 @@ export type { default as MailMessage } from './mail-message.js';
15
15
  * The base shape of the object a transport hands back for a sent message. Every bundled
16
16
  * transport sets the envelope and the Message-ID, the rest depends on the transport.
17
17
  *
18
- * The index signature keeps a transport specific field readable through this type, and it
19
- * is also what a result type has to inherit to stay assignable to it, so the result type
20
- * of a transport outside this package has to extend this interface rather than restate it
18
+ * The index signature keeps a transport specific field readable through this type, the way
19
+ * the `any` typed result of @types/nodemailer was, and it is also what a result type has
20
+ * to inherit to stay assignable to it, so the result type of a transport outside this
21
+ * package has to extend this interface rather than restate it
21
22
  */
22
23
  export interface SentMessageInfo {
23
24
  /** The envelope the message was sent with */
@@ -33,9 +34,9 @@ export interface SentMessageInfo {
33
34
  /** Last response from the server */
34
35
  response?: string | undefined;
35
36
  /** The generated message, for the transports that hand it back instead of sending it */
36
- message?: unknown;
37
+ message?: any;
37
38
  /** Transport specific fields */
38
- [key: string]: unknown;
39
+ [key: string]: any;
39
40
  }
40
41
  /**
41
42
  * Callback for sendMail, receives the transport result once the transport has taken the
@@ -43,9 +44,11 @@ export interface SentMessageInfo {
43
44
  */
44
45
  export type SendMailCallback<T = SentMessageInfo> = (err: NodemailerError | null, info: T) => void;
45
46
  /**
46
- * Callback for verify(), success is true once the transport accepted the configuration
47
+ * Callback for verify(), success is true once the transport accepted the configuration.
48
+ * Declared with a required success value, the way @types/nodemailer declared it, the
49
+ * error path hands over the error alone
47
50
  */
48
- export type VerifyCallback = (err: NodemailerError | null, success?: true) => void;
51
+ export type VerifyCallback = Callback<true>;
49
52
  /**
50
53
  * Callback a plugin calls once it is done, an error aborts the send
51
54
  */
@@ -60,21 +63,23 @@ export type PluginFunction<T = SentMessageInfo> = (mail: MailMessage<T>, callbac
60
63
  */
61
64
  export interface GetSocketOptions {
62
65
  host?: string | undefined;
63
- port?: number | string | undefined;
66
+ port?: number | undefined;
64
67
  [key: string]: any;
65
68
  }
66
69
  /**
67
- * The result of a getSocket handler, the socket to use for the connection
70
+ * The result of a getSocket handler, the socket to use for the connection. The object is
71
+ * merged into the connection options, so it may carry any of those as well
68
72
  */
69
73
  export interface SocketOptions {
70
74
  /** An established socket, the proxied connection */
71
75
  connection?: net.Socket | undefined;
76
+ [key: string]: any;
72
77
  }
73
78
  /**
74
- * Receives the socket options from a getSocket handler, or the error that prevented the
75
- * connection
79
+ * Receives the socket options from a getSocket handler, false when a new socket should be
80
+ * opened, or the error that prevented the connection
76
81
  */
77
- export type GetSocketCallback = (err: NodemailerError | null, socketOptions?: SocketOptions) => void;
82
+ export type GetSocketCallback = (err: Error | null, socketOptions?: SocketOptions | false) => void;
78
83
  /**
79
84
  * A socket handler. Mail sets one on the transport as getSocket when a proxy is configured,
80
85
  * the SMTP transports call it to get a proxied socket instead of connecting directly
@@ -101,9 +106,12 @@ export interface MailMeta {
101
106
  /**
102
107
  * A transport as consumed by Mail: any object with a name, a version and a send method
103
108
  * works, the rest is optional. Mail forwards its close, isIdle and verify calls to the
104
- * methods of the same name as they are, so their arguments are up to the transport
109
+ * methods of the same name as they are, so their arguments are up to the transport.
110
+ *
111
+ * D is the options type of the transport, the second type parameter @types/nodemailer
112
+ * declared on Transport, Transporter and Mail
105
113
  */
106
- export interface Transport<T = SentMessageInfo> {
114
+ export interface Transport<T = SentMessageInfo, D extends TransportOptions = TransportOptions> {
107
115
  /** Transport name, used for logging */
108
116
  name: string;
109
117
  /** Transport version, used for logging */
@@ -119,7 +127,7 @@ export interface Transport<T = SentMessageInfo> {
119
127
  /** Registers an event listener, the transport may emit 'log', 'error', 'idle' and 'clear' */
120
128
  on?(event: string | symbol, listener: (...args: any[]) => void): this;
121
129
  /** The Mail object the transport belongs to, set by Mail */
122
- mailer?: Mail<T> | undefined;
130
+ mailer?: Mail<T, D> | undefined;
123
131
  /** Socket handler for a proxied connection, set by Mail when a proxy is configured */
124
132
  getSocket?: GetSocketHandler | undefined;
125
133
  }
@@ -150,22 +158,23 @@ export interface TransportOptions {
150
158
  attachDataUrls?: boolean | undefined;
151
159
  }
152
160
  /**
153
- * The transporter object createTransport returns, a Mail instance wrapping a transport
161
+ * The transporter object createTransport returns, a Mail instance wrapping a transport. D
162
+ * is the options type of the transport, it types the options field of the transporter
154
163
  */
155
- export type Transporter<T = SentMessageInfo> = Mail<T>;
164
+ export type Transporter<T = SentMessageInfo, D extends TransportOptions = TransportOptions> = Mail<T, D>;
156
165
  /**
157
166
  * Creates an object for exposing the Mail API
158
167
  *
159
168
  * @constructor
160
169
  * @param transporter Transport object instance to pass the mails to
161
170
  */
162
- declare class Mail<out T = SentMessageInfo> extends EventEmitter {
163
- options: TransportOptions;
171
+ declare class Mail<out T = SentMessageInfo, out D extends TransportOptions = TransportOptions> extends EventEmitter {
172
+ options: D;
164
173
  /** Message defaults given to createTransport, kept public because the DefinitelyTyped typings declared it */
165
174
  _defaults: MailDefaults;
166
175
  meta: Map<string, any>;
167
176
  dkim: DKIM | false;
168
- transporter: Transport<T>;
177
+ transporter: Transport<T, D>;
169
178
  logger: shared.Logger;
170
179
  /** Closes the transport, the pooled SMTP transport closes its connections */
171
180
  close: () => void;
@@ -178,7 +187,7 @@ declare class Mail<out T = SentMessageInfo> extends EventEmitter {
178
187
  };
179
188
  /** Socket handler for a proxied connection, set by setupProxy and handed to the transport on the next send */
180
189
  getSocket?: GetSocketHandler | false | undefined;
181
- constructor(transporter: Transport<T>, options?: TransportOptions, defaults?: MailDefaults);
190
+ constructor(transporter: Transport<T, D>, options?: D, defaults?: MailDefaults);
182
191
  use(step: string, plugin: PluginFunction<T>): this;
183
192
  /**
184
193
  * Sends an email using the preselected transport object
@@ -213,7 +222,10 @@ declare namespace Mail {
213
222
  type ListHeader = MailComposerListHeaderEntry;
214
223
  type ListHeaders = MailComposerListHeaders;
215
224
  type Envelope = MimeNodeEnvelopeInput;
216
- type TextEncoding = NonNullable<SendMailOptions['textEncoding']>;
225
+ type Connection = SocketOptions;
226
+ type TextEncoding = MailComposerTextEncoding;
217
227
  type PluginFunction<T = SentMessageInfo> = MailPluginFunction<T>;
218
228
  }
229
+ /** The same aliases as module level exports, for `import * as Mail` and `import Mail = require()` */
230
+ export type { SendMailOptions as Options, MimeNodeAddress as Address, MailComposerAttachment as Attachment, MailComposerAlternative as AttachmentLike, MailComposerAlternative as AmpAttachment, MailComposerIcalEvent as IcalAttachment, MimeNodeHeaders as Headers, MailComposerListHeaderEntry as ListHeader, MailComposerListHeaders as ListHeaders, MimeNodeEnvelopeInput as Envelope, SocketOptions as Connection, MailComposerTextEncoding as TextEncoding };
219
231
  export default Mail;
@@ -3,6 +3,7 @@ import type { MailComposerOptions } from '../mail-composer/index.js';
3
3
  import type { DKIMOptions } from '../dkim/index.js';
4
4
  import type { SMTPEnvelopeDsn } from '../smtp-connection/index.js';
5
5
  import type { SMTPTransportAuthOptions } from '../smtp-transport/index.js';
6
+ import type { SESSendEmailRequest } from '../ses-transport/index.js';
6
7
  import type { NodemailerError } from '../errors.js';
7
8
  import type { ResolveContentOptions } from '../shared/index.js';
8
9
  import type Mail from './index.js';
@@ -14,6 +15,8 @@ import type { SentMessageInfo } from './index.js';
14
15
  export interface SendMailOptions extends MailComposerOptions {
15
16
  /** DKIM signing options for this message, used instead of the ones of the transporter */
16
17
  dkim?: DKIMOptions | undefined;
18
+ /** Extra DKIM options for this message, merged over the options of the signer. The SES transport sets skipFields here, the option is not meant for callers */
19
+ _dkim?: DKIMOptions | undefined;
17
20
  /** Recipients allowed on this message, 0 disables the limit, defaults to 100000 */
18
21
  maxRecipients?: number | undefined;
19
22
  /** SMTP transports: DSN parameters for the envelope, sent when the server supports the DSN extension */
@@ -23,9 +26,7 @@ export interface SendMailOptions extends MailComposerOptions {
23
26
  /** SMTP transports: per-message authentication settings, used instead of the transport level auth */
24
27
  auth?: SMTPTransportAuthOptions | undefined;
25
28
  /** SES transport: extra SendEmailCommand parameters merged into the API call */
26
- ses?: {
27
- [key: string]: unknown;
28
- } | undefined;
29
+ ses?: SESSendEmailRequest | undefined;
29
30
  }
30
31
  /**
31
32
  * Default message fields, the third argument of createTransport. Applied to every message
@@ -71,7 +72,13 @@ export interface MailMessageListHeader {
71
72
  export default class MailMessage<T = SentMessageInfo> {
72
73
  mailer: Mail<T>;
73
74
  data: MailMessageData;
74
- message: MimeNode | null;
75
+ /**
76
+ * The compiled MIME tree. Set once the compile step is done, so it is null while the
77
+ * 'compile' plugins run and set by the time the 'stream' plugins and the transport see
78
+ * the message. Declared as always set, the way @types/nodemailer declared it, since the
79
+ * plugins that read it are the ones that run after it is set
80
+ */
81
+ message: MimeNode;
75
82
  constructor(mailer: Mail<T>, data?: SendMailOptions);
76
83
  resolveContent(data: {
77
84
  [key: string]: any;
@@ -107,8 +107,9 @@ class MailMessage {
107
107
  if (this.data.attachments && this.data.attachments.length) {
108
108
  this.data.attachments.forEach((attachment, i) => {
109
109
  if (!attachment.filename) {
110
+ // a backslash separates as well, so a Windows path does not put the sender's directories in the headers
110
111
  attachment.filename =
111
- (attachment.path || attachment.href || '').split('/').pop().split('?').shift() ||
112
+ (attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() ||
112
113
  'attachment-' + (i + 1);
113
114
  if (attachment.filename.indexOf('.') < 0) {
114
115
  attachment.filename += '.' + mimeFuncs.detectExtension(attachment.contentType);
@@ -2,8 +2,8 @@
2
2
  * A header value split into the value token and its parameters, the result of parseHeaderValue
3
3
  */
4
4
  export interface ParsedHeaderValue {
5
- /** The value ahead of the parameters, for example the content type */
6
- value: string | false;
5
+ /** The value ahead of the parameters, for example the content type, an empty string when there is none */
6
+ value: string;
7
7
  /** Parameter values keyed by lowercase parameter name */
8
8
  params: Record<string, string>;
9
9
  }
@@ -25,6 +25,9 @@ export interface EncodedHeaderParam {
25
25
  /** Parameter value of this part */
26
26
  value: string;
27
27
  }
28
+ /** The names @types/nodemailer used for the two types above */
29
+ export type HeaderValue = StructuredHeaderValue;
30
+ export type ParsedHeaderParam = EncodedHeaderParam;
28
31
  /**
29
32
  * Checks if a value is plaintext string (uses only printable 7bit chars)
30
33
  *
@@ -402,7 +402,7 @@ function buildHeaderParam(key, data, maxLength) {
402
402
  */
403
403
  function parseHeaderValue(str) {
404
404
  const response = {
405
- value: false,
405
+ value: '',
406
406
  params: {}
407
407
  };
408
408
  // Parameter names come from a caller supplied contentType/contentDisposition. A