nodemailer 10.0.10 → 10.0.12
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/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/dist/cjs/addressparser/index.d.ts +16 -1
- package/dist/cjs/addressparser/index.js +1 -17
- package/dist/cjs/base64/index.js +2 -1
- package/dist/cjs/dkim/index.d.ts +13 -1
- package/dist/cjs/dkim/index.js +25 -8
- package/dist/cjs/dkim/message-parser.d.ts +10 -1
- package/dist/cjs/dkim/relaxed-body.d.ts +10 -1
- package/dist/cjs/dkim/sign.d.ts +2 -0
- package/dist/cjs/dkim/sign.js +17 -1
- package/dist/cjs/errors.d.ts +3 -2
- package/dist/cjs/fetch/cookies.d.ts +12 -1
- package/dist/cjs/fetch/index.d.ts +15 -1
- package/dist/cjs/fetch/index.js +39 -64
- package/dist/cjs/json-transport/index.d.ts +14 -4
- package/dist/cjs/json-transport/index.js +2 -0
- package/dist/cjs/mail-composer/index.d.ts +8 -3
- package/dist/cjs/mailer/index.d.ts +36 -24
- package/dist/cjs/mailer/mail-message.d.ts +11 -4
- package/dist/cjs/mime-funcs/index.d.ts +5 -2
- package/dist/cjs/mime-funcs/index.js +1 -1
- package/dist/cjs/mime-node/index.d.ts +5 -2
- package/dist/cjs/nodemailer.d.ts +25 -14
- package/dist/cjs/nodemailer.js +1 -0
- package/dist/cjs/package-info.d.ts +1 -1
- package/dist/cjs/package-info.js +1 -1
- package/dist/cjs/qp/index.d.ts +2 -0
- package/dist/cjs/qp/index.js +10 -1
- package/dist/cjs/sendmail-transport/index.d.ts +2 -0
- package/dist/cjs/ses-transport/index.d.ts +33 -1
- package/dist/cjs/shared/index.d.ts +18 -6
- package/dist/cjs/shared/index.js +4 -2
- package/dist/cjs/smtp-connection/data-stream.d.ts +2 -1
- package/dist/cjs/smtp-connection/data-stream.js +32 -24
- package/dist/cjs/smtp-connection/http-proxy-client.d.ts +2 -2
- package/dist/cjs/smtp-connection/http-proxy-client.js +6 -4
- package/dist/cjs/smtp-connection/index.d.ts +58 -23
- package/dist/cjs/smtp-connection/index.js +123 -60
- package/dist/cjs/smtp-pool/index.d.ts +6 -3
- package/dist/cjs/smtp-pool/index.js +39 -11
- package/dist/cjs/smtp-pool/pool-resource.js +27 -31
- package/dist/cjs/smtp-transport/index.d.ts +13 -5
- package/dist/cjs/smtp-transport/index.js +25 -33
- package/dist/cjs/stream-transport/index.d.ts +2 -0
- package/dist/cjs/xoauth2/index.d.ts +13 -3
- package/dist/cjs/xoauth2/index.js +25 -13
- package/dist/esm/addressparser/index.d.ts +16 -1
- package/dist/esm/addressparser/index.js +2 -17
- package/dist/esm/base64/index.js +2 -1
- package/dist/esm/dkim/index.d.ts +13 -1
- package/dist/esm/dkim/index.js +25 -8
- package/dist/esm/dkim/message-parser.d.ts +10 -1
- package/dist/esm/dkim/message-parser.js +2 -1
- package/dist/esm/dkim/relaxed-body.d.ts +10 -1
- package/dist/esm/dkim/relaxed-body.js +2 -1
- package/dist/esm/dkim/sign.d.ts +2 -0
- package/dist/esm/dkim/sign.js +17 -1
- package/dist/esm/errors.d.ts +3 -2
- package/dist/esm/fetch/cookies.d.ts +12 -1
- package/dist/esm/fetch/cookies.js +2 -1
- package/dist/esm/fetch/index.d.ts +15 -1
- package/dist/esm/fetch/index.js +39 -64
- package/dist/esm/json-transport/index.d.ts +14 -4
- package/dist/esm/json-transport/index.js +2 -0
- package/dist/esm/mail-composer/index.d.ts +8 -3
- package/dist/esm/mailer/index.d.ts +36 -24
- package/dist/esm/mailer/mail-message.d.ts +11 -4
- package/dist/esm/mime-funcs/index.d.ts +5 -2
- package/dist/esm/mime-funcs/index.js +1 -1
- package/dist/esm/mime-node/index.d.ts +5 -2
- package/dist/esm/nodemailer.d.ts +25 -14
- package/dist/esm/package-info.d.ts +1 -1
- package/dist/esm/package-info.js +1 -1
- package/dist/esm/qp/index.d.ts +2 -0
- package/dist/esm/qp/index.js +10 -1
- package/dist/esm/sendmail-transport/index.d.ts +2 -0
- package/dist/esm/ses-transport/index.d.ts +33 -1
- package/dist/esm/shared/index.d.ts +18 -6
- package/dist/esm/shared/index.js +4 -2
- package/dist/esm/smtp-connection/data-stream.d.ts +2 -1
- package/dist/esm/smtp-connection/data-stream.js +32 -24
- package/dist/esm/smtp-connection/http-proxy-client.d.ts +2 -2
- package/dist/esm/smtp-connection/http-proxy-client.js +6 -4
- package/dist/esm/smtp-connection/index.d.ts +58 -23
- package/dist/esm/smtp-connection/index.js +123 -60
- package/dist/esm/smtp-pool/index.d.ts +6 -3
- package/dist/esm/smtp-pool/index.js +39 -11
- package/dist/esm/smtp-pool/pool-resource.js +27 -31
- package/dist/esm/smtp-transport/index.d.ts +13 -5
- package/dist/esm/smtp-transport/index.js +25 -33
- package/dist/esm/stream-transport/index.d.ts +2 -0
- package/dist/esm/xoauth2/index.d.ts +13 -3
- package/dist/esm/xoauth2/index.js +25 -13
- package/package.json +13 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [10.0.12](https://github.com/nodemailer/nodemailer/compare/v10.0.11...v10.0.12) (2026-09-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* settle every send on a connection error, back off pool requeues, turn a bare CR into CRLF, bound fetch, honour requireTLS ([63ccd66](https://github.com/nodemailer/nodemailer/commit/63ccd66c894bbaac18c82084ee385bf6488226cf))
|
|
9
|
+
|
|
10
|
+
## [10.0.11](https://github.com/nodemailer/nodemailer/compare/v10.0.10...v10.0.11) (2026-09-27)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **fetch:** report a form body that can not be encoded through the returned stream ([74d40bf](https://github.com/nodemailer/nodemailer/commit/74d40bf1e4553bc0568b471250a9251bcb569b00))
|
|
16
|
+
* keep the CommonJS entry point and the services subpath compatible with the pre-TypeScript build ([52901ef](https://github.com/nodemailer/nodemailer/commit/52901ef3725ad179aa56276495a60f53b2c83516))
|
|
17
|
+
* **qp:** keep wrap() terminating for short line lengths and a trailing incomplete escape ([8fa140b](https://github.com/nodemailer/nodemailer/commit/8fa140b11c62cb1202eac84d35bb3ba28bc3b1a1))
|
|
18
|
+
* **smtp-connection:** fail a password login cleanly when the server offers only XOAUTH2 ([90abf7d](https://github.com/nodemailer/nodemailer/commit/90abf7d11db5ebfeb4292b62c1fff969741c7d33))
|
|
19
|
+
* **types:** restore the layout of @types/nodemailer in the bundled declarations ([ac2e40f](https://github.com/nodemailer/nodemailer/commit/ac2e40ffc69427e0eb33ce3945fae76c4c828c8d))
|
|
20
|
+
|
|
3
21
|
## [10.0.10](https://github.com/nodemailer/nodemailer/compare/v10.0.9...v10.0.10) (2026-09-14)
|
|
4
22
|
|
|
5
23
|
|
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
|
-
|
|
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 });
|
package/dist/cjs/base64/index.js
CHANGED
|
@@ -25,7 +25,8 @@ function encode(buffer) {
|
|
|
25
25
|
*/
|
|
26
26
|
function wrap(str, lineLength) {
|
|
27
27
|
str = (str || '').toString();
|
|
28
|
-
|
|
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
|
}
|
package/dist/cjs/dkim/index.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/cjs/dkim/index.js
CHANGED
|
@@ -90,13 +90,22 @@ class DKIMSigner {
|
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
const key = this.keys[keyPos++];
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
let dkimField;
|
|
94
|
+
try {
|
|
95
|
+
dkimField = (0, sign_js_1.default)(this.headers, this.hashAlgo, this.bodyHash, {
|
|
96
|
+
domainName: key.domainName,
|
|
97
|
+
keySelector: key.keySelector,
|
|
98
|
+
privateKey: key.privateKey,
|
|
99
|
+
headerFieldNames: this.options.headerFieldNames,
|
|
100
|
+
skipFields: this.options.skipFields
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
this.hasErrored = true;
|
|
105
|
+
this.cleanup();
|
|
106
|
+
this.output.emit('error', err);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
100
109
|
if (dkimField) {
|
|
101
110
|
this.output.write(Buffer.from(dkimField + '\r\n'));
|
|
102
111
|
}
|
|
@@ -196,7 +205,15 @@ class DKIM {
|
|
|
196
205
|
}
|
|
197
206
|
const signer = new DKIMSigner(options, this.keys, inputStream, output);
|
|
198
207
|
setImmediate(() => {
|
|
199
|
-
|
|
208
|
+
try {
|
|
209
|
+
signer.signStream();
|
|
210
|
+
}
|
|
211
|
+
catch (_E) {
|
|
212
|
+
// the body hash is created here, an unknown hashAlgo throws inside this timer
|
|
213
|
+
// where nothing else could catch it
|
|
214
|
+
output.emit('error', sign_js_1.default.unsupportedHashAlgoError(signer.hashAlgo));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
200
217
|
if (writeValue) {
|
|
201
218
|
setImmediate(() => {
|
|
202
219
|
inputStream.end(writeValue);
|
|
@@ -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
|
-
|
|
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;
|
|
@@ -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
|
-
|
|
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;
|
package/dist/cjs/dkim/sign.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
+
import type { NodemailerError } from '../errors.js';
|
|
2
3
|
import type { MessageParserHeaderLine } from './message-parser.js';
|
|
3
4
|
/**
|
|
4
5
|
* Private key accepted by crypto.Sign#sign: a PEM string, a Buffer, a KeyObject or an
|
|
@@ -45,5 +46,6 @@ export interface DKIMRelaxedHeaders {
|
|
|
45
46
|
declare function sign(headers: MessageParserHeaderLine[], hashAlgo: string, bodyHash: string, options?: DKIMSignOptions): string | false;
|
|
46
47
|
declare namespace sign {
|
|
47
48
|
var relaxedHeaders: (headers: MessageParserHeaderLine[], fieldNames?: string, skipFields?: string) => DKIMRelaxedHeaders;
|
|
49
|
+
var unsupportedHashAlgoError: (hashAlgo: string) => NodemailerError;
|
|
48
50
|
}
|
|
49
51
|
export default sign;
|
package/dist/cjs/dkim/sign.js
CHANGED
|
@@ -39,6 +39,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
const punycode = __importStar(require("../punycode/index.js"));
|
|
40
40
|
const mimeFuncs = __importStar(require("../mime-funcs/index.js"));
|
|
41
41
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
42
|
+
const errors = __importStar(require("../errors.js"));
|
|
43
|
+
/**
|
|
44
|
+
* Error for a hashAlgo value the crypto module does not know
|
|
45
|
+
*/
|
|
46
|
+
function unsupportedHashAlgoError(hashAlgo) {
|
|
47
|
+
const err = new Error('Unsupported DKIM hash algorithm "' + hashAlgo + '"');
|
|
48
|
+
err.code = errors.ECONFIG;
|
|
49
|
+
return err;
|
|
50
|
+
}
|
|
42
51
|
/**
|
|
43
52
|
* Returns DKIM signature header line
|
|
44
53
|
*
|
|
@@ -63,7 +72,13 @@ function sign(headers, hashAlgo, bodyHash, options) {
|
|
|
63
72
|
const canonicalizedHeaderData = relaxedHeaders(headers, fieldNames, options.skipFields);
|
|
64
73
|
const dkimHeader = generateDKIMHeader(options.domainName, options.keySelector, canonicalizedHeaderData.fieldNames, hashAlgo, bodyHash);
|
|
65
74
|
canonicalizedHeaderData.headers += 'dkim-signature:' + relaxedHeaderLine(dkimHeader);
|
|
66
|
-
|
|
75
|
+
let signer;
|
|
76
|
+
try {
|
|
77
|
+
signer = node_crypto_1.default.createSign(('rsa-' + hashAlgo).toUpperCase());
|
|
78
|
+
}
|
|
79
|
+
catch (_E) {
|
|
80
|
+
throw unsupportedHashAlgoError(hashAlgo);
|
|
81
|
+
}
|
|
67
82
|
// the header lines are 'binary' strings, so this reproduces the original header bytes
|
|
68
83
|
signer.update(canonicalizedHeaderData.headers, 'latin1');
|
|
69
84
|
let signature;
|
|
@@ -76,6 +91,7 @@ function sign(headers, hashAlgo, bodyHash, options) {
|
|
|
76
91
|
return dkimHeader + signature.replace(/(^.{73}|.{75}(?!\r?\n|\r))/g, '$&\r\n ').trim();
|
|
77
92
|
}
|
|
78
93
|
sign.relaxedHeaders = relaxedHeaders;
|
|
94
|
+
sign.unsupportedHashAlgoError = unsupportedHashAlgoError;
|
|
79
95
|
exports.default = sign;
|
|
80
96
|
function generateDKIMHeader(domainName, keySelector, fieldNames, hashAlgo, bodyHash) {
|
|
81
97
|
// the caller supplied tag values are interpolated straight into the tag list, and none of
|
package/dist/cjs/errors.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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;
|
|
@@ -25,8 +25,10 @@ export interface FetchOptions {
|
|
|
25
25
|
tls?: {
|
|
26
26
|
[key: string]: any;
|
|
27
27
|
} | undefined;
|
|
28
|
-
/**
|
|
28
|
+
/** Socket inactivity timeout in milliseconds, defaults to 60000, 0 disables it */
|
|
29
29
|
timeout?: number | undefined;
|
|
30
|
+
/** Maximum size of the (decoded) response body in bytes, defaults to 64 MB, Infinity disables the limit */
|
|
31
|
+
maxBytes?: number | undefined;
|
|
30
32
|
/** Maximum number of redirects to follow (default 5) */
|
|
31
33
|
maxRedirects?: number | undefined;
|
|
32
34
|
/** Resolve responses with a status code of 300 or above instead of emitting an error */
|
|
@@ -47,5 +49,17 @@ export interface FetchResponse extends PassThrough {
|
|
|
47
49
|
declare function nmfetch(url: string, options?: FetchOptions): FetchResponse;
|
|
48
50
|
declare namespace nmfetch {
|
|
49
51
|
var Cookies: typeof import("./cookies.js").default;
|
|
52
|
+
var DEFAULT_TIMEOUT: number;
|
|
50
53
|
}
|
|
54
|
+
type CookiesJar = Cookies;
|
|
55
|
+
/**
|
|
56
|
+
* Type aliases in the layout of @types/nodemailer, so `fetch.Options` style references keep working
|
|
57
|
+
*/
|
|
58
|
+
declare namespace nmfetch {
|
|
59
|
+
type Options = FetchOptions;
|
|
60
|
+
type WritableResponse = FetchResponse;
|
|
61
|
+
type Cookies = CookiesJar;
|
|
62
|
+
}
|
|
63
|
+
/** The same aliases as module level exports, for `import * as fetch` and `import fetch = require()` */
|
|
64
|
+
export type { FetchOptions as Options, FetchResponse as WritableResponse, Cookies };
|
|
51
65
|
export default nmfetch;
|
package/dist/cjs/fetch/index.js
CHANGED
|
@@ -47,6 +47,10 @@ const node_net_1 = __importDefault(require("node:net"));
|
|
|
47
47
|
const errors = __importStar(require("../errors.js"));
|
|
48
48
|
const objects_js_1 = require("../shared/objects.js");
|
|
49
49
|
const MAX_REDIRECTS = 5;
|
|
50
|
+
// a stalled server would otherwise hold the request, and whatever waits on it, open forever
|
|
51
|
+
const DEFAULT_TIMEOUT = 60 * 1000;
|
|
52
|
+
// the body is usually buffered in memory by the caller, so an unbounded download is refused
|
|
53
|
+
const DEFAULT_MAX_BYTES = 64 * 1024 * 1024;
|
|
50
54
|
// Only genuine TLS settings are taken from options.tls. That object reaches us straight
|
|
51
55
|
// from a user supplied attachment (content.tls), so keys like host, port, path, socketPath
|
|
52
56
|
// or lookup would otherwise repoint the request at a destination that never went through
|
|
@@ -193,14 +197,14 @@ function nmfetch(url, options) {
|
|
|
193
197
|
.join('&'));
|
|
194
198
|
}
|
|
195
199
|
catch (E) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
200
|
+
// the caller attaches its error listener once nmfetch has returned, so
|
|
201
|
+
// the error is emitted on the next tick and the stream is handed back
|
|
202
|
+
// the way every other failure is reported
|
|
199
203
|
finished = true;
|
|
200
204
|
E.code = errors.EFETCH;
|
|
201
205
|
E.sourceUrl = url;
|
|
202
|
-
fetchRes.emit('error', E);
|
|
203
|
-
return
|
|
206
|
+
setImmediate(() => fetchRes.emit('error', E));
|
|
207
|
+
return fetchRes;
|
|
204
208
|
}
|
|
205
209
|
}
|
|
206
210
|
else {
|
|
@@ -252,28 +256,22 @@ function nmfetch(url, options) {
|
|
|
252
256
|
});
|
|
253
257
|
return fetchRes;
|
|
254
258
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (finished) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
finished = true;
|
|
261
|
-
req.abort();
|
|
262
|
-
const err = new Error('Request Timeout');
|
|
263
|
-
err.code = errors.EFETCH;
|
|
264
|
-
err.sourceUrl = url;
|
|
265
|
-
fetchRes.emit('error', err);
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
req.on('error', (err) => {
|
|
259
|
+
// reports the first failure of this request on fetchRes and releases the request
|
|
260
|
+
const fail = (err, sourceUrl = url) => {
|
|
269
261
|
if (finished) {
|
|
270
262
|
return;
|
|
271
263
|
}
|
|
272
264
|
finished = true;
|
|
273
265
|
err.code = errors.EFETCH;
|
|
274
|
-
err.sourceUrl =
|
|
266
|
+
err.sourceUrl = sourceUrl;
|
|
275
267
|
fetchRes.emit('error', err);
|
|
276
|
-
|
|
268
|
+
req.abort();
|
|
269
|
+
};
|
|
270
|
+
const timeout = typeof options.timeout === 'number' && options.timeout >= 0 ? options.timeout : DEFAULT_TIMEOUT;
|
|
271
|
+
if (timeout) {
|
|
272
|
+
req.setTimeout(timeout, () => fail(new Error('Request Timeout')));
|
|
273
|
+
}
|
|
274
|
+
req.on('error', (err) => fail(err));
|
|
277
275
|
req.on('response', res => {
|
|
278
276
|
let inflate;
|
|
279
277
|
if (finished) {
|
|
@@ -294,13 +292,7 @@ function nmfetch(url, options) {
|
|
|
294
292
|
// redirect
|
|
295
293
|
options.redirects++;
|
|
296
294
|
if (options.redirects > options.maxRedirects) {
|
|
297
|
-
|
|
298
|
-
const err = new Error('Maximum redirect count exceeded');
|
|
299
|
-
err.code = errors.EFETCH;
|
|
300
|
-
err.sourceUrl = url;
|
|
301
|
-
fetchRes.emit('error', err);
|
|
302
|
-
req.abort();
|
|
303
|
-
return;
|
|
295
|
+
return fail(new Error('Maximum redirect count exceeded'));
|
|
304
296
|
}
|
|
305
297
|
// redirect does not include POST body
|
|
306
298
|
options.method = 'GET';
|
|
@@ -320,13 +312,7 @@ function nmfetch(url, options) {
|
|
|
320
312
|
// call: that call gets its own `finished` flag and no handle on this
|
|
321
313
|
// request, so this one would stay open and could emit a second error on
|
|
322
314
|
// the shared fetchRes once it times out. Callers listen with req.once().
|
|
323
|
-
|
|
324
|
-
const err = new Error('Unsupported protocol for URL ' + redirectUrl);
|
|
325
|
-
err.code = errors.EFETCH;
|
|
326
|
-
err.sourceUrl = redirectUrl;
|
|
327
|
-
fetchRes.emit('error', err);
|
|
328
|
-
req.abort();
|
|
329
|
-
return;
|
|
315
|
+
return fail(new Error('Unsupported protocol for URL ' + redirectUrl), redirectUrl);
|
|
330
316
|
}
|
|
331
317
|
// Do not forward credentials when the redirect leaves the original
|
|
332
318
|
// security context: a different host, or a downgrade from https to
|
|
@@ -343,41 +329,33 @@ function nmfetch(url, options) {
|
|
|
343
329
|
}
|
|
344
330
|
});
|
|
345
331
|
}
|
|
332
|
+
// this request is done with, release it so its socket and timeout do not
|
|
333
|
+
// outlive it and report a late error on the shared fetchRes
|
|
334
|
+
finished = true;
|
|
335
|
+
res.resume();
|
|
336
|
+
req.abort();
|
|
346
337
|
return nmfetch(redirectUrl, options);
|
|
347
338
|
}
|
|
348
339
|
fetchRes.statusCode = res.statusCode;
|
|
349
340
|
fetchRes.headers = res.headers;
|
|
350
341
|
if (res.statusCode >= 300 && !options.allowErrorResponse) {
|
|
351
|
-
|
|
352
|
-
const err = new Error('Invalid status code ' + res.statusCode);
|
|
353
|
-
err.code = errors.EFETCH;
|
|
354
|
-
err.sourceUrl = url;
|
|
355
|
-
fetchRes.emit('error', err);
|
|
356
|
-
req.abort();
|
|
357
|
-
return;
|
|
342
|
+
return fail(new Error('Invalid status code ' + res.statusCode));
|
|
358
343
|
}
|
|
359
|
-
res.on('error', (err) =>
|
|
360
|
-
|
|
344
|
+
res.on('error', (err) => fail(err));
|
|
345
|
+
const maxBytes = typeof options.maxBytes === 'number' && options.maxBytes > 0 ? options.maxBytes : DEFAULT_MAX_BYTES;
|
|
346
|
+
const source = inflate || res;
|
|
347
|
+
let received = 0;
|
|
348
|
+
source.on('data', (chunk) => {
|
|
349
|
+
received += chunk.length;
|
|
350
|
+
if (received <= maxBytes || finished) {
|
|
361
351
|
return;
|
|
362
352
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
err.sourceUrl = url;
|
|
366
|
-
fetchRes.emit('error', err);
|
|
367
|
-
req.abort();
|
|
353
|
+
source.unpipe(fetchRes);
|
|
354
|
+
fail(new Error('Response size exceeds the allowed ' + maxBytes + ' bytes'));
|
|
368
355
|
});
|
|
369
356
|
if (inflate) {
|
|
370
357
|
res.pipe(inflate).pipe(fetchRes);
|
|
371
|
-
inflate.on('error', (err) =>
|
|
372
|
-
if (finished) {
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
finished = true;
|
|
376
|
-
err.code = errors.EFETCH;
|
|
377
|
-
err.sourceUrl = url;
|
|
378
|
-
fetchRes.emit('error', err);
|
|
379
|
-
req.abort();
|
|
380
|
-
});
|
|
358
|
+
inflate.on('error', (err) => fail(err));
|
|
381
359
|
}
|
|
382
360
|
else {
|
|
383
361
|
res.pipe(fetchRes);
|
|
@@ -392,11 +370,7 @@ function nmfetch(url, options) {
|
|
|
392
370
|
req.write(body);
|
|
393
371
|
}
|
|
394
372
|
catch (err) {
|
|
395
|
-
|
|
396
|
-
err.code = errors.EFETCH;
|
|
397
|
-
err.sourceUrl = url;
|
|
398
|
-
fetchRes.emit('error', err);
|
|
399
|
-
return;
|
|
373
|
+
return fail(err);
|
|
400
374
|
}
|
|
401
375
|
}
|
|
402
376
|
req.end();
|
|
@@ -404,6 +378,7 @@ function nmfetch(url, options) {
|
|
|
404
378
|
return fetchRes;
|
|
405
379
|
}
|
|
406
380
|
nmfetch.Cookies = cookies_js_1.default;
|
|
381
|
+
nmfetch.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
407
382
|
exports.default = nmfetch;
|
|
408
383
|
module.exports = exports.default;
|
|
409
384
|
Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });
|
|
@@ -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
|
|
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:
|
|
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?:
|
|
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;
|