nodemailer 10.1.7 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/addressparser/index.js +2 -5
  3. package/dist/cjs/dkim/index.js +1 -3
  4. package/dist/cjs/errors.d.ts +19 -0
  5. package/dist/cjs/errors.js +14 -1
  6. package/dist/cjs/fetch/cookies.js +2 -4
  7. package/dist/cjs/fetch/index.js +2 -8
  8. package/dist/cjs/mail-composer/index.js +42 -9
  9. package/dist/cjs/mailer/mail-message.js +5 -6
  10. package/dist/cjs/mime-funcs/mime-types.js +3 -12
  11. package/dist/cjs/mime-node/index.d.ts +34 -1
  12. package/dist/cjs/mime-node/index.js +35 -13
  13. package/dist/cjs/package-info.d.ts +1 -1
  14. package/dist/cjs/package-info.js +1 -1
  15. package/dist/cjs/qp/index.js +3 -12
  16. package/dist/cjs/sendmail-transport/index.js +1 -3
  17. package/dist/cjs/shared/index.js +2 -6
  18. package/dist/cjs/smtp-connection/http-proxy-client.js +1 -1
  19. package/dist/cjs/smtp-connection/index.d.ts +6 -0
  20. package/dist/cjs/smtp-connection/index.js +15 -12
  21. package/dist/cjs/smtp-connection/server-message-id.d.ts +14 -0
  22. package/dist/cjs/smtp-connection/server-message-id.js +53 -0
  23. package/dist/cjs/smtp-pool/index.d.ts +11 -0
  24. package/dist/cjs/smtp-pool/index.js +25 -1
  25. package/dist/cjs/smtp-pool/pool-resource.js +2 -5
  26. package/dist/esm/addressparser/index.js +2 -5
  27. package/dist/esm/dkim/index.js +1 -3
  28. package/dist/esm/errors.d.ts +19 -0
  29. package/dist/esm/errors.js +12 -0
  30. package/dist/esm/fetch/cookies.js +2 -4
  31. package/dist/esm/fetch/index.js +2 -8
  32. package/dist/esm/mail-composer/index.js +42 -9
  33. package/dist/esm/mailer/mail-message.js +5 -6
  34. package/dist/esm/mime-funcs/mime-types.js +3 -12
  35. package/dist/esm/mime-node/index.d.ts +34 -1
  36. package/dist/esm/mime-node/index.js +35 -13
  37. package/dist/esm/package-info.d.ts +1 -1
  38. package/dist/esm/package-info.js +1 -1
  39. package/dist/esm/qp/index.js +3 -12
  40. package/dist/esm/sendmail-transport/index.js +1 -3
  41. package/dist/esm/shared/index.js +2 -6
  42. package/dist/esm/smtp-connection/http-proxy-client.js +1 -1
  43. package/dist/esm/smtp-connection/index.d.ts +6 -0
  44. package/dist/esm/smtp-connection/index.js +16 -13
  45. package/dist/esm/smtp-connection/server-message-id.d.ts +14 -0
  46. package/dist/esm/smtp-connection/server-message-id.js +50 -0
  47. package/dist/esm/smtp-pool/index.d.ts +11 -0
  48. package/dist/esm/smtp-pool/index.js +25 -1
  49. package/dist/esm/smtp-pool/pool-resource.js +2 -5
  50. package/package.json +4 -2
@@ -117,9 +117,7 @@ function exceedsDomainLimits(domain) {
117
117
  */
118
118
  function normalizeDomain(domain, toUnicode) {
119
119
  // domainToASCII and domainToUnicode landed in Node 7, the bundled codec covers Node 6
120
- if (typeof urlModule.domainToASCII === 'function' &&
121
- typeof urlModule.domainToUnicode === 'function' &&
122
- !URL_PARSER_UNSAFE.test(domain)) {
120
+ if (typeof urlModule.domainToASCII === 'function' && typeof urlModule.domainToUnicode === 'function' && !URL_PARSER_UNSAFE.test(domain)) {
123
121
  // The U-label form is decoded from the A-label form rather than from the input:
124
122
  // Deno's domainToASCII returns an empty string for a label it cannot decode, while
125
123
  // its domainToUnicode returns the label with U+FFFD in place of the bad part
@@ -632,9 +630,7 @@ class MimeNode {
632
630
  // the checks miss and the header ends up claiming a type it is not set up for
633
631
  structured.value = (structured.value || '').toString().replace(/[\x00-\x1f\x7f]/g, '');
634
632
  this._handleContentType(structured);
635
- if (structured.value.match(/^text\/plain\b/) &&
636
- typeof this.content === 'string' &&
637
- /[\u0080-\uFFFF]/.test(this.content)) {
633
+ if (structured.value.match(/^text\/plain\b/) && typeof this.content === 'string' && /[\u0080-\uFFFF]/.test(this.content)) {
638
634
  structured.params.charset = 'utf-8';
639
635
  }
640
636
  if (this.filename) {
@@ -675,7 +671,7 @@ class MimeNode {
675
671
  }
676
672
  break;
677
673
  }
678
- value = this._encodeHeaderValue(key, value);
674
+ value = this.encodeHeaderValue(key, value);
679
675
  // skip empty lines
680
676
  if (!(value || '').toString().trim()) {
681
677
  return;
@@ -1293,8 +1289,7 @@ class MimeNode {
1293
1289
  // where it came from. MimeNode is exported and subclassable, so the generator is
1294
1290
  // not necessarily the one below. Stripping twice costs nothing, it is idempotent.
1295
1291
  const declared = _stripBoundaryControls(structured.params.boundary || this.boundary || '');
1296
- this.boundary = structured.params.boundary =
1297
- declared || _stripBoundaryControls(this._generateBoundary());
1292
+ this.boundary = structured.params.boundary = declared || _stripBoundaryControls(this._generateBoundary());
1298
1293
  }
1299
1294
  else {
1300
1295
  this.boundary = false;
@@ -1312,13 +1307,19 @@ class MimeNode {
1312
1307
  return _stripBoundaryControls(this.rootNode.boundaryPrefix + '-' + this.rootNode.baseBoundary) + '-Part_' + this._nodeId;
1313
1308
  }
1314
1309
  /**
1315
- * Encodes a header value for use in the generated rfc2822 email.
1310
+ * Encodes a header value the way this node encodes it in the generated message:
1311
+ * address headers are punycoded and mime encoded, message id headers get their
1312
+ * angle brackets, a Date object is formatted and any other value is mime encoded
1313
+ * when it holds non-ascii or control characters (using the node's `textEncoding`).
1316
1314
  *
1317
- * @param key Header key
1315
+ * The result is a single unfolded line without the key. Fold it before writing it
1316
+ * into a message, `key + ': ' + value` folded at 76 characters is what the node does.
1317
+ *
1318
+ * @param key Header key, case insensitive
1318
1319
  * @param value Header value
1319
- * @internal
1320
+ * @returns Encoded header value
1320
1321
  */
1321
- _encodeHeaderValue(key, value) {
1322
+ encodeHeaderValue(key, value) {
1322
1323
  key = this._normalizeHeaderKey(key);
1323
1324
  switch (key) {
1324
1325
  // Structured headers
@@ -1383,6 +1384,27 @@ class MimeNode {
1383
1384
  return this._encodeHeaderText(value);
1384
1385
  }
1385
1386
  }
1387
+ /**
1388
+ * Encodes a header value without a node at hand. Same as the instance method of a
1389
+ * node created with the given options.
1390
+ *
1391
+ * @param key Header key, case insensitive
1392
+ * @param value Header value
1393
+ * @param [options] Encoding options
1394
+ * @param [options.textEncoding] either 'Q' (the default) or 'B'
1395
+ * @returns Encoded header value
1396
+ */
1397
+ static encodeHeaderValue(key, value, options) {
1398
+ return new MimeNode(false, { textEncoding: options?.textEncoding }).encodeHeaderValue(key, value);
1399
+ }
1400
+ /**
1401
+ * Alias of encodeHeaderValue, kept for callers that used the method before it was public
1402
+ *
1403
+ * @internal
1404
+ */
1405
+ _encodeHeaderValue(key, value) {
1406
+ return this.encodeHeaderValue(key, value);
1407
+ }
1386
1408
  /**
1387
1409
  * Rebuilds address object using punycode and other adjustments
1388
1410
  *
@@ -1,3 +1,3 @@
1
1
  export declare const name = "nodemailer";
2
- export declare const version = "10.1.7";
2
+ export declare const version = "10.2.0";
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.1.7';
3
+ export const version = '10.2.0';
4
4
  export const homepage = 'https://nodemailer.com/';
@@ -45,15 +45,9 @@ function encodeBytes(buffer, next, binary, previous) {
45
45
  for (let i = 0; i < len; i++) {
46
46
  const ord = buffer[i];
47
47
  const following = i + 1 < len ? buffer[i + 1] : next;
48
- const lineBreakByte = binary && (ord === 0x0d || ord === 0x0a)
49
- ? ord === 0x0d
50
- ? following === 0x0a
51
- : (i > 0 ? buffer[i - 1] : previous) === 0x0d
52
- : true;
48
+ const lineBreakByte = binary && (ord === 0x0d || ord === 0x0a) ? (ord === 0x0d ? following === 0x0a : (i > 0 ? buffer[i - 1] : previous) === 0x0d) : true;
53
49
  // if the char is in allowed range, then keep as is, unless it is a WS in the end of a line
54
- if (QP_LITERAL[ord] &&
55
- lineBreakByte &&
56
- !(isWhitespace(ord) && (following === undefined || following === 0x0a || following === 0x0d))) {
50
+ if (QP_LITERAL[ord] && lineBreakByte && !(isWhitespace(ord) && (following === undefined || following === 0x0a || following === 0x0d))) {
57
51
  output[pos++] = ord;
58
52
  continue;
59
53
  }
@@ -114,10 +108,7 @@ export function wrap(str, lineLength) {
114
108
  line = line.substr(0, line.length - match[0].length);
115
109
  }
116
110
  // ensure that utf-8 sequences are not split
117
- while (line.length > 3 &&
118
- line.length < len - pos &&
119
- !line.match(/^(?:=[\da-f]{2}){1,4}$/i) &&
120
- (match = line.match(/[=][\da-f]{2}$/gi))) {
111
+ while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/[=][\da-f]{2}$/gi))) {
121
112
  code = parseInt(match[0].substr(1, 2), 16);
122
113
  if (code < 128) {
123
114
  break;
@@ -71,9 +71,7 @@ class SendmailTransport {
71
71
  return done(err);
72
72
  }
73
73
  // force -i to keep single dots
74
- const args = this.args
75
- ? ['-i'].concat(this.args).concat(envelope.to)
76
- : ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
74
+ const args = this.args ? ['-i'].concat(this.args).concat(envelope.to) : ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
77
75
  const callback = (err) => {
78
76
  if (returned) {
79
77
  // ignore any additional responses, already done
@@ -217,9 +217,7 @@ export const resolveHostname = (options, callback) => {
217
217
  return respond(err);
218
218
  }
219
219
  // Get all supported addresses from dns.lookup
220
- const supportedAddresses = addresses
221
- ? addresses.filter(addr => isFamilySupported(addr.family)).map(addr => addr.address)
222
- : [];
220
+ const supportedAddresses = addresses ? addresses.filter(addr => isFamilySupported(addr.family)).map(addr => addr.address) : [];
223
221
  if (addresses && addresses.length && !supportedAddresses.length) {
224
222
  // there are addresses but none can be used
225
223
  console.warn(`Failed to resolve IPv${addresses[0].family} addresses with current network`);
@@ -549,9 +547,7 @@ export const assign = function (...args) {
549
547
  if (isProtoKey(key)) {
550
548
  return;
551
549
  }
552
- if (['tls', 'auth'].includes(key) &&
553
- source[key] &&
554
- typeof source[key] === 'object') {
550
+ if (['tls', 'auth'].includes(key) && source[key] && typeof source[key] === 'object') {
555
551
  // tls and auth are special keys that need to be enumerated separately
556
552
  // other objects are passed as is. Enumerating is a copy of user supplied
557
553
  // keys just like the loop above, so it gets the same treatment
@@ -9,7 +9,7 @@ import * as errors from '../errors.js';
9
9
  // never sends \r\n\r\n cannot grow memory unboundedly before the socket times out.
10
10
  const MAX_RESPONSE_HEADER_BYTES = 64 * 1024;
11
11
  // URL hostnames keep the brackets around an IPv6 literal, socket options and net.isIPv6 take it without
12
- const unbracket = (host) => typeof host === 'string' && host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
12
+ const unbracket = (host) => (typeof host === 'string' && host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host);
13
13
  function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, callback) {
14
14
  if (typeof tlsOptions === 'function') {
15
15
  callback = tlsOptions;
@@ -245,6 +245,12 @@ export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo {
245
245
  messageSize: number;
246
246
  /** Final server response for the message */
247
247
  response: string;
248
+ /**
249
+ * Message-ID the server gave the message, with angle brackets, when its final reply names
250
+ * one in a known format (Microsoft 365 and Outlook.com, Amazon SES). Such a server replaces
251
+ * the Message-ID header, so the delivered copy carries this id instead of messageId
252
+ */
253
+ serverMessageId?: string | undefined;
248
254
  }
249
255
  /**
250
256
  * Callback for send(), receives the result once the server accepted the message. The error
@@ -7,7 +7,8 @@ import crypto from 'node:crypto';
7
7
  import DataStream from './data-stream.js';
8
8
  import { PassThrough } from 'node:stream';
9
9
  import * as shared from '../shared/index.js';
10
- import { ERR_ACCESS_DENIED, isTransientError } from '../errors.js';
10
+ import { parseServerMessageId } from './server-message-id.js';
11
+ import { ERR_ACCESS_DENIED, isPermanentResponseCode, isTransientError } from '../errors.js';
11
12
  // default timeout values in ms
12
13
  const CONNECTION_TIMEOUT = 2 * 60 * 1000; // how much to wait for the connection to be established
13
14
  const SOCKET_TIMEOUT = 10 * 60 * 1000; // how much to wait for socket inactivity before disconnecting the client
@@ -361,9 +362,7 @@ class SMTPConnection extends EventEmitter {
361
362
  if (this._destroyed || this._closing) {
362
363
  return;
363
364
  }
364
- const connectFn = secure
365
- ? tls.connect
366
- : net.connect;
365
+ const connectFn = secure ? tls.connect : net.connect;
367
366
  try {
368
367
  this._socket = connectFn(opts, () => this._onConnect());
369
368
  this._setupConnectionHandlers();
@@ -701,6 +700,16 @@ class SMTPConnection extends EventEmitter {
701
700
  result.messageTime = Date.now() - envelopeTime;
702
701
  result.messageSize = stream.outByteCount;
703
702
  result.response = str;
703
+ const serverMessageId = parseServerMessageId(result.response, this.options.host);
704
+ if (serverMessageId) {
705
+ result.serverMessageId = serverMessageId;
706
+ }
707
+ // an LMTP server answers the message once per recipient, so recipients can be
708
+ // refused after the envelope info was built without any rejected errors on it
709
+ const rejectedErrors = this._envelope?.rejectedErrors;
710
+ if (!result.rejectedErrors && rejectedErrors && rejectedErrors.length) {
711
+ result.rejectedErrors = rejectedErrors;
712
+ }
704
713
  return callback(null, result);
705
714
  });
706
715
  if (typeof message.pipe === 'function') {
@@ -928,6 +937,7 @@ class SMTPConnection extends EventEmitter {
928
937
  const responseCode = (typeof response === 'string' && Number((response.match(/^\d+/) || [])[0])) || false;
929
938
  if (responseCode) {
930
939
  err.responseCode = responseCode;
940
+ err.permanent = isPermanentResponseCode(responseCode);
931
941
  }
932
942
  if (command) {
933
943
  err.command = command;
@@ -970,12 +980,7 @@ class SMTPConnection extends EventEmitter {
970
980
  this.close();
971
981
  return;
972
982
  }
973
- if (!failureResponse &&
974
- this.stage === 'connected' &&
975
- !this._responseActions.length &&
976
- !this._pendingSend &&
977
- !this._destroyed &&
978
- !this._closing) {
983
+ if (!failureResponse && this.stage === 'connected' && !this._responseActions.length && !this._pendingSend && !this._destroyed && !this._closing) {
979
984
  // nothing was waiting for the server, so this is the server ending an idle session
980
985
  // (usually after its idle timeout), not a failure
981
986
  this.logger.info({
@@ -1196,9 +1201,7 @@ class SMTPConnection extends EventEmitter {
1196
1201
  const args = [];
1197
1202
  let useSmtpUtf8 = false;
1198
1203
  this._envelope = (envelope || {});
1199
- this._envelope.from = ((this._envelope.from && this._envelope.from.address) || this._envelope.from || '')
1200
- .toString()
1201
- .trim();
1204
+ this._envelope.from = ((this._envelope.from && this._envelope.from.address) || this._envelope.from || '').toString().trim();
1202
1205
  this._envelope.to = []
1203
1206
  .concat(this._envelope.to || [])
1204
1207
  .map(to => ((to && to.address) || to || '').toString().trim());
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Reads the Message-ID a receiving server gave the message out of its final 250 reply. Some
3
+ * servers replace the Message-ID header of a submitted message with one of their own, and
4
+ * the copy the recipients and the sent folder get carries that one instead of the id the
5
+ * message was built with. Only replies in a format known to carry such an id are read.
6
+ */
7
+ /**
8
+ * Reads the server assigned Message-ID out of the final reply to a message
9
+ *
10
+ * @param response Final server reply for the message
11
+ * @param [host] Hostname the connection was made to, SES replies are only read for an SES host
12
+ * @returns The Message-ID with its angle brackets, or undefined when the reply names none
13
+ */
14
+ export declare function parseServerMessageId(response: string | undefined, host?: string): string | undefined;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Reads the Message-ID a receiving server gave the message out of its final 250 reply. Some
3
+ * servers replace the Message-ID header of a submitted message with one of their own, and
4
+ * the copy the recipients and the sent folder get carries that one instead of the id the
5
+ * message was built with. Only replies in a format known to carry such an id are read.
6
+ */
7
+ // Microsoft 365 and Outlook.com: "250 2.0.0 OK <id@host.prod.outlook.com> [Hostname=...]"
8
+ const OUTLOOK_REPLY = /^250 2\.0\.0 OK (<[^<>\s]+\.prod\.outlook\.com>)/i;
9
+ // Amazon SES: "250 Ok 0100018b5c3c0a4f-...-000000", the local part of the Message-ID it sets
10
+ const SES_REPLY = /^250 Ok ([0-9a-f]+(?:-[0-9a-f]+)+)$/i;
11
+ // an AWS region name such as us-east-1 or ap-southeast-2
12
+ const AWS_REGION = /^[a-z]{2}(?:-[a-z]+)+-\d+$/;
13
+ /**
14
+ * Finds the AWS region an SES SMTP endpoint is in from its hostname, such as
15
+ * email-smtp.eu-west-1.amazonaws.com or a VPC endpoint name under it
16
+ *
17
+ * @param host SMTP hostname
18
+ * @returns Region name, or undefined for a host outside amazonaws.com and awsapps.com
19
+ */
20
+ function sesRegion(host) {
21
+ const labels = host.toLowerCase().replace(/\.$/, '').split('.');
22
+ const domain = labels.slice(-2).join('.');
23
+ if (domain !== 'amazonaws.com' && domain !== 'awsapps.com') {
24
+ return undefined;
25
+ }
26
+ return labels.slice(0, -2).find(label => AWS_REGION.test(label));
27
+ }
28
+ /**
29
+ * Reads the server assigned Message-ID out of the final reply to a message
30
+ *
31
+ * @param response Final server reply for the message
32
+ * @param [host] Hostname the connection was made to, SES replies are only read for an SES host
33
+ * @returns The Message-ID with its angle brackets, or undefined when the reply names none
34
+ */
35
+ export function parseServerMessageId(response, host) {
36
+ const reply = (response || '').toString().trim();
37
+ const outlook = reply.match(OUTLOOK_REPLY);
38
+ if (outlook) {
39
+ return outlook[1];
40
+ }
41
+ const ses = reply.match(SES_REPLY);
42
+ if (ses && host) {
43
+ const region = sesRegion(host);
44
+ if (region) {
45
+ // the SES Message-ID domain is email.amazonses.com in us-east-1 and the region elsewhere
46
+ return '<' + ses[1].toLowerCase() + '@' + (region === 'us-east-1' ? 'email' : region) + '.amazonses.com>';
47
+ }
48
+ }
49
+ return undefined;
50
+ }
@@ -110,6 +110,17 @@ declare class SMTPPool extends EventEmitter {
110
110
  * Returns true if there are free slots in the queue
111
111
  */
112
112
  isIdle(): boolean;
113
+ /**
114
+ * Counts the messages the pool has not finished with yet: the ones waiting in the queue
115
+ * plus the ones a connection is transmitting right now. isIdle() only tells whether the
116
+ * pool can take another message, it is already true while a message is still being sent,
117
+ * so use this to check that nothing would be lost by closing the pool. A message that is
118
+ * re-queued after its connection dropped is counted until its callback runs, also while it waits to be put back on the queue, and
119
+ * it is no longer counted by the time its callback runs.
120
+ *
121
+ * @returns Number of queued and in-flight messages
122
+ */
123
+ pendingCount(): number;
113
124
  /**
114
125
  * Verifies SMTP configuration
115
126
  *
@@ -62,6 +62,7 @@ class SMTPPool extends EventEmitter {
62
62
  this._queue = [];
63
63
  this._connections = [];
64
64
  this._connectionCounter = 0;
65
+ this._pending = 0;
65
66
  this.idling = true;
66
67
  setImmediate(() => {
67
68
  if (this.idling) {
@@ -94,10 +95,20 @@ class SMTPPool extends EventEmitter {
94
95
  setImmediate(() => callback(err));
95
96
  return false;
96
97
  }
98
+ // counted until the callback runs, whichever path runs it: delivered, failed, requeued
99
+ // until it gives up, or drained by close()
100
+ let counted = true;
101
+ this._pending++;
97
102
  this._queue.push({
98
103
  mail,
99
104
  requeueAttempts: 0,
100
- callback
105
+ callback: (err, info) => {
106
+ if (counted) {
107
+ counted = false;
108
+ this._pending--;
109
+ }
110
+ callback(err, info);
111
+ }
101
112
  });
102
113
  if (this.idling && this._queue.length >= this.options.maxConnections) {
103
114
  this.idling = false;
@@ -441,6 +452,19 @@ class SMTPPool extends EventEmitter {
441
452
  isIdle() {
442
453
  return this.idling;
443
454
  }
455
+ /**
456
+ * Counts the messages the pool has not finished with yet: the ones waiting in the queue
457
+ * plus the ones a connection is transmitting right now. isIdle() only tells whether the
458
+ * pool can take another message, it is already true while a message is still being sent,
459
+ * so use this to check that nothing would be lost by closing the pool. A message that is
460
+ * re-queued after its connection dropped is counted until its callback runs, also while it waits to be put back on the queue, and
461
+ * it is no longer counted by the time its callback runs.
462
+ *
463
+ * @returns Number of queued and in-flight messages
464
+ */
465
+ pendingCount() {
466
+ return this._pending;
467
+ }
444
468
  verify(callback) {
445
469
  let promise;
446
470
  if (!callback) {
@@ -19,8 +19,7 @@ export default class PoolResource extends EventEmitter {
19
19
  switch ((this.options.auth.type || '').toString().toUpperCase()) {
20
20
  case 'OAUTH2': {
21
21
  const oauth2 = new XOAuth2(this.options.auth, this.logger);
22
- oauth2.provisionCallback =
23
- (this.pool.mailer && this.pool.mailer.get('oauth2_provision_cb')) || oauth2.provisionCallback;
22
+ oauth2.provisionCallback = (this.pool.mailer && this.pool.mailer.get('oauth2_provision_cb')) || oauth2.provisionCallback;
24
23
  this.auth = {
25
24
  type: 'OAUTH2',
26
25
  user: this.options.auth.user,
@@ -208,9 +207,7 @@ export default class PoolResource extends EventEmitter {
208
207
  this.connection.close();
209
208
  return;
210
209
  }
211
- if ((err.code === errors.EENVELOPE || err.code === errors.EMESSAGE) &&
212
- err.responseCode !== 421 &&
213
- !this.connection._destroyed) {
210
+ if ((err.code === errors.EENVELOPE || err.code === errors.EMESSAGE) && err.responseCode !== 421 && !this.connection._destroyed) {
214
211
  // The server refused this message, the connection itself is fine. Reset the
215
212
  // session and keep using it instead of opening a new one
216
213
  this.connection.reset(resetErr => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "10.1.7",
3
+ "version": "10.2.0",
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",
@@ -128,6 +128,8 @@
128
128
  "test": "node --import tsx --test --test-concurrency=1 $(find test \\( -name '*-test.ts' -o -name '*.test.ts' \\))",
129
129
  "pretest:coverage": "npm run build",
130
130
  "test:coverage": "c8 node --import tsx --test --test-concurrency=1 $(find test \\( -name '*-test.ts' -o -name '*.test.ts' \\))",
131
+ "pretest:cjs": "npm run build",
132
+ "test:cjs": "NODE_OPTIONS=--no-experimental-require-module node test/package/cjs-smoke.cjs",
131
133
  "pretest:bun": "npm run build",
132
134
  "test:bun": "bun test --timeout 60000 $(find ./test \\( -name '*-test.ts' -o -name '*.test.ts' \\))",
133
135
  "format": "prettier --write \"**/*.{js,cjs,ts,json,md}\"",
@@ -155,7 +157,7 @@
155
157
  "@types/node": "20.19.43",
156
158
  "bunyan": "1.8.15",
157
159
  "c8": "12.0.0",
158
- "eslint": "10.12.0",
160
+ "eslint": "10.13.0",
159
161
  "eslint-config-prettier": "10.1.8",
160
162
  "globals": "17.13.0",
161
163
  "libbase64": "1.3.2",