nodemailer 10.0.6 → 10.0.7
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 +10 -0
- package/dist/cjs/mime-funcs/index.js +4 -1
- package/dist/cjs/mime-node/index.js +27 -5
- package/dist/cjs/package-info.d.ts +1 -1
- package/dist/cjs/package-info.js +1 -1
- package/dist/cjs/smtp-pool/index.js +4 -2
- package/dist/esm/mime-funcs/index.js +4 -1
- package/dist/esm/mime-node/index.js +27 -5
- package/dist/esm/package-info.d.ts +1 -1
- package/dist/esm/package-info.js +1 -1
- package/dist/esm/smtp-pool/index.js +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [10.0.7](https://github.com/nodemailer/nodemailer/compare/v10.0.6...v10.0.7) (2026-09-11)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **mime-funcs:** do not double encode Buffer input when chunking base64 mime words ([#1865](https://github.com/nodemailer/nodemailer/issues/1865)) ([4327a59](https://github.com/nodemailer/nodemailer/commit/4327a59939748a7f9394b0a029495fd476f68f30))
|
|
9
|
+
* **mime-node:** keep a boundary that is only line breaks from stripping to empty ([ec46800](https://github.com/nodemailer/nodemailer/commit/ec46800cdcab734d9aa79e1278e819962b3b8f09))
|
|
10
|
+
* **mime-node:** strip line breaks from multipart boundary material ([#1867](https://github.com/nodemailer/nodemailer/issues/1867)) ([03c1a5c](https://github.com/nodemailer/nodemailer/commit/03c1a5c48b6828d9392983d8718fdb1fd583a06c))
|
|
11
|
+
* **smtp-pool:** release rate-limited connections on close ([#1866](https://github.com/nodemailer/nodemailer/issues/1866)) ([7f5c7a4](https://github.com/nodemailer/nodemailer/commit/7f5c7a46b61da9f5c5feaffd921c55b9d5892ee5))
|
|
12
|
+
|
|
3
13
|
## [10.0.6](https://github.com/nodemailer/nodemailer/compare/v10.0.5...v10.0.6) (2026-09-11)
|
|
4
14
|
|
|
5
15
|
|
|
@@ -125,7 +125,10 @@ function encodeWord(data, mimeWordEncoding, maxLength) {
|
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
127
|
else if (mimeWordEncoding === 'B') {
|
|
128
|
-
|
|
128
|
+
// the chunking loop below splits raw text and base64 encodes each part, so a
|
|
129
|
+
// Buffer goes in as its UTF-8 string: handing it the base64 of the whole input
|
|
130
|
+
// would encode the encoding itself and decode back to base64 text
|
|
131
|
+
encodedStr = typeof data === 'string' ? data : data.toString('utf-8');
|
|
129
132
|
maxLength = maxLength ? Math.max(3, ((maxLength - (maxLength % 4)) / 4) * 3) : 0;
|
|
130
133
|
}
|
|
131
134
|
if (maxLength && (mimeWordEncoding !== 'B' ? encodedStr : base64.encode(data)).length > maxLength) {
|
|
@@ -99,6 +99,15 @@ function normalizeDomain(domain, toUnicode) {
|
|
|
99
99
|
}
|
|
100
100
|
return toUnicode ? punycode.toUnicode(domain) : punycode.toASCII(domain);
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Removes the line breaks that would split a value across lines once it is written out.
|
|
104
|
+
*
|
|
105
|
+
* @param value Value to clean
|
|
106
|
+
* @return Value with every CR and LF removed
|
|
107
|
+
*/
|
|
108
|
+
function _stripLineBreaks(value) {
|
|
109
|
+
return value.replace(/[\r\n]+/g, '');
|
|
110
|
+
}
|
|
102
111
|
/**
|
|
103
112
|
* Creates a new mime tree node. Assumes 'multipart/*' as the content type
|
|
104
113
|
* if it is a branch, anything else counts as leaf. If rootNode is missing from
|
|
@@ -119,10 +128,12 @@ class MimeNode {
|
|
|
119
128
|
this.nodeCounter = 0;
|
|
120
129
|
options = options || {};
|
|
121
130
|
/**
|
|
122
|
-
* shared part of the unique multipart boundary
|
|
131
|
+
* shared part of the unique multipart boundary. A line break here would split
|
|
132
|
+
* the delimiter lines the tree is streamed with, so the declared boundary could
|
|
133
|
+
* never match them again and the remainder would go out as body lines
|
|
123
134
|
*/
|
|
124
|
-
this.baseBoundary = options.baseBoundary || node_crypto_1.default.randomBytes(8).toString('hex');
|
|
125
|
-
this.boundaryPrefix = options.boundaryPrefix || '--_NmP';
|
|
135
|
+
this.baseBoundary = _stripLineBreaks(options.baseBoundary || node_crypto_1.default.randomBytes(8).toString('hex'));
|
|
136
|
+
this.boundaryPrefix = _stripLineBreaks(options.boundaryPrefix || '--_NmP');
|
|
126
137
|
this.disableFileAccess = !!options.disableFileAccess;
|
|
127
138
|
this.disableUrlAccess = !!options.disableUrlAccess;
|
|
128
139
|
this.normalizeHeaderKey = options.normalizeHeaderKey;
|
|
@@ -1169,8 +1180,19 @@ class MimeNode {
|
|
|
1169
1180
|
this.contentType = structured.value.trim().toLowerCase();
|
|
1170
1181
|
this.multipart = /^multipart\//i.test(this.contentType) ? this.contentType.substr(this.contentType.indexOf('/') + 1) : false;
|
|
1171
1182
|
if (this.multipart) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1183
|
+
// A line break in the boundary would split the delimiter lines the tree is
|
|
1184
|
+
// streamed with, so the declared boundary could never match them again and
|
|
1185
|
+
// the remainder would go out as body lines. The declared value and the
|
|
1186
|
+
// delimiters are assigned from the same expression here, so whatever the
|
|
1187
|
+
// header emitter then does with it, the two sides cannot disagree.
|
|
1188
|
+
//
|
|
1189
|
+
// Stripping runs before the fallback rather than over the whole chain: a
|
|
1190
|
+
// boundary that was nothing but line breaks would otherwise strip to '' and
|
|
1191
|
+
// leave the node declaring no boundary and streaming bare '--' delimiters.
|
|
1192
|
+
// The generated boundary is stripped too, since baseBoundary and
|
|
1193
|
+
// boundaryPrefix are public and may have been written after construction.
|
|
1194
|
+
const declared = _stripLineBreaks(structured.params.boundary || this.boundary || '');
|
|
1195
|
+
this.boundary = structured.params.boundary = declared || _stripLineBreaks(this._generateBoundary());
|
|
1174
1196
|
}
|
|
1175
1197
|
else {
|
|
1176
1198
|
this.boundary = false;
|
package/dist/cjs/package-info.js
CHANGED
|
@@ -138,8 +138,10 @@ class SMTPPool extends node_events_1.EventEmitter {
|
|
|
138
138
|
let connection;
|
|
139
139
|
const len = this._connections.length;
|
|
140
140
|
this._closed = true;
|
|
141
|
-
//
|
|
142
|
-
|
|
141
|
+
// release connections gated by the rate limiter so they become
|
|
142
|
+
// available and are torn down below instead of leaking with a
|
|
143
|
+
// cleared timer that never fires
|
|
144
|
+
this._clearRateLimit();
|
|
143
145
|
if (!len && !this._queue.length) {
|
|
144
146
|
return;
|
|
145
147
|
}
|
|
@@ -76,7 +76,10 @@ export function encodeWord(data, mimeWordEncoding, maxLength) {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
else if (mimeWordEncoding === 'B') {
|
|
79
|
-
|
|
79
|
+
// the chunking loop below splits raw text and base64 encodes each part, so a
|
|
80
|
+
// Buffer goes in as its UTF-8 string: handing it the base64 of the whole input
|
|
81
|
+
// would encode the encoding itself and decode back to base64 text
|
|
82
|
+
encodedStr = typeof data === 'string' ? data : data.toString('utf-8');
|
|
80
83
|
maxLength = maxLength ? Math.max(3, ((maxLength - (maxLength % 4)) / 4) * 3) : 0;
|
|
81
84
|
}
|
|
82
85
|
if (maxLength && (mimeWordEncoding !== 'B' ? encodedStr : base64.encode(data)).length > maxLength) {
|
|
@@ -61,6 +61,15 @@ function normalizeDomain(domain, toUnicode) {
|
|
|
61
61
|
}
|
|
62
62
|
return toUnicode ? punycode.toUnicode(domain) : punycode.toASCII(domain);
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Removes the line breaks that would split a value across lines once it is written out.
|
|
66
|
+
*
|
|
67
|
+
* @param value Value to clean
|
|
68
|
+
* @return Value with every CR and LF removed
|
|
69
|
+
*/
|
|
70
|
+
function _stripLineBreaks(value) {
|
|
71
|
+
return value.replace(/[\r\n]+/g, '');
|
|
72
|
+
}
|
|
64
73
|
/**
|
|
65
74
|
* Creates a new mime tree node. Assumes 'multipart/*' as the content type
|
|
66
75
|
* if it is a branch, anything else counts as leaf. If rootNode is missing from
|
|
@@ -81,10 +90,12 @@ class MimeNode {
|
|
|
81
90
|
this.nodeCounter = 0;
|
|
82
91
|
options = options || {};
|
|
83
92
|
/**
|
|
84
|
-
* shared part of the unique multipart boundary
|
|
93
|
+
* shared part of the unique multipart boundary. A line break here would split
|
|
94
|
+
* the delimiter lines the tree is streamed with, so the declared boundary could
|
|
95
|
+
* never match them again and the remainder would go out as body lines
|
|
85
96
|
*/
|
|
86
|
-
this.baseBoundary = options.baseBoundary || crypto.randomBytes(8).toString('hex');
|
|
87
|
-
this.boundaryPrefix = options.boundaryPrefix || '--_NmP';
|
|
97
|
+
this.baseBoundary = _stripLineBreaks(options.baseBoundary || crypto.randomBytes(8).toString('hex'));
|
|
98
|
+
this.boundaryPrefix = _stripLineBreaks(options.boundaryPrefix || '--_NmP');
|
|
88
99
|
this.disableFileAccess = !!options.disableFileAccess;
|
|
89
100
|
this.disableUrlAccess = !!options.disableUrlAccess;
|
|
90
101
|
this.normalizeHeaderKey = options.normalizeHeaderKey;
|
|
@@ -1131,8 +1142,19 @@ class MimeNode {
|
|
|
1131
1142
|
this.contentType = structured.value.trim().toLowerCase();
|
|
1132
1143
|
this.multipart = /^multipart\//i.test(this.contentType) ? this.contentType.substr(this.contentType.indexOf('/') + 1) : false;
|
|
1133
1144
|
if (this.multipart) {
|
|
1134
|
-
|
|
1135
|
-
|
|
1145
|
+
// A line break in the boundary would split the delimiter lines the tree is
|
|
1146
|
+
// streamed with, so the declared boundary could never match them again and
|
|
1147
|
+
// the remainder would go out as body lines. The declared value and the
|
|
1148
|
+
// delimiters are assigned from the same expression here, so whatever the
|
|
1149
|
+
// header emitter then does with it, the two sides cannot disagree.
|
|
1150
|
+
//
|
|
1151
|
+
// Stripping runs before the fallback rather than over the whole chain: a
|
|
1152
|
+
// boundary that was nothing but line breaks would otherwise strip to '' and
|
|
1153
|
+
// leave the node declaring no boundary and streaming bare '--' delimiters.
|
|
1154
|
+
// The generated boundary is stripped too, since baseBoundary and
|
|
1155
|
+
// boundaryPrefix are public and may have been written after construction.
|
|
1156
|
+
const declared = _stripLineBreaks(structured.params.boundary || this.boundary || '');
|
|
1157
|
+
this.boundary = structured.params.boundary = declared || _stripLineBreaks(this._generateBoundary());
|
|
1136
1158
|
}
|
|
1137
1159
|
else {
|
|
1138
1160
|
this.boundary = false;
|
package/dist/esm/package-info.js
CHANGED
|
@@ -100,8 +100,10 @@ class SMTPPool extends EventEmitter {
|
|
|
100
100
|
let connection;
|
|
101
101
|
const len = this._connections.length;
|
|
102
102
|
this._closed = true;
|
|
103
|
-
//
|
|
104
|
-
|
|
103
|
+
// release connections gated by the rate limiter so they become
|
|
104
|
+
// available and are torn down below instead of leaking with a
|
|
105
|
+
// cleared timer that never fires
|
|
106
|
+
this._clearRateLimit();
|
|
105
107
|
if (!len && !this._queue.length) {
|
|
106
108
|
return;
|
|
107
109
|
}
|