nodemailer 10.0.14 → 10.0.16

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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [10.0.16](https://github.com/nodemailer/nodemailer/compare/v10.0.15...v10.0.16) (2026-10-07)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **addressparser:** keep an escaped parenthesis inside a comment ([c4ae20d](https://github.com/nodemailer/nodemailer/commit/c4ae20d074ac0510cc2d0cbd6039ee7fab3a4ca8))
9
+ * **fetch:** keep the case of cookie names ([#1888](https://github.com/nodemailer/nodemailer/issues/1888)) ([9f16eed](https://github.com/nodemailer/nodemailer/commit/9f16eedf8de0485e6d07969113db992ff70f89ce))
10
+ * **fetch:** read the cookie name-value pair by position ([645e97c](https://github.com/nodemailer/nodemailer/commit/645e97c8f0586404d9fb861c9527be7572c2c832))
11
+
12
+ ## [10.0.15](https://github.com/nodemailer/nodemailer/compare/v10.0.14...v10.0.15) (2026-10-05)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **errors:** inherit NodemailerError code from ErrnoException ([e99db61](https://github.com/nodemailer/nodemailer/commit/e99db61d51c244e184a3a79103d1d732ffb6376b)), closes [#1884](https://github.com/nodemailer/nodemailer/issues/1884)
18
+ * **errors:** keep NodemailerError compatible with @types/node 26 ErrnoException ([#1885](https://github.com/nodemailer/nodemailer/issues/1885)) ([b660328](https://github.com/nodemailer/nodemailer/commit/b6603286cc45bff52c13cc74e5ac47f424452fdc))
19
+
3
20
  ## [10.0.14](https://github.com/nodemailer/nodemailer/compare/v10.0.13...v10.0.14) (2026-10-03)
4
21
 
5
22
 
@@ -670,7 +670,11 @@ class Tokenizer {
670
670
  this.escaped = false;
671
671
  return;
672
672
  }
673
- else if (['"', "'"].includes(this.operatorExpecting) && chr === '\\') {
673
+ else if (['"', "'", ')'].includes(this.operatorExpecting) && chr === '\\') {
674
+ // A backslash escapes the next character inside a quoted string and inside a
675
+ // comment alike (RFC 5322 3.2.2, ccontent includes quoted-pair). Honouring it
676
+ // only in quoted strings let an escaped parenthesis close the comment, which
677
+ // released the rest of it, an address included, into the header
674
678
  this.escaped = true;
675
679
  return;
676
680
  }
@@ -65,11 +65,11 @@ export declare const EFETCH = "EFETCH";
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
67
  * depends on where the error originated. Socket level errors keep the errno
68
- * and syscall fields Node.js sets on them.
68
+ * and syscall fields Node.js sets on them. `code` (see ERROR_CODES) is
69
+ * inherited from ErrnoException, not redeclared, so it follows the
70
+ * consumer's @types/node.
69
71
  */
70
72
  export interface NodemailerError extends NodeJS.ErrnoException {
71
- /** Nodemailer error code, see ERROR_CODES */
72
- code?: string | undefined;
73
73
  /** SMTP command that was in flight when the server replied with an error */
74
74
  command?: string | undefined;
75
75
  /** Raw SMTP server response */
@@ -130,19 +130,31 @@ class Cookies {
130
130
  */
131
131
  parse(cookieStr) {
132
132
  const cookie = {};
133
+ let hasNameValue = false;
133
134
  (cookieStr || '')
134
135
  .toString()
135
136
  .split(';')
136
137
  .forEach(cookiePart => {
138
+ if (!cookiePart.trim()) {
139
+ // skip empty parts
140
+ return;
141
+ }
137
142
  const valueParts = cookiePart.split('=');
138
- const key = valueParts.shift().trim().toLowerCase();
143
+ const name = valueParts.shift().trim();
139
144
  let value = valueParts.join('=').trim();
140
145
  let domain;
141
- if (!key) {
142
- // skip empty parts
146
+ // the first part is always the name-value pair, so a cookie named
147
+ // like an attribute is not mistaken for one (RFC 6265 section 5.2)
148
+ if (!hasNameValue) {
149
+ hasNameValue = true;
150
+ if (name) {
151
+ // cookie names are case-sensitive, only attribute names are not
152
+ cookie.name = name;
153
+ cookie.value = value;
154
+ }
143
155
  return;
144
156
  }
145
- switch (key) {
157
+ switch (name.toLowerCase()) {
146
158
  case 'expires': {
147
159
  const expires = new Date(value);
148
160
  // ignore date if can not parse it
@@ -170,11 +182,6 @@ class Cookies {
170
182
  case 'httponly':
171
183
  cookie.httponly = true;
172
184
  break;
173
- default:
174
- if (!cookie.name) {
175
- cookie.name = key;
176
- cookie.value = value;
177
- }
178
185
  }
179
186
  });
180
187
  return cookie;
@@ -1,3 +1,3 @@
1
1
  export declare const name = "nodemailer";
2
- export declare const version = "10.0.14";
2
+ export declare const version = "10.0.16";
3
3
  export declare const homepage = "https://nodemailer.com/";
@@ -3,5 +3,5 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.homepage = exports.version = exports.name = void 0;
5
5
  exports.name = 'nodemailer';
6
- exports.version = '10.0.14';
6
+ exports.version = '10.0.16';
7
7
  exports.homepage = 'https://nodemailer.com/';
@@ -668,7 +668,11 @@ class Tokenizer {
668
668
  this.escaped = false;
669
669
  return;
670
670
  }
671
- else if (['"', "'"].includes(this.operatorExpecting) && chr === '\\') {
671
+ else if (['"', "'", ')'].includes(this.operatorExpecting) && chr === '\\') {
672
+ // A backslash escapes the next character inside a quoted string and inside a
673
+ // comment alike (RFC 5322 3.2.2, ccontent includes quoted-pair). Honouring it
674
+ // only in quoted strings let an escaped parenthesis close the comment, which
675
+ // released the rest of it, an address included, into the header
672
676
  this.escaped = true;
673
677
  return;
674
678
  }
@@ -65,11 +65,11 @@ export declare const EFETCH = "EFETCH";
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
67
  * depends on where the error originated. Socket level errors keep the errno
68
- * and syscall fields Node.js sets on them.
68
+ * and syscall fields Node.js sets on them. `code` (see ERROR_CODES) is
69
+ * inherited from ErrnoException, not redeclared, so it follows the
70
+ * consumer's @types/node.
69
71
  */
70
72
  export interface NodemailerError extends NodeJS.ErrnoException {
71
- /** Nodemailer error code, see ERROR_CODES */
72
- code?: string | undefined;
73
73
  /** SMTP command that was in flight when the server replied with an error */
74
74
  command?: string | undefined;
75
75
  /** Raw SMTP server response */
@@ -92,19 +92,31 @@ class Cookies {
92
92
  */
93
93
  parse(cookieStr) {
94
94
  const cookie = {};
95
+ let hasNameValue = false;
95
96
  (cookieStr || '')
96
97
  .toString()
97
98
  .split(';')
98
99
  .forEach(cookiePart => {
100
+ if (!cookiePart.trim()) {
101
+ // skip empty parts
102
+ return;
103
+ }
99
104
  const valueParts = cookiePart.split('=');
100
- const key = valueParts.shift().trim().toLowerCase();
105
+ const name = valueParts.shift().trim();
101
106
  let value = valueParts.join('=').trim();
102
107
  let domain;
103
- if (!key) {
104
- // skip empty parts
108
+ // the first part is always the name-value pair, so a cookie named
109
+ // like an attribute is not mistaken for one (RFC 6265 section 5.2)
110
+ if (!hasNameValue) {
111
+ hasNameValue = true;
112
+ if (name) {
113
+ // cookie names are case-sensitive, only attribute names are not
114
+ cookie.name = name;
115
+ cookie.value = value;
116
+ }
105
117
  return;
106
118
  }
107
- switch (key) {
119
+ switch (name.toLowerCase()) {
108
120
  case 'expires': {
109
121
  const expires = new Date(value);
110
122
  // ignore date if can not parse it
@@ -132,11 +144,6 @@ class Cookies {
132
144
  case 'httponly':
133
145
  cookie.httponly = true;
134
146
  break;
135
- default:
136
- if (!cookie.name) {
137
- cookie.name = key;
138
- cookie.value = value;
139
- }
140
147
  }
141
148
  });
142
149
  return cookie;
@@ -1,3 +1,3 @@
1
1
  export declare const name = "nodemailer";
2
- export declare const version = "10.0.14";
2
+ export declare const version = "10.0.16";
3
3
  export declare const homepage = "https://nodemailer.com/";
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/build.js from package.json. Do not edit by hand.
2
2
  export const name = 'nodemailer';
3
- export const version = '10.0.14';
3
+ export const version = '10.0.16';
4
4
  export const homepage = 'https://nodemailer.com/';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "10.0.14",
3
+ "version": "10.0.16",
4
4
  "description": "Easy as cake e-mail sending from your Node.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/nodemailer.js",
@@ -158,17 +158,17 @@
158
158
  "eslint": "10.12.0",
159
159
  "eslint-config-prettier": "10.1.8",
160
160
  "globals": "17.13.0",
161
- "libbase64": "1.3.1",
162
- "libmime": "5.4.6",
161
+ "libbase64": "1.3.2",
162
+ "libmime": "5.4.7",
163
163
  "libqp": "2.1.2",
164
- "mailauth": "7.1.0",
164
+ "mailauth": "7.1.1",
165
165
  "prettier": "3.9.9",
166
166
  "proxy": "1.0.2",
167
167
  "proxy-test-server": "1.0.0",
168
- "smtp-server": "3.19.16",
168
+ "smtp-server": "3.19.17",
169
169
  "tsx": "4.23.15",
170
170
  "typescript": "6.0.3",
171
- "typescript-eslint": "8.71.0"
171
+ "typescript-eslint": "8.71.1"
172
172
  },
173
173
  "engines": {
174
174
  "node": ">=20.0.0"