nodemailer 6.4.13 → 6.4.17
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 +17 -1
- package/lib/dkim/message-parser.js +1 -4
- package/lib/fetch/cookies.js +1 -4
- package/lib/fetch/index.js +3 -11
- package/lib/mail-composer/index.js +2 -3
- package/lib/mailer/mail-message.js +1 -6
- package/lib/mime-funcs/mime-types.js +2 -9
- package/lib/mime-node/index.js +1 -1
- package/lib/nodemailer.js +4 -9
- package/lib/sendmail-transport/index.js +8 -0
- package/lib/ses-transport/index.js +1 -1
- package/lib/shared/index.js +3 -11
- package/lib/smtp-connection/http-proxy-client.js +1 -1
- package/lib/smtp-connection/index.js +4 -14
- package/lib/well-known/index.js +1 -1
- package/lib/well-known/services.json +6 -0
- package/lib/xoauth2/index.js +4 -4
- package/package.json +6 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 6.4.17 2020-12-11
|
|
4
|
+
|
|
5
|
+
- Allow mixing attachments with caendar alternatives
|
|
6
|
+
|
|
7
|
+
## 6.4.16 2020-11-12
|
|
8
|
+
|
|
9
|
+
- Applied updated prettier formating rules
|
|
10
|
+
|
|
11
|
+
## 6.4.15 2020-11-06
|
|
12
|
+
|
|
13
|
+
- Minor changes in header key casing
|
|
14
|
+
|
|
15
|
+
## 6.4.14 2020-10-14
|
|
16
|
+
|
|
17
|
+
- Disabled postinstall script
|
|
18
|
+
|
|
3
19
|
## 6.4.13 2020-10-02
|
|
4
20
|
|
|
5
21
|
- Fix normalizeHeaderKey method for single node messages
|
|
6
22
|
|
|
7
23
|
## 6.4.12 2020-09-30
|
|
8
24
|
|
|
9
|
-
- Better handling of
|
|
25
|
+
- Better handling of attachment filenames that include quote symbols
|
|
10
26
|
- Includes all information from the oath2 error response in the error message (Normal Gaussian) [1787f227]
|
|
11
27
|
|
|
12
28
|
## 6.4.11 2020-07-29
|
|
@@ -146,10 +146,7 @@ class MessageParser extends Transform {
|
|
|
146
146
|
return lines
|
|
147
147
|
.filter(line => line.trim())
|
|
148
148
|
.map(line => ({
|
|
149
|
-
key: line
|
|
150
|
-
.substr(0, line.indexOf(':'))
|
|
151
|
-
.trim()
|
|
152
|
-
.toLowerCase(),
|
|
149
|
+
key: line.substr(0, line.indexOf(':')).trim().toLowerCase(),
|
|
153
150
|
line
|
|
154
151
|
}));
|
|
155
152
|
}
|
package/lib/fetch/cookies.js
CHANGED
|
@@ -110,10 +110,7 @@ class Cookies {
|
|
|
110
110
|
.split(';')
|
|
111
111
|
.forEach(cookiePart => {
|
|
112
112
|
let valueParts = cookiePart.split('=');
|
|
113
|
-
let key = valueParts
|
|
114
|
-
.shift()
|
|
115
|
-
.trim()
|
|
116
|
-
.toLowerCase();
|
|
113
|
+
let key = valueParts.shift().trim().toLowerCase();
|
|
117
114
|
let value = valueParts.join('=').trim();
|
|
118
115
|
let domain;
|
|
119
116
|
|
package/lib/fetch/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const packageData = require('../../package.json');
|
|
|
10
10
|
|
|
11
11
|
const MAX_REDIRECTS = 5;
|
|
12
12
|
|
|
13
|
-
module.exports = function(url, options) {
|
|
13
|
+
module.exports = function (url, options) {
|
|
14
14
|
return fetch(url, options);
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -33,11 +33,7 @@ function fetch(url, options) {
|
|
|
33
33
|
|
|
34
34
|
let fetchRes = options.fetchRes;
|
|
35
35
|
let parsed = urllib.parse(url);
|
|
36
|
-
let method =
|
|
37
|
-
(options.method || '')
|
|
38
|
-
.toString()
|
|
39
|
-
.trim()
|
|
40
|
-
.toUpperCase() || 'GET';
|
|
36
|
+
let method = (options.method || '').toString().trim().toUpperCase() || 'GET';
|
|
41
37
|
let finished = false;
|
|
42
38
|
let cookies;
|
|
43
39
|
let body;
|
|
@@ -115,11 +111,7 @@ function fetch(url, options) {
|
|
|
115
111
|
headers['Content-Length'] = body.length;
|
|
116
112
|
}
|
|
117
113
|
// if method is not provided, use POST instead of GET
|
|
118
|
-
method =
|
|
119
|
-
(options.method || '')
|
|
120
|
-
.toString()
|
|
121
|
-
.trim()
|
|
122
|
-
.toUpperCase() || 'POST';
|
|
114
|
+
method = (options.method || '').toString().trim().toUpperCase() || 'POST';
|
|
123
115
|
}
|
|
124
116
|
|
|
125
117
|
let req;
|
|
@@ -230,9 +230,8 @@ class MailComposer {
|
|
|
230
230
|
amp.contentType = 'text/x-amp-html; charset=utf-8';
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
if (this.mail.icalEvent && !(this.mail.attachments && this.mail.attachments.length)) {
|
|
233
|
+
// NB! when including attachments with a calendar alternative you might end up in a blank screen on some clients
|
|
234
|
+
if (this.mail.icalEvent) {
|
|
236
235
|
if (
|
|
237
236
|
typeof this.mail.icalEvent === 'object' &&
|
|
238
237
|
(this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
|
|
@@ -64,12 +64,7 @@ class MailMessage {
|
|
|
64
64
|
if (this.data.attachments && this.data.attachments.length) {
|
|
65
65
|
this.data.attachments.forEach((attachment, i) => {
|
|
66
66
|
if (!attachment.filename) {
|
|
67
|
-
attachment.filename =
|
|
68
|
-
(attachment.path || attachment.href || '')
|
|
69
|
-
.split('/')
|
|
70
|
-
.pop()
|
|
71
|
-
.split('?')
|
|
72
|
-
.shift() || 'attachment-' + (i + 1);
|
|
67
|
+
attachment.filename = (attachment.path || attachment.href || '').split('/').pop().split('?').shift() || 'attachment-' + (i + 1);
|
|
73
68
|
if (attachment.filename.indexOf('.') < 0) {
|
|
74
69
|
attachment.filename += '.' + mimeFuncs.detectExtension(attachment.contentType);
|
|
75
70
|
}
|
|
@@ -2063,11 +2063,7 @@ module.exports = {
|
|
|
2063
2063
|
}
|
|
2064
2064
|
|
|
2065
2065
|
let parsed = path.parse(filename);
|
|
2066
|
-
let extension = (parsed.ext.substr(1) || parsed.name || '')
|
|
2067
|
-
.split('?')
|
|
2068
|
-
.shift()
|
|
2069
|
-
.trim()
|
|
2070
|
-
.toLowerCase();
|
|
2066
|
+
let extension = (parsed.ext.substr(1) || parsed.name || '').split('?').shift().trim().toLowerCase();
|
|
2071
2067
|
let value = defaultMimeType;
|
|
2072
2068
|
|
|
2073
2069
|
if (extensions.has(extension)) {
|
|
@@ -2084,10 +2080,7 @@ module.exports = {
|
|
|
2084
2080
|
if (!mimeType) {
|
|
2085
2081
|
return defaultExtension;
|
|
2086
2082
|
}
|
|
2087
|
-
let parts = (mimeType || '')
|
|
2088
|
-
.toLowerCase()
|
|
2089
|
-
.trim()
|
|
2090
|
-
.split('/');
|
|
2083
|
+
let parts = (mimeType || '').toLowerCase().trim().split('/');
|
|
2091
2084
|
let rootType = parts.shift().trim();
|
|
2092
2085
|
let subType = parts.join('/').trim();
|
|
2093
2086
|
|
package/lib/mime-node/index.js
CHANGED
|
@@ -999,7 +999,7 @@ class MimeNode {
|
|
|
999
999
|
.trim()
|
|
1000
1000
|
.toLowerCase()
|
|
1001
1001
|
// use uppercase words, except MIME
|
|
1002
|
-
.replace(/^X-SMTPAPI$|^(MIME|DKIM)\b|^[a-z]|-(SPF|FBL|ID|MD5)$|-[a-z]/gi, c => c.toUpperCase())
|
|
1002
|
+
.replace(/^X-SMTPAPI$|^(MIME|DKIM|ARC|BIMI)\b|^[a-z]|-(SPF|FBL|ID|MD5)$|-[a-z]/gi, c => c.toUpperCase())
|
|
1003
1003
|
// special case
|
|
1004
1004
|
.replace(/^Content-Features$/i, 'Content-features');
|
|
1005
1005
|
|
package/lib/nodemailer.js
CHANGED
|
@@ -13,16 +13,11 @@ const packageData = require('../package.json');
|
|
|
13
13
|
|
|
14
14
|
const ETHEREAL_API = (process.env.ETHEREAL_API || 'https://api.nodemailer.com').replace(/\/+$/, '');
|
|
15
15
|
const ETHEREAL_WEB = (process.env.ETHEREAL_WEB || 'https://ethereal.email').replace(/\/+$/, '');
|
|
16
|
-
const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes(
|
|
17
|
-
(process.env.ETHEREAL_CACHE || 'yes')
|
|
18
|
-
.toString()
|
|
19
|
-
.trim()
|
|
20
|
-
.toLowerCase()
|
|
21
|
-
);
|
|
16
|
+
const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes((process.env.ETHEREAL_CACHE || 'yes').toString().trim().toLowerCase());
|
|
22
17
|
|
|
23
18
|
let testAccount = false;
|
|
24
19
|
|
|
25
|
-
module.exports.createTransport = function(transporter, defaults) {
|
|
20
|
+
module.exports.createTransport = function (transporter, defaults) {
|
|
26
21
|
let urlConfig;
|
|
27
22
|
let options;
|
|
28
23
|
let mailer;
|
|
@@ -60,7 +55,7 @@ module.exports.createTransport = function(transporter, defaults) {
|
|
|
60
55
|
return mailer;
|
|
61
56
|
};
|
|
62
57
|
|
|
63
|
-
module.exports.createTestAccount = function(apiUrl, callback) {
|
|
58
|
+
module.exports.createTestAccount = function (apiUrl, callback) {
|
|
64
59
|
let promise;
|
|
65
60
|
|
|
66
61
|
if (!callback && typeof apiUrl === 'function') {
|
|
@@ -128,7 +123,7 @@ module.exports.createTestAccount = function(apiUrl, callback) {
|
|
|
128
123
|
return promise;
|
|
129
124
|
};
|
|
130
125
|
|
|
131
|
-
module.exports.getTestMessageUrl = function(info) {
|
|
126
|
+
module.exports.getTestMessageUrl = function (info) {
|
|
132
127
|
if (!info || !info.response) {
|
|
133
128
|
return false;
|
|
134
129
|
}
|
|
@@ -70,6 +70,14 @@ class SendmailTransport {
|
|
|
70
70
|
let returned;
|
|
71
71
|
let transform;
|
|
72
72
|
|
|
73
|
+
const hasInvalidAddresses = []
|
|
74
|
+
.concat(envelope.from || [])
|
|
75
|
+
.concat(envelope.to || [])
|
|
76
|
+
.some(addr => /^-/.test(addr));
|
|
77
|
+
if (hasInvalidAddresses) {
|
|
78
|
+
return done(new Error('Can not send mail. Invalid envelope addresses.'));
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
if (this.args) {
|
|
74
82
|
// force -i to keep single dots
|
|
75
83
|
args = ['-i'].concat(this.args).concat(envelope.to);
|
|
@@ -38,7 +38,7 @@ class SESTransport extends EventEmitter {
|
|
|
38
38
|
// max messages per second
|
|
39
39
|
this.sendingRate = Number(this.options.sendingRate) || Infinity;
|
|
40
40
|
this.sendingRateTTL = null;
|
|
41
|
-
this.rateInterval = 1000;
|
|
41
|
+
this.rateInterval = 1000; // milliseconds
|
|
42
42
|
this.rateMessages = [];
|
|
43
43
|
|
|
44
44
|
this.pending = [];
|
package/lib/shared/index.js
CHANGED
|
@@ -276,7 +276,7 @@ module.exports.getLogger = (options, defaults) => {
|
|
|
276
276
|
* @param {Function} reject Function to run if callback ends with an error
|
|
277
277
|
*/
|
|
278
278
|
module.exports.callbackPromise = (resolve, reject) =>
|
|
279
|
-
function() {
|
|
279
|
+
function () {
|
|
280
280
|
let args = Array.from(arguments);
|
|
281
281
|
let err = args.shift();
|
|
282
282
|
if (err) {
|
|
@@ -357,7 +357,7 @@ module.exports.resolveContent = (data, key, callback) => {
|
|
|
357
357
|
/**
|
|
358
358
|
* Copies properties from source objects to target objects
|
|
359
359
|
*/
|
|
360
|
-
module.exports.assign = function(/* target, ... sources */) {
|
|
360
|
+
module.exports.assign = function (/* target, ... sources */) {
|
|
361
361
|
let args = Array.from(arguments);
|
|
362
362
|
let target = args.shift() || {};
|
|
363
363
|
|
|
@@ -489,15 +489,7 @@ function createDefaultLogger(levels) {
|
|
|
489
489
|
|
|
490
490
|
message = util.format(message, ...args);
|
|
491
491
|
message.split(/\r?\n/).forEach(line => {
|
|
492
|
-
console.log(
|
|
493
|
-
'[%s] %s %s',
|
|
494
|
-
new Date()
|
|
495
|
-
.toISOString()
|
|
496
|
-
.substr(0, 19)
|
|
497
|
-
.replace(/T/, ' '),
|
|
498
|
-
levelNames.get(level),
|
|
499
|
-
prefix + line
|
|
500
|
-
);
|
|
492
|
+
console.log('[%s] %s %s', new Date().toISOString().substr(0, 19).replace(/T/, ' '), levelNames.get(level), prefix + line);
|
|
501
493
|
});
|
|
502
494
|
};
|
|
503
495
|
|
|
@@ -44,7 +44,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
|
|
|
44
44
|
// Error harness for initial connection. Once connection is established, the responsibility
|
|
45
45
|
// to handle errors is passed to whoever uses this socket
|
|
46
46
|
let finished = false;
|
|
47
|
-
let tempSocketErr = function(err) {
|
|
47
|
+
let tempSocketErr = function (err) {
|
|
48
48
|
if (finished) {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
@@ -45,10 +45,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
45
45
|
constructor(options) {
|
|
46
46
|
super(options);
|
|
47
47
|
|
|
48
|
-
this.id = crypto
|
|
49
|
-
.randomBytes(8)
|
|
50
|
-
.toString('base64')
|
|
51
|
-
.replace(/\W/g, '');
|
|
48
|
+
this.id = crypto.randomBytes(8).toString('base64').replace(/\W/g, '');
|
|
52
49
|
this.stage = 'init';
|
|
53
50
|
|
|
54
51
|
this.options = options || {};
|
|
@@ -73,10 +70,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
73
70
|
|
|
74
71
|
this.customAuth = new Map();
|
|
75
72
|
Object.keys(this.options.customAuth || {}).forEach(key => {
|
|
76
|
-
let mapKey = (key || '')
|
|
77
|
-
.toString()
|
|
78
|
-
.trim()
|
|
79
|
-
.toUpperCase();
|
|
73
|
+
let mapKey = (key || '').toString().trim().toUpperCase();
|
|
80
74
|
if (!mapKey) {
|
|
81
75
|
return;
|
|
82
76
|
}
|
|
@@ -424,11 +418,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
424
418
|
|
|
425
419
|
this._auth = authData || {};
|
|
426
420
|
// Select SASL authentication method
|
|
427
|
-
this._authMethod =
|
|
428
|
-
(this._auth.method || '')
|
|
429
|
-
.toString()
|
|
430
|
-
.trim()
|
|
431
|
-
.toUpperCase() || false;
|
|
421
|
+
this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false;
|
|
432
422
|
|
|
433
423
|
if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) {
|
|
434
424
|
this._authMethod = 'XOAUTH2';
|
|
@@ -598,7 +588,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
598
588
|
|
|
599
589
|
// ensure that callback is only called once
|
|
600
590
|
let returned = false;
|
|
601
|
-
let callback = function() {
|
|
591
|
+
let callback = function () {
|
|
602
592
|
if (returned) {
|
|
603
593
|
return;
|
|
604
594
|
}
|
package/lib/well-known/index.js
CHANGED
|
@@ -41,7 +41,7 @@ function normalizeService(service) {
|
|
|
41
41
|
* @param {String} key [description]
|
|
42
42
|
* @returns {Object} SMTP config or false if not found
|
|
43
43
|
*/
|
|
44
|
-
module.exports = function(key) {
|
|
44
|
+
module.exports = function (key) {
|
|
45
45
|
key = normalizeKey(key.split('@').pop());
|
|
46
46
|
return normalized[key] || false;
|
|
47
47
|
};
|
package/lib/xoauth2/index.js
CHANGED
|
@@ -263,11 +263,11 @@ class XOAuth2 extends Stream {
|
|
|
263
263
|
if (data.error) {
|
|
264
264
|
// Error Response : https://tools.ietf.org/html/rfc6749#section-5.2
|
|
265
265
|
let errorMessage = data.error;
|
|
266
|
-
if(data.error_description) {
|
|
267
|
-
|
|
266
|
+
if (data.error_description) {
|
|
267
|
+
errorMessage += ': ' + data.error_description;
|
|
268
268
|
}
|
|
269
|
-
if(data.error_uri) {
|
|
270
|
-
|
|
269
|
+
if (data.error_uri) {
|
|
270
|
+
errorMessage += ' (' + data.error_uri + ')';
|
|
271
271
|
}
|
|
272
272
|
return callback(new Error(errorMessage));
|
|
273
273
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodemailer",
|
|
3
|
-
"version": "6.4.
|
|
3
|
+
"version": "6.4.17",
|
|
4
4
|
"description": "Easy as cake e-mail sending from your Node.js applications",
|
|
5
5
|
"main": "lib/nodemailer.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "grunt"
|
|
8
|
-
"postinstall": "node -e \"try{require('./postinstall')}catch(e){}\""
|
|
7
|
+
"test": "grunt"
|
|
9
8
|
},
|
|
10
9
|
"repository": {
|
|
11
10
|
"type": "git",
|
|
@@ -24,7 +23,7 @@
|
|
|
24
23
|
"bunyan": "1.8.14",
|
|
25
24
|
"chai": "4.2.0",
|
|
26
25
|
"eslint-config-nodemailer": "1.2.0",
|
|
27
|
-
"eslint-config-prettier": "
|
|
26
|
+
"eslint-config-prettier": "7.0.0",
|
|
28
27
|
"grunt": "1.3.0",
|
|
29
28
|
"grunt-cli": "1.3.2",
|
|
30
29
|
"grunt-eslint": "23.0.0",
|
|
@@ -32,12 +31,12 @@
|
|
|
32
31
|
"libbase64": "1.2.1",
|
|
33
32
|
"libmime": "5.0.0",
|
|
34
33
|
"libqp": "1.1.0",
|
|
35
|
-
"mocha": "8.1
|
|
34
|
+
"mocha": "8.2.1",
|
|
36
35
|
"nodemailer-ntlm-auth": "1.0.1",
|
|
37
36
|
"proxy": "1.0.2",
|
|
38
37
|
"proxy-test-server": "1.0.0",
|
|
39
|
-
"sinon": "9.1
|
|
40
|
-
"smtp-server": "3.
|
|
38
|
+
"sinon": "9.2.1",
|
|
39
|
+
"smtp-server": "3.8.0"
|
|
41
40
|
},
|
|
42
41
|
"engines": {
|
|
43
42
|
"node": ">=6.0.0"
|