nodemailer 7.0.4 → 7.0.6
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 +16 -0
- package/lib/base64/index.js +11 -14
- package/lib/mail-composer/index.js +26 -2
- package/lib/mime-funcs/index.js +1 -1
- package/lib/shared/index.js +55 -33
- package/lib/smtp-connection/index.js +2 -2
- package/lib/well-known/services.json +277 -42
- package/lib/xoauth2/index.js +57 -6
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [7.0.6](https://github.com/nodemailer/nodemailer/compare/v7.0.5...v7.0.6) (2025-08-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **encoder:** avoid silent data loss by properly flushing trailing base64 ([#1747](https://github.com/nodemailer/nodemailer/issues/1747)) ([01ae76f](https://github.com/nodemailer/nodemailer/commit/01ae76f2cfe991c0c3fe80170f236da60531496b))
|
|
9
|
+
* handle multiple XOAUTH2 token requests correctly ([#1754](https://github.com/nodemailer/nodemailer/issues/1754)) ([dbe0028](https://github.com/nodemailer/nodemailer/commit/dbe00286351cddf012726a41a96ae613d30a34ee))
|
|
10
|
+
* ReDoS vulnerability in parseDataURI and _processDataUrl ([#1755](https://github.com/nodemailer/nodemailer/issues/1755)) ([90b3e24](https://github.com/nodemailer/nodemailer/commit/90b3e24d23929ebf9f4e16261049b40ee4055a39))
|
|
11
|
+
|
|
12
|
+
## [7.0.5](https://github.com/nodemailer/nodemailer/compare/v7.0.4...v7.0.5) (2025-07-07)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* updated well known delivery service list ([fa2724b](https://github.com/nodemailer/nodemailer/commit/fa2724b337eb8d8fdcdd788fe903980b061316b8))
|
|
18
|
+
|
|
3
19
|
## [7.0.4](https://github.com/nodemailer/nodemailer/compare/v7.0.3...v7.0.4) (2025-06-29)
|
|
4
20
|
|
|
5
21
|
|
package/lib/base64/index.js
CHANGED
|
@@ -35,15 +35,12 @@ function wrap(str, lineLength) {
|
|
|
35
35
|
let pos = 0;
|
|
36
36
|
let chunkLength = lineLength * 1024;
|
|
37
37
|
while (pos < str.length) {
|
|
38
|
-
let wrappedLines = str
|
|
39
|
-
.substr(pos, chunkLength)
|
|
40
|
-
.replace(new RegExp('.{' + lineLength + '}', 'g'), '$&\r\n')
|
|
41
|
-
.trim();
|
|
38
|
+
let wrappedLines = str.substr(pos, chunkLength).replace(new RegExp('.{' + lineLength + '}', 'g'), '$&\r\n');
|
|
42
39
|
result.push(wrappedLines);
|
|
43
40
|
pos += chunkLength;
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
return result.join('
|
|
43
|
+
return result.join('');
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
/**
|
|
@@ -56,7 +53,6 @@ function wrap(str, lineLength) {
|
|
|
56
53
|
class Encoder extends Transform {
|
|
57
54
|
constructor(options) {
|
|
58
55
|
super();
|
|
59
|
-
// init Transform
|
|
60
56
|
this.options = options || {};
|
|
61
57
|
|
|
62
58
|
if (this.options.lineLength !== false) {
|
|
@@ -98,17 +94,20 @@ class Encoder extends Transform {
|
|
|
98
94
|
if (this.options.lineLength) {
|
|
99
95
|
b64 = wrap(b64, this.options.lineLength);
|
|
100
96
|
|
|
101
|
-
// remove last line as it is still most probably incomplete
|
|
102
97
|
let lastLF = b64.lastIndexOf('\n');
|
|
103
98
|
if (lastLF < 0) {
|
|
104
99
|
this._curLine = b64;
|
|
105
100
|
b64 = '';
|
|
106
|
-
} else if (lastLF === b64.length - 1) {
|
|
107
|
-
this._curLine = '';
|
|
108
101
|
} else {
|
|
109
|
-
this._curLine = b64.
|
|
110
|
-
b64 = b64.
|
|
102
|
+
this._curLine = b64.substring(lastLF + 1);
|
|
103
|
+
b64 = b64.substring(0, lastLF + 1);
|
|
104
|
+
|
|
105
|
+
if (b64 && !b64.endsWith('\r\n')) {
|
|
106
|
+
b64 += '\r\n';
|
|
107
|
+
}
|
|
111
108
|
}
|
|
109
|
+
} else {
|
|
110
|
+
this._curLine = '';
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
if (b64) {
|
|
@@ -125,16 +124,14 @@ class Encoder extends Transform {
|
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
if (this._curLine) {
|
|
128
|
-
this._curLine = wrap(this._curLine, this.options.lineLength);
|
|
129
127
|
this.outputBytes += this._curLine.length;
|
|
130
|
-
this.push(this._curLine, 'ascii');
|
|
128
|
+
this.push(Buffer.from(this._curLine, 'ascii'));
|
|
131
129
|
this._curLine = '';
|
|
132
130
|
}
|
|
133
131
|
done();
|
|
134
132
|
}
|
|
135
133
|
}
|
|
136
134
|
|
|
137
|
-
// expose to the world
|
|
138
135
|
module.exports = {
|
|
139
136
|
encode,
|
|
140
137
|
wrap,
|
|
@@ -550,9 +550,33 @@ class MailComposer {
|
|
|
550
550
|
* @return {Object} Parsed element
|
|
551
551
|
*/
|
|
552
552
|
_processDataUrl(element) {
|
|
553
|
+
const dataUrl = element.path || element.href;
|
|
554
|
+
|
|
555
|
+
// Early validation to prevent ReDoS
|
|
556
|
+
if (!dataUrl || typeof dataUrl !== 'string') {
|
|
557
|
+
return element;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (!dataUrl.startsWith('data:')) {
|
|
561
|
+
return element;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (dataUrl.length > 100000) {
|
|
565
|
+
// 100KB limit for data URL string
|
|
566
|
+
// Return empty content for excessively long data URLs
|
|
567
|
+
return Object.assign({}, element, {
|
|
568
|
+
path: false,
|
|
569
|
+
href: false,
|
|
570
|
+
content: Buffer.alloc(0),
|
|
571
|
+
contentType: element.contentType || 'application/octet-stream'
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
|
|
553
575
|
let parsedDataUri;
|
|
554
|
-
|
|
555
|
-
parsedDataUri = parseDataURI(
|
|
576
|
+
try {
|
|
577
|
+
parsedDataUri = parseDataURI(dataUrl);
|
|
578
|
+
} catch (err) {
|
|
579
|
+
return element;
|
|
556
580
|
}
|
|
557
581
|
|
|
558
582
|
if (!parsedDataUri) {
|
package/lib/mime-funcs/index.js
CHANGED
|
@@ -269,7 +269,7 @@ module.exports = {
|
|
|
269
269
|
|
|
270
270
|
// first line includes the charset and language info and needs to be encoded
|
|
271
271
|
// even if it does not contain any unicode characters
|
|
272
|
-
line =
|
|
272
|
+
line = "utf-8''";
|
|
273
273
|
let encoded = true;
|
|
274
274
|
startPos = 0;
|
|
275
275
|
|
package/lib/shared/index.js
CHANGED
|
@@ -419,52 +419,74 @@ module.exports.callbackPromise = (resolve, reject) =>
|
|
|
419
419
|
};
|
|
420
420
|
|
|
421
421
|
module.exports.parseDataURI = uri => {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (!commaPos) {
|
|
425
|
-
return uri;
|
|
422
|
+
if (typeof uri !== 'string') {
|
|
423
|
+
return null;
|
|
426
424
|
}
|
|
427
425
|
|
|
428
|
-
|
|
429
|
-
|
|
426
|
+
// Early return for non-data URIs to avoid unnecessary processing
|
|
427
|
+
if (!uri.startsWith('data:')) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
430
|
|
|
431
|
-
|
|
431
|
+
// Find the first comma safely - this prevents ReDoS
|
|
432
|
+
const commaPos = uri.indexOf(',');
|
|
433
|
+
if (commaPos === -1) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
432
436
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
437
|
+
const data = uri.substring(commaPos + 1);
|
|
438
|
+
const metaStr = uri.substring('data:'.length, commaPos);
|
|
439
|
+
|
|
440
|
+
let encoding;
|
|
441
|
+
const metaEntries = metaStr.split(';');
|
|
442
|
+
|
|
443
|
+
if (metaEntries.length > 0) {
|
|
444
|
+
const lastEntry = metaEntries[metaEntries.length - 1].toLowerCase().trim();
|
|
445
|
+
// Only recognize valid encoding types to prevent manipulation
|
|
446
|
+
if (['base64', 'utf8', 'utf-8'].includes(lastEntry) && lastEntry.indexOf('=') === -1) {
|
|
447
|
+
encoding = lastEntry;
|
|
448
|
+
metaEntries.pop();
|
|
449
|
+
}
|
|
438
450
|
}
|
|
439
451
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
452
|
+
const contentType = metaEntries.length > 0 ? metaEntries.shift() : 'application/octet-stream';
|
|
453
|
+
const params = {};
|
|
454
|
+
|
|
455
|
+
for (let i = 0; i < metaEntries.length; i++) {
|
|
456
|
+
const entry = metaEntries[i];
|
|
457
|
+
const sepPos = entry.indexOf('=');
|
|
458
|
+
if (sepPos > 0) {
|
|
459
|
+
// Ensure there's a key before the '='
|
|
460
|
+
const key = entry.substring(0, sepPos).trim();
|
|
461
|
+
const value = entry.substring(sepPos + 1).trim();
|
|
462
|
+
if (key) {
|
|
463
|
+
params[key] = value;
|
|
464
|
+
}
|
|
448
465
|
}
|
|
449
466
|
}
|
|
450
467
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
break;
|
|
458
|
-
default:
|
|
468
|
+
// Decode data based on encoding with proper error handling
|
|
469
|
+
let bufferData;
|
|
470
|
+
try {
|
|
471
|
+
if (encoding === 'base64') {
|
|
472
|
+
bufferData = Buffer.from(data, 'base64');
|
|
473
|
+
} else {
|
|
459
474
|
try {
|
|
460
|
-
|
|
461
|
-
} catch (
|
|
462
|
-
|
|
475
|
+
bufferData = Buffer.from(decodeURIComponent(data));
|
|
476
|
+
} catch (decodeError) {
|
|
477
|
+
bufferData = Buffer.from(data);
|
|
463
478
|
}
|
|
464
|
-
|
|
479
|
+
}
|
|
480
|
+
} catch (bufferError) {
|
|
481
|
+
bufferData = Buffer.alloc(0);
|
|
465
482
|
}
|
|
466
483
|
|
|
467
|
-
return {
|
|
484
|
+
return {
|
|
485
|
+
data: bufferData,
|
|
486
|
+
encoding: encoding || null,
|
|
487
|
+
contentType: contentType || 'application/octet-stream',
|
|
488
|
+
params
|
|
489
|
+
};
|
|
468
490
|
};
|
|
469
491
|
|
|
470
492
|
/**
|
|
@@ -1619,7 +1619,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1619
1619
|
}
|
|
1620
1620
|
|
|
1621
1621
|
if (!this._envelope.rcptQueue.length) {
|
|
1622
|
-
return callback(this._formatError('
|
|
1622
|
+
return callback(this._formatError("Can't send mail - no recipients defined", 'EENVELOPE', false, 'API'));
|
|
1623
1623
|
} else {
|
|
1624
1624
|
this._recipientQueue = [];
|
|
1625
1625
|
|
|
@@ -1675,7 +1675,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1675
1675
|
});
|
|
1676
1676
|
this._sendCommand('DATA');
|
|
1677
1677
|
} else {
|
|
1678
|
-
err = this._formatError('
|
|
1678
|
+
err = this._formatError("Can't send mail - all recipients were rejected", 'EENVELOPE', str, 'RCPT TO');
|
|
1679
1679
|
err.rejected = this._envelope.rejected;
|
|
1680
1680
|
err.rejectedErrors = this._envelope.rejectedErrors;
|
|
1681
1681
|
return callback(err);
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"1und1": {
|
|
3
|
+
"description": "1&1 Mail (German hosting provider)",
|
|
3
4
|
"host": "smtp.1und1.de",
|
|
4
5
|
"port": 465,
|
|
5
6
|
"secure": true,
|
|
6
7
|
"authMethod": "LOGIN"
|
|
7
8
|
},
|
|
8
9
|
|
|
10
|
+
"126": {
|
|
11
|
+
"description": "126 Mail (NetEase)",
|
|
12
|
+
"host": "smtp.126.com",
|
|
13
|
+
"port": 465,
|
|
14
|
+
"secure": true
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
"163": {
|
|
18
|
+
"description": "163 Mail (NetEase)",
|
|
19
|
+
"host": "smtp.163.com",
|
|
20
|
+
"port": 465,
|
|
21
|
+
"secure": true
|
|
22
|
+
},
|
|
23
|
+
|
|
9
24
|
"Aliyun": {
|
|
25
|
+
"description": "Alibaba Cloud Mail",
|
|
10
26
|
"domains": ["aliyun.com"],
|
|
11
27
|
"host": "smtp.aliyun.com",
|
|
12
28
|
"port": 465,
|
|
@@ -14,56 +30,91 @@
|
|
|
14
30
|
},
|
|
15
31
|
|
|
16
32
|
"AliyunQiye": {
|
|
33
|
+
"description": "Alibaba Cloud Enterprise Mail",
|
|
17
34
|
"host": "smtp.qiye.aliyun.com",
|
|
18
35
|
"port": 465,
|
|
19
36
|
"secure": true
|
|
20
37
|
},
|
|
21
38
|
|
|
22
39
|
"AOL": {
|
|
40
|
+
"description": "AOL Mail",
|
|
23
41
|
"domains": ["aol.com"],
|
|
24
42
|
"host": "smtp.aol.com",
|
|
25
43
|
"port": 587
|
|
26
44
|
},
|
|
27
45
|
|
|
46
|
+
"Aruba": {
|
|
47
|
+
"description": "Aruba PEC (Italian email provider)",
|
|
48
|
+
"domains": ["aruba.it", "pec.aruba.it"],
|
|
49
|
+
"aliases": ["Aruba PEC"],
|
|
50
|
+
"host": "smtps.aruba.it",
|
|
51
|
+
"port": 465,
|
|
52
|
+
"secure": true,
|
|
53
|
+
"authMethod": "LOGIN"
|
|
54
|
+
},
|
|
55
|
+
|
|
28
56
|
"Bluewin": {
|
|
57
|
+
"description": "Bluewin (Swiss email provider)",
|
|
29
58
|
"host": "smtpauths.bluewin.ch",
|
|
30
59
|
"domains": ["bluewin.ch"],
|
|
31
60
|
"port": 465
|
|
32
61
|
},
|
|
33
62
|
|
|
63
|
+
"BOL": {
|
|
64
|
+
"description": "BOL Mail (Brazilian provider)",
|
|
65
|
+
"domains": ["bol.com.br"],
|
|
66
|
+
"host": "smtp.bol.com.br",
|
|
67
|
+
"port": 587,
|
|
68
|
+
"requireTLS": true
|
|
69
|
+
},
|
|
70
|
+
|
|
34
71
|
"DebugMail": {
|
|
72
|
+
"description": "DebugMail (email testing service)",
|
|
35
73
|
"host": "debugmail.io",
|
|
36
74
|
"port": 25
|
|
37
75
|
},
|
|
38
76
|
|
|
77
|
+
"Disroot": {
|
|
78
|
+
"description": "Disroot (privacy-focused provider)",
|
|
79
|
+
"domains": ["disroot.org"],
|
|
80
|
+
"host": "disroot.org",
|
|
81
|
+
"port": 587,
|
|
82
|
+
"secure": false,
|
|
83
|
+
"authMethod": "LOGIN"
|
|
84
|
+
},
|
|
85
|
+
|
|
39
86
|
"DynectEmail": {
|
|
87
|
+
"description": "Dyn Email Delivery",
|
|
40
88
|
"aliases": ["Dynect"],
|
|
41
89
|
"host": "smtp.dynect.net",
|
|
42
90
|
"port": 25
|
|
43
91
|
},
|
|
44
92
|
|
|
93
|
+
"ElasticEmail": {
|
|
94
|
+
"description": "Elastic Email",
|
|
95
|
+
"aliases": ["Elastic Email"],
|
|
96
|
+
"host": "smtp.elasticemail.com",
|
|
97
|
+
"port": 465,
|
|
98
|
+
"secure": true
|
|
99
|
+
},
|
|
100
|
+
|
|
45
101
|
"Ethereal": {
|
|
102
|
+
"description": "Ethereal Email (email testing service)",
|
|
46
103
|
"aliases": ["ethereal.email"],
|
|
47
104
|
"host": "smtp.ethereal.email",
|
|
48
105
|
"port": 587
|
|
49
106
|
},
|
|
50
107
|
|
|
51
108
|
"FastMail": {
|
|
109
|
+
"description": "FastMail",
|
|
52
110
|
"domains": ["fastmail.fm"],
|
|
53
111
|
"host": "smtp.fastmail.com",
|
|
54
112
|
"port": 465,
|
|
55
113
|
"secure": true
|
|
56
114
|
},
|
|
57
115
|
|
|
58
|
-
"Forward Email": {
|
|
59
|
-
"aliases": ["FE", "ForwardEmail"],
|
|
60
|
-
"domains": ["forwardemail.net"],
|
|
61
|
-
"host": "smtp.forwardemail.net",
|
|
62
|
-
"port": 465,
|
|
63
|
-
"secure": true
|
|
64
|
-
},
|
|
65
|
-
|
|
66
116
|
"Feishu Mail": {
|
|
117
|
+
"description": "Feishu Mail (Lark)",
|
|
67
118
|
"aliases": ["Feishu", "FeishuMail"],
|
|
68
119
|
"domains": ["www.feishu.cn"],
|
|
69
120
|
"host": "smtp.feishu.cn",
|
|
@@ -71,13 +122,24 @@
|
|
|
71
122
|
"secure": true
|
|
72
123
|
},
|
|
73
124
|
|
|
125
|
+
"Forward Email": {
|
|
126
|
+
"description": "Forward Email (email forwarding service)",
|
|
127
|
+
"aliases": ["FE", "ForwardEmail"],
|
|
128
|
+
"domains": ["forwardemail.net"],
|
|
129
|
+
"host": "smtp.forwardemail.net",
|
|
130
|
+
"port": 465,
|
|
131
|
+
"secure": true
|
|
132
|
+
},
|
|
133
|
+
|
|
74
134
|
"GandiMail": {
|
|
135
|
+
"description": "Gandi Mail",
|
|
75
136
|
"aliases": ["Gandi", "Gandi Mail"],
|
|
76
137
|
"host": "mail.gandi.net",
|
|
77
138
|
"port": 587
|
|
78
139
|
},
|
|
79
140
|
|
|
80
141
|
"Gmail": {
|
|
142
|
+
"description": "Gmail",
|
|
81
143
|
"aliases": ["Google Mail"],
|
|
82
144
|
"domains": ["gmail.com", "googlemail.com"],
|
|
83
145
|
"host": "smtp.gmail.com",
|
|
@@ -85,26 +147,38 @@
|
|
|
85
147
|
"secure": true
|
|
86
148
|
},
|
|
87
149
|
|
|
150
|
+
"GMX": {
|
|
151
|
+
"description": "GMX Mail",
|
|
152
|
+
"domains": ["gmx.com", "gmx.net", "gmx.de"],
|
|
153
|
+
"host": "mail.gmx.com",
|
|
154
|
+
"port": 587
|
|
155
|
+
},
|
|
156
|
+
|
|
88
157
|
"Godaddy": {
|
|
158
|
+
"description": "GoDaddy Email (US)",
|
|
89
159
|
"host": "smtpout.secureserver.net",
|
|
90
160
|
"port": 25
|
|
91
161
|
},
|
|
92
162
|
|
|
93
163
|
"GodaddyAsia": {
|
|
164
|
+
"description": "GoDaddy Email (Asia)",
|
|
94
165
|
"host": "smtp.asia.secureserver.net",
|
|
95
166
|
"port": 25
|
|
96
167
|
},
|
|
97
168
|
|
|
98
169
|
"GodaddyEurope": {
|
|
170
|
+
"description": "GoDaddy Email (Europe)",
|
|
99
171
|
"host": "smtp.europe.secureserver.net",
|
|
100
172
|
"port": 25
|
|
101
173
|
},
|
|
102
174
|
|
|
103
175
|
"hot.ee": {
|
|
176
|
+
"description": "Hot.ee (Estonian email provider)",
|
|
104
177
|
"host": "mail.hot.ee"
|
|
105
178
|
},
|
|
106
179
|
|
|
107
180
|
"Hotmail": {
|
|
181
|
+
"description": "Outlook.com / Hotmail",
|
|
108
182
|
"aliases": ["Outlook", "Outlook.com", "Hotmail.com"],
|
|
109
183
|
"domains": ["hotmail.com", "outlook.com"],
|
|
110
184
|
"host": "smtp-mail.outlook.com",
|
|
@@ -112,6 +186,7 @@
|
|
|
112
186
|
},
|
|
113
187
|
|
|
114
188
|
"iCloud": {
|
|
189
|
+
"description": "iCloud Mail",
|
|
115
190
|
"aliases": ["Me", "Mac"],
|
|
116
191
|
"domains": ["me.com", "mac.com"],
|
|
117
192
|
"host": "smtp.mail.me.com",
|
|
@@ -119,72 +194,117 @@
|
|
|
119
194
|
},
|
|
120
195
|
|
|
121
196
|
"Infomaniak": {
|
|
197
|
+
"description": "Infomaniak Mail (Swiss hosting provider)",
|
|
122
198
|
"host": "mail.infomaniak.com",
|
|
123
199
|
"domains": ["ik.me", "ikmail.com", "etik.com"],
|
|
124
200
|
"port": 587
|
|
125
201
|
},
|
|
202
|
+
|
|
203
|
+
"KolabNow": {
|
|
204
|
+
"description": "KolabNow (secure email service)",
|
|
205
|
+
"domains": ["kolabnow.com"],
|
|
206
|
+
"aliases": ["Kolab"],
|
|
207
|
+
"host": "smtp.kolabnow.com",
|
|
208
|
+
"port": 465,
|
|
209
|
+
"secure": true,
|
|
210
|
+
"authMethod": "LOGIN"
|
|
211
|
+
},
|
|
212
|
+
|
|
126
213
|
"Loopia": {
|
|
214
|
+
"description": "Loopia (Swedish hosting provider)",
|
|
127
215
|
"host": "mailcluster.loopia.se",
|
|
128
216
|
"port": 465
|
|
129
217
|
},
|
|
218
|
+
|
|
219
|
+
"Loops": {
|
|
220
|
+
"description": "Loops",
|
|
221
|
+
"host": "smtp.loops.so",
|
|
222
|
+
"port": 587
|
|
223
|
+
},
|
|
224
|
+
|
|
130
225
|
"mail.ee": {
|
|
226
|
+
"description": "Mail.ee (Estonian email provider)",
|
|
131
227
|
"host": "smtp.mail.ee"
|
|
132
228
|
},
|
|
133
229
|
|
|
134
230
|
"Mail.ru": {
|
|
231
|
+
"description": "Mail.ru",
|
|
135
232
|
"host": "smtp.mail.ru",
|
|
136
233
|
"port": 465,
|
|
137
234
|
"secure": true
|
|
138
235
|
},
|
|
139
236
|
|
|
140
237
|
"Mailcatch.app": {
|
|
238
|
+
"description": "Mailcatch (email testing service)",
|
|
141
239
|
"host": "sandbox-smtp.mailcatch.app",
|
|
142
240
|
"port": 2525
|
|
143
241
|
},
|
|
144
242
|
|
|
145
243
|
"Maildev": {
|
|
244
|
+
"description": "MailDev (local email testing)",
|
|
146
245
|
"port": 1025,
|
|
147
246
|
"ignoreTLS": true
|
|
148
247
|
},
|
|
149
248
|
|
|
249
|
+
"MailerSend": {
|
|
250
|
+
"description": "MailerSend",
|
|
251
|
+
"host": "smtp.mailersend.net",
|
|
252
|
+
"port": 587
|
|
253
|
+
},
|
|
254
|
+
|
|
150
255
|
"Mailgun": {
|
|
256
|
+
"description": "Mailgun",
|
|
151
257
|
"host": "smtp.mailgun.org",
|
|
152
258
|
"port": 465,
|
|
153
259
|
"secure": true
|
|
154
260
|
},
|
|
155
261
|
|
|
156
262
|
"Mailjet": {
|
|
263
|
+
"description": "Mailjet",
|
|
157
264
|
"host": "in.mailjet.com",
|
|
158
265
|
"port": 587
|
|
159
266
|
},
|
|
160
267
|
|
|
161
268
|
"Mailosaur": {
|
|
269
|
+
"description": "Mailosaur (email testing service)",
|
|
162
270
|
"host": "mailosaur.io",
|
|
163
271
|
"port": 25
|
|
164
272
|
},
|
|
165
273
|
|
|
166
274
|
"Mailtrap": {
|
|
275
|
+
"description": "Mailtrap",
|
|
167
276
|
"host": "live.smtp.mailtrap.io",
|
|
168
277
|
"port": 587
|
|
169
278
|
},
|
|
170
279
|
|
|
171
280
|
"Mandrill": {
|
|
281
|
+
"description": "Mandrill (by Mailchimp)",
|
|
172
282
|
"host": "smtp.mandrillapp.com",
|
|
173
283
|
"port": 587
|
|
174
284
|
},
|
|
175
285
|
|
|
176
286
|
"Naver": {
|
|
287
|
+
"description": "Naver Mail (Korean email provider)",
|
|
177
288
|
"host": "smtp.naver.com",
|
|
178
289
|
"port": 587
|
|
179
290
|
},
|
|
180
291
|
|
|
292
|
+
"OhMySMTP": {
|
|
293
|
+
"description": "OhMySMTP (email delivery service)",
|
|
294
|
+
"host": "smtp.ohmysmtp.com",
|
|
295
|
+
"port": 587,
|
|
296
|
+
"secure": false
|
|
297
|
+
},
|
|
298
|
+
|
|
181
299
|
"One": {
|
|
300
|
+
"description": "One.com Email",
|
|
182
301
|
"host": "send.one.com",
|
|
183
302
|
"port": 465,
|
|
184
303
|
"secure": true
|
|
185
304
|
},
|
|
186
305
|
|
|
187
306
|
"OpenMailBox": {
|
|
307
|
+
"description": "OpenMailBox",
|
|
188
308
|
"aliases": ["OMB", "openmailbox.org"],
|
|
189
309
|
"host": "smtp.openmailbox.org",
|
|
190
310
|
"port": 465,
|
|
@@ -192,24 +312,21 @@
|
|
|
192
312
|
},
|
|
193
313
|
|
|
194
314
|
"Outlook365": {
|
|
315
|
+
"description": "Microsoft 365 / Office 365",
|
|
195
316
|
"host": "smtp.office365.com",
|
|
196
317
|
"port": 587,
|
|
197
318
|
"secure": false
|
|
198
319
|
},
|
|
199
320
|
|
|
200
|
-
"OhMySMTP": {
|
|
201
|
-
"host": "smtp.ohmysmtp.com",
|
|
202
|
-
"port": 587,
|
|
203
|
-
"secure": false
|
|
204
|
-
},
|
|
205
|
-
|
|
206
321
|
"Postmark": {
|
|
322
|
+
"description": "Postmark",
|
|
207
323
|
"aliases": ["PostmarkApp"],
|
|
208
324
|
"host": "smtp.postmarkapp.com",
|
|
209
325
|
"port": 2525
|
|
210
326
|
},
|
|
211
327
|
|
|
212
328
|
"Proton": {
|
|
329
|
+
"description": "Proton Mail",
|
|
213
330
|
"aliases": ["ProtonMail", "Proton.me", "Protonmail.com", "Protonmail.ch"],
|
|
214
331
|
"domains": ["proton.me", "protonmail.com", "pm.me", "protonmail.ch"],
|
|
215
332
|
"host": "smtp.protonmail.ch",
|
|
@@ -218,12 +335,14 @@
|
|
|
218
335
|
},
|
|
219
336
|
|
|
220
337
|
"qiye.aliyun": {
|
|
338
|
+
"description": "Alibaba Mail Enterprise Edition",
|
|
221
339
|
"host": "smtp.mxhichina.com",
|
|
222
340
|
"port": "465",
|
|
223
341
|
"secure": true
|
|
224
342
|
},
|
|
225
343
|
|
|
226
344
|
"QQ": {
|
|
345
|
+
"description": "QQ Mail",
|
|
227
346
|
"domains": ["qq.com"],
|
|
228
347
|
"host": "smtp.qq.com",
|
|
229
348
|
"port": 465,
|
|
@@ -231,6 +350,7 @@
|
|
|
231
350
|
},
|
|
232
351
|
|
|
233
352
|
"QQex": {
|
|
353
|
+
"description": "QQ Enterprise Mail",
|
|
234
354
|
"aliases": ["QQ Enterprise"],
|
|
235
355
|
"domains": ["exmail.qq.com"],
|
|
236
356
|
"host": "smtp.exmail.qq.com",
|
|
@@ -238,89 +358,189 @@
|
|
|
238
358
|
"secure": true
|
|
239
359
|
},
|
|
240
360
|
|
|
361
|
+
"Resend": {
|
|
362
|
+
"description": "Resend",
|
|
363
|
+
"host": "smtp.resend.com",
|
|
364
|
+
"port": 465,
|
|
365
|
+
"secure": true
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
"Runbox": {
|
|
369
|
+
"description": "Runbox (Norwegian email provider)",
|
|
370
|
+
"domains": ["runbox.com"],
|
|
371
|
+
"host": "smtp.runbox.com",
|
|
372
|
+
"port": 465,
|
|
373
|
+
"secure": true
|
|
374
|
+
},
|
|
375
|
+
|
|
241
376
|
"SendCloud": {
|
|
377
|
+
"description": "SendCloud (Chinese email delivery)",
|
|
242
378
|
"host": "smtp.sendcloud.net",
|
|
243
379
|
"port": 2525
|
|
244
380
|
},
|
|
245
381
|
|
|
246
382
|
"SendGrid": {
|
|
383
|
+
"description": "SendGrid",
|
|
247
384
|
"host": "smtp.sendgrid.net",
|
|
248
385
|
"port": 587
|
|
249
386
|
},
|
|
250
387
|
|
|
251
388
|
"SendinBlue": {
|
|
389
|
+
"description": "Brevo (formerly Sendinblue)",
|
|
252
390
|
"aliases": ["Brevo"],
|
|
253
391
|
"host": "smtp-relay.brevo.com",
|
|
254
392
|
"port": 587
|
|
255
393
|
},
|
|
256
394
|
|
|
257
395
|
"SendPulse": {
|
|
396
|
+
"description": "SendPulse",
|
|
258
397
|
"host": "smtp-pulse.com",
|
|
259
398
|
"port": 465,
|
|
260
399
|
"secure": true
|
|
261
400
|
},
|
|
262
401
|
|
|
263
402
|
"SES": {
|
|
403
|
+
"description": "AWS SES US East (N. Virginia)",
|
|
264
404
|
"host": "email-smtp.us-east-1.amazonaws.com",
|
|
265
405
|
"port": 465,
|
|
266
406
|
"secure": true
|
|
267
407
|
},
|
|
268
408
|
|
|
269
|
-
"SES-
|
|
270
|
-
"
|
|
409
|
+
"SES-AP-NORTHEAST-1": {
|
|
410
|
+
"description": "AWS SES Asia Pacific (Tokyo)",
|
|
411
|
+
"host": "email-smtp.ap-northeast-1.amazonaws.com",
|
|
271
412
|
"port": 465,
|
|
272
413
|
"secure": true
|
|
273
414
|
},
|
|
274
415
|
|
|
275
|
-
"SES-
|
|
276
|
-
"
|
|
416
|
+
"SES-AP-NORTHEAST-2": {
|
|
417
|
+
"description": "AWS SES Asia Pacific (Seoul)",
|
|
418
|
+
"host": "email-smtp.ap-northeast-2.amazonaws.com",
|
|
277
419
|
"port": 465,
|
|
278
420
|
"secure": true
|
|
279
421
|
},
|
|
280
422
|
|
|
281
|
-
"SES-
|
|
282
|
-
"
|
|
423
|
+
"SES-AP-NORTHEAST-3": {
|
|
424
|
+
"description": "AWS SES Asia Pacific (Osaka)",
|
|
425
|
+
"host": "email-smtp.ap-northeast-3.amazonaws.com",
|
|
283
426
|
"port": 465,
|
|
284
427
|
"secure": true
|
|
285
428
|
},
|
|
286
429
|
|
|
287
430
|
"SES-AP-SOUTH-1": {
|
|
431
|
+
"description": "AWS SES Asia Pacific (Mumbai)",
|
|
288
432
|
"host": "email-smtp.ap-south-1.amazonaws.com",
|
|
289
433
|
"port": 465,
|
|
290
434
|
"secure": true
|
|
291
435
|
},
|
|
292
436
|
|
|
293
|
-
"SES-AP-
|
|
294
|
-
"
|
|
437
|
+
"SES-AP-SOUTHEAST-1": {
|
|
438
|
+
"description": "AWS SES Asia Pacific (Singapore)",
|
|
439
|
+
"host": "email-smtp.ap-southeast-1.amazonaws.com",
|
|
295
440
|
"port": 465,
|
|
296
441
|
"secure": true
|
|
297
442
|
},
|
|
298
443
|
|
|
299
|
-
"SES-AP-
|
|
300
|
-
"
|
|
444
|
+
"SES-AP-SOUTHEAST-2": {
|
|
445
|
+
"description": "AWS SES Asia Pacific (Sydney)",
|
|
446
|
+
"host": "email-smtp.ap-southeast-2.amazonaws.com",
|
|
301
447
|
"port": 465,
|
|
302
448
|
"secure": true
|
|
303
449
|
},
|
|
304
450
|
|
|
305
|
-
"SES-
|
|
306
|
-
"
|
|
451
|
+
"SES-CA-CENTRAL-1": {
|
|
452
|
+
"description": "AWS SES Canada (Central)",
|
|
453
|
+
"host": "email-smtp.ca-central-1.amazonaws.com",
|
|
307
454
|
"port": 465,
|
|
308
455
|
"secure": true
|
|
309
456
|
},
|
|
310
457
|
|
|
311
|
-
"SES-
|
|
312
|
-
"
|
|
458
|
+
"SES-EU-CENTRAL-1": {
|
|
459
|
+
"description": "AWS SES Europe (Frankfurt)",
|
|
460
|
+
"host": "email-smtp.eu-central-1.amazonaws.com",
|
|
313
461
|
"port": 465,
|
|
314
462
|
"secure": true
|
|
315
463
|
},
|
|
316
464
|
|
|
317
|
-
"SES-
|
|
318
|
-
"
|
|
465
|
+
"SES-EU-NORTH-1": {
|
|
466
|
+
"description": "AWS SES Europe (Stockholm)",
|
|
467
|
+
"host": "email-smtp.eu-north-1.amazonaws.com",
|
|
468
|
+
"port": 465,
|
|
469
|
+
"secure": true
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
"SES-EU-WEST-1": {
|
|
473
|
+
"description": "AWS SES Europe (Ireland)",
|
|
474
|
+
"host": "email-smtp.eu-west-1.amazonaws.com",
|
|
475
|
+
"port": 465,
|
|
476
|
+
"secure": true
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
"SES-EU-WEST-2": {
|
|
480
|
+
"description": "AWS SES Europe (London)",
|
|
481
|
+
"host": "email-smtp.eu-west-2.amazonaws.com",
|
|
482
|
+
"port": 465,
|
|
483
|
+
"secure": true
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
"SES-EU-WEST-3": {
|
|
487
|
+
"description": "AWS SES Europe (Paris)",
|
|
488
|
+
"host": "email-smtp.eu-west-3.amazonaws.com",
|
|
489
|
+
"port": 465,
|
|
490
|
+
"secure": true
|
|
491
|
+
},
|
|
492
|
+
|
|
493
|
+
"SES-SA-EAST-1": {
|
|
494
|
+
"description": "AWS SES South America (São Paulo)",
|
|
495
|
+
"host": "email-smtp.sa-east-1.amazonaws.com",
|
|
496
|
+
"port": 465,
|
|
497
|
+
"secure": true
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
"SES-US-EAST-1": {
|
|
501
|
+
"description": "AWS SES US East (N. Virginia)",
|
|
502
|
+
"host": "email-smtp.us-east-1.amazonaws.com",
|
|
503
|
+
"port": 465,
|
|
504
|
+
"secure": true
|
|
505
|
+
},
|
|
506
|
+
|
|
507
|
+
"SES-US-EAST-2": {
|
|
508
|
+
"description": "AWS SES US East (Ohio)",
|
|
509
|
+
"host": "email-smtp.us-east-2.amazonaws.com",
|
|
510
|
+
"port": 465,
|
|
511
|
+
"secure": true
|
|
512
|
+
},
|
|
513
|
+
|
|
514
|
+
"SES-US-GOV-EAST-1": {
|
|
515
|
+
"description": "AWS SES GovCloud (US-East)",
|
|
516
|
+
"host": "email-smtp.us-gov-east-1.amazonaws.com",
|
|
517
|
+
"port": 465,
|
|
518
|
+
"secure": true
|
|
519
|
+
},
|
|
520
|
+
|
|
521
|
+
"SES-US-GOV-WEST-1": {
|
|
522
|
+
"description": "AWS SES GovCloud (US-West)",
|
|
523
|
+
"host": "email-smtp.us-gov-west-1.amazonaws.com",
|
|
524
|
+
"port": 465,
|
|
525
|
+
"secure": true
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
"SES-US-WEST-1": {
|
|
529
|
+
"description": "AWS SES US West (N. California)",
|
|
530
|
+
"host": "email-smtp.us-west-1.amazonaws.com",
|
|
531
|
+
"port": 465,
|
|
532
|
+
"secure": true
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
"SES-US-WEST-2": {
|
|
536
|
+
"description": "AWS SES US West (Oregon)",
|
|
537
|
+
"host": "email-smtp.us-west-2.amazonaws.com",
|
|
319
538
|
"port": 465,
|
|
320
539
|
"secure": true
|
|
321
540
|
},
|
|
322
541
|
|
|
323
542
|
"Seznam": {
|
|
543
|
+
"description": "Seznam Email (Czech email provider)",
|
|
324
544
|
"aliases": ["Seznam Email"],
|
|
325
545
|
"domains": ["seznam.cz", "email.cz", "post.cz", "spoluzaci.cz"],
|
|
326
546
|
"host": "smtp.seznam.cz",
|
|
@@ -328,7 +548,14 @@
|
|
|
328
548
|
"secure": true
|
|
329
549
|
},
|
|
330
550
|
|
|
551
|
+
"SMTP2GO": {
|
|
552
|
+
"description": "SMTP2GO",
|
|
553
|
+
"host": "mail.smtp2go.com",
|
|
554
|
+
"port": 2525
|
|
555
|
+
},
|
|
556
|
+
|
|
331
557
|
"Sparkpost": {
|
|
558
|
+
"description": "SparkPost",
|
|
332
559
|
"aliases": ["SparkPost", "SparkPost Mail"],
|
|
333
560
|
"domains": ["sparkpost.com"],
|
|
334
561
|
"host": "smtp.sparkpostmail.com",
|
|
@@ -337,11 +564,21 @@
|
|
|
337
564
|
},
|
|
338
565
|
|
|
339
566
|
"Tipimail": {
|
|
567
|
+
"description": "Tipimail (email delivery service)",
|
|
340
568
|
"host": "smtp.tipimail.com",
|
|
341
569
|
"port": 587
|
|
342
570
|
},
|
|
343
571
|
|
|
572
|
+
"Tutanota": {
|
|
573
|
+
"description": "Tutanota (Tuta Mail)",
|
|
574
|
+
"domains": ["tutanota.com", "tuta.com", "tutanota.de", "tuta.io"],
|
|
575
|
+
"host": "smtp.tutanota.com",
|
|
576
|
+
"port": 465,
|
|
577
|
+
"secure": true
|
|
578
|
+
},
|
|
579
|
+
|
|
344
580
|
"Yahoo": {
|
|
581
|
+
"description": "Yahoo Mail",
|
|
345
582
|
"domains": ["yahoo.com"],
|
|
346
583
|
"host": "smtp.mail.yahoo.com",
|
|
347
584
|
"port": 465,
|
|
@@ -349,28 +586,26 @@
|
|
|
349
586
|
},
|
|
350
587
|
|
|
351
588
|
"Yandex": {
|
|
589
|
+
"description": "Yandex Mail",
|
|
352
590
|
"domains": ["yandex.ru"],
|
|
353
591
|
"host": "smtp.yandex.ru",
|
|
354
592
|
"port": 465,
|
|
355
593
|
"secure": true
|
|
356
594
|
},
|
|
357
595
|
|
|
596
|
+
"Zimbra": {
|
|
597
|
+
"description": "Zimbra Mail Server",
|
|
598
|
+
"aliases": ["Zimbra Collaboration"],
|
|
599
|
+
"host": "smtp.zimbra.com",
|
|
600
|
+
"port": 587,
|
|
601
|
+
"requireTLS": true
|
|
602
|
+
},
|
|
603
|
+
|
|
358
604
|
"Zoho": {
|
|
605
|
+
"description": "Zoho Mail",
|
|
359
606
|
"host": "smtp.zoho.com",
|
|
360
607
|
"port": 465,
|
|
361
608
|
"secure": true,
|
|
362
609
|
"authMethod": "LOGIN"
|
|
363
|
-
},
|
|
364
|
-
|
|
365
|
-
"126": {
|
|
366
|
-
"host": "smtp.126.com",
|
|
367
|
-
"port": 465,
|
|
368
|
-
"secure": true
|
|
369
|
-
},
|
|
370
|
-
|
|
371
|
-
"163": {
|
|
372
|
-
"host": "smtp.163.com",
|
|
373
|
-
"port": 465,
|
|
374
|
-
"secure": true
|
|
375
610
|
}
|
|
376
611
|
}
|
package/lib/xoauth2/index.js
CHANGED
|
@@ -72,6 +72,9 @@ class XOAuth2 extends Stream {
|
|
|
72
72
|
let timeout = Math.max(Number(this.options.timeout) || 0, 0);
|
|
73
73
|
this.expires = (timeout && Date.now() + timeout * 1000) || 0;
|
|
74
74
|
}
|
|
75
|
+
|
|
76
|
+
this.renewing = false; // Track if renewal is in progress
|
|
77
|
+
this.renewalQueue = []; // Queue for pending requests during renewal
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
/**
|
|
@@ -82,14 +85,61 @@ class XOAuth2 extends Stream {
|
|
|
82
85
|
*/
|
|
83
86
|
getToken(renew, callback) {
|
|
84
87
|
if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) {
|
|
88
|
+
this.logger.debug(
|
|
89
|
+
{
|
|
90
|
+
tnx: 'OAUTH2',
|
|
91
|
+
user: this.options.user,
|
|
92
|
+
action: 'reuse'
|
|
93
|
+
},
|
|
94
|
+
'Reusing existing access token for %s',
|
|
95
|
+
this.options.user
|
|
96
|
+
);
|
|
85
97
|
return callback(null, this.accessToken);
|
|
86
98
|
}
|
|
87
99
|
|
|
88
|
-
|
|
89
|
-
|
|
100
|
+
// check if it is possible to renew, if not, return the current token or error
|
|
101
|
+
if (!this.provisionCallback && !this.options.refreshToken && !this.options.serviceClient) {
|
|
102
|
+
if (this.accessToken) {
|
|
103
|
+
this.logger.debug(
|
|
104
|
+
{
|
|
105
|
+
tnx: 'OAUTH2',
|
|
106
|
+
user: this.options.user,
|
|
107
|
+
action: 'reuse'
|
|
108
|
+
},
|
|
109
|
+
'Reusing existing access token (no refresh capability) for %s',
|
|
110
|
+
this.options.user
|
|
111
|
+
);
|
|
112
|
+
return callback(null, this.accessToken);
|
|
113
|
+
}
|
|
114
|
+
this.logger.error(
|
|
115
|
+
{
|
|
116
|
+
tnx: 'OAUTH2',
|
|
117
|
+
user: this.options.user,
|
|
118
|
+
action: 'renew'
|
|
119
|
+
},
|
|
120
|
+
'Cannot renew access token for %s: No refresh mechanism available',
|
|
121
|
+
this.options.user
|
|
122
|
+
);
|
|
123
|
+
return callback(new Error("Can't create new access token for user"));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// If renewal already in progress, queue this request instead of starting another
|
|
127
|
+
if (this.renewing) {
|
|
128
|
+
return this.renewalQueue.push({ renew, callback });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.renewing = true;
|
|
132
|
+
|
|
133
|
+
// Handles token renewal completion - processes queued requests and cleans up
|
|
134
|
+
const generateCallback = (err, accessToken) => {
|
|
135
|
+
this.renewalQueue.forEach(item => item.callback(err, accessToken));
|
|
136
|
+
this.renewalQueue = [];
|
|
137
|
+
this.renewing = false;
|
|
138
|
+
|
|
139
|
+
if (err) {
|
|
90
140
|
this.logger.error(
|
|
91
141
|
{
|
|
92
|
-
err
|
|
142
|
+
err,
|
|
93
143
|
tnx: 'OAUTH2',
|
|
94
144
|
user: this.options.user,
|
|
95
145
|
action: 'renew'
|
|
@@ -108,7 +158,8 @@ class XOAuth2 extends Stream {
|
|
|
108
158
|
this.options.user
|
|
109
159
|
);
|
|
110
160
|
}
|
|
111
|
-
|
|
161
|
+
// Complete original request
|
|
162
|
+
callback(err, accessToken);
|
|
112
163
|
};
|
|
113
164
|
|
|
114
165
|
if (this.provisionCallback) {
|
|
@@ -167,7 +218,7 @@ class XOAuth2 extends Stream {
|
|
|
167
218
|
try {
|
|
168
219
|
token = this.jwtSignRS256(tokenData);
|
|
169
220
|
} catch (err) {
|
|
170
|
-
return callback(new Error('
|
|
221
|
+
return callback(new Error("Can't generate token. Check your auth options"));
|
|
171
222
|
}
|
|
172
223
|
|
|
173
224
|
urlOptions = {
|
|
@@ -181,7 +232,7 @@ class XOAuth2 extends Stream {
|
|
|
181
232
|
};
|
|
182
233
|
} else {
|
|
183
234
|
if (!this.options.refreshToken) {
|
|
184
|
-
return callback(new Error('
|
|
235
|
+
return callback(new Error("Can't create new access token for user"));
|
|
185
236
|
}
|
|
186
237
|
|
|
187
238
|
// web app - https://developers.google.com/identity/protocols/OAuth2WebServer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodemailer",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.6",
|
|
4
4
|
"description": "Easy as cake e-mail sending from your Node.js applications",
|
|
5
5
|
"main": "lib/nodemailer.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://nodemailer.com/",
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@aws-sdk/client-sesv2": "3.
|
|
26
|
+
"@aws-sdk/client-sesv2": "3.876.0",
|
|
27
27
|
"bunyan": "1.8.15",
|
|
28
28
|
"c8": "10.1.3",
|
|
29
29
|
"eslint": "8.57.0",
|