nodemailer 6.6.4 → 6.7.2

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,21 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 6.7.2 2021-11-26
4
+
5
+ - Fix proxies for account verification
6
+
7
+ ## 6.7.1 2021-11-15
8
+
9
+ - fix verify on ses-transport (stanofsky)
10
+
11
+ ## 6.7.0 2021-10-11
12
+
13
+ - Updated DNS resolving logic. If there are multiple responses for a A/AAAA record, then loop these randomly instead of only caching the first one
14
+
15
+ ## 6.6.5 2021-09-23
16
+
17
+ - Replaced Object.values() and Array.flat() with polyfills to allow using Nodemailer in Node v6+
18
+
3
19
  ## 6.6.4 2021-09-22
4
20
 
5
21
  - Better compatibility with IPv6-only SMTP hosts (oxzi)
package/README.md CHANGED
@@ -10,6 +10,8 @@ See [nodemailer.com](https://nodemailer.com/) for documentation and terms.
10
10
 
11
11
  ## Having an issue?
12
12
 
13
+ > Nodemailer supports all Node.js versions starting from Node.js@v6.0.0. Existing test suite does not support such old Node.js versions so all features are not actually tested. From time to time some regression bugs might occur because of this.
14
+
13
15
  #### First review the docs
14
16
 
15
17
  Documentation for Nodemailer can be found at [nodemailer.com](https://nodemailer.com/about/).
@@ -95,6 +95,10 @@ class Mail extends EventEmitter {
95
95
  ['close', 'isIdle', 'verify'].forEach(method => {
96
96
  this[method] = (...args) => {
97
97
  if (typeof this.transporter[method] === 'function') {
98
+ if (method === 'verify' && typeof this.getSocket === 'function') {
99
+ this.transporter.getSocket = this.getSocket;
100
+ this.getSocket = false;
101
+ }
98
102
  return this.transporter[method](...args);
99
103
  } else {
100
104
  this.logger.warn(
@@ -320,18 +320,18 @@ class SESTransport extends EventEmitter {
320
320
  Source: 'invalid@invalid',
321
321
  Destinations: ['invalid@invalid']
322
322
  };
323
- const cb = err => {
324
- if (err && (err.code || err.Code) !== 'InvalidParameterValue') {
325
- return callback(err);
326
- }
327
- return callback(null, true);
328
- };
329
323
 
330
324
  if (!callback) {
331
325
  promise = new Promise((resolve, reject) => {
332
326
  callback = shared.callbackPromise(resolve, reject);
333
327
  });
334
328
  }
329
+ const cb = err => {
330
+ if (err && (err.code || err.Code) !== 'InvalidParameterValue') {
331
+ return callback(err);
332
+ }
333
+ return callback(null, true);
334
+ };
335
335
 
336
336
  if (typeof ses.send === 'function' && aws.SendRawEmailCommand) {
337
337
  // v3 API
@@ -339,7 +339,7 @@ class SESTransport extends EventEmitter {
339
339
  ses.send(new aws.SendRawEmailCommand(sesMessage), cb);
340
340
  } else {
341
341
  // v2 API
342
- ses.sendRawEmail(sesMessage, cb).promise();
342
+ ses.sendRawEmail(sesMessage, cb);
343
343
  }
344
344
 
345
345
  return promise;
@@ -12,12 +12,17 @@ const os = require('os');
12
12
 
13
13
  const DNS_TTL = 5 * 60 * 1000;
14
14
 
15
+ const networkInterfaces = (module.exports.networkInterfaces = os.networkInterfaces());
16
+
15
17
  const resolver = (family, hostname, callback) => {
16
- const familySupported = Object.values(os.networkInterfaces()).
17
- flat().
18
- filter(i => !i.internal).
19
- filter(i => i.family === 'IPv' + family).
20
- length > 0;
18
+ const familySupported =
19
+ // crux that replaces Object.values(networkInterfaces) as Object.values is not supported in nodejs v6
20
+ Object.keys(networkInterfaces)
21
+ .map(key => networkInterfaces[key])
22
+ // crux that replaces .flat() as it is not supported in older Node versions (v10 and older)
23
+ .reduce((acc, val) => acc.concat(val), [])
24
+ .filter(i => !i.internal)
25
+ .filter(i => i.family === 'IPv' + family).length > 0;
21
26
 
22
27
  if (!familySupported) {
23
28
  return callback(null, []);
@@ -41,16 +46,45 @@ const resolver = (family, hostname, callback) => {
41
46
  };
42
47
 
43
48
  const dnsCache = (module.exports.dnsCache = new Map());
49
+
50
+ const formatDNSValue = (value, extra) => {
51
+ if (!value) {
52
+ return Object.assign({}, extra || {});
53
+ }
54
+
55
+ return Object.assign(
56
+ {
57
+ servername: value.servername,
58
+ host:
59
+ !value.addresses || !value.addresses.length
60
+ ? null
61
+ : value.addresses.length === 1
62
+ ? value.addresses[0]
63
+ : value.addresses[Math.floor(Math.random() * value.addresses.length)]
64
+ },
65
+ extra || {}
66
+ );
67
+ };
68
+
44
69
  module.exports.resolveHostname = (options, callback) => {
45
70
  options = options || {};
46
71
 
72
+ if (!options.host && options.servername) {
73
+ options.host = options.servername;
74
+ }
75
+
47
76
  if (!options.host || net.isIP(options.host)) {
48
77
  // nothing to do here
49
78
  let value = {
50
- host: options.host,
79
+ addresses: [options.host],
51
80
  servername: options.servername || false
52
81
  };
53
- return callback(null, value);
82
+ return callback(
83
+ null,
84
+ formatDNSValue(value, {
85
+ cached: false
86
+ })
87
+ );
54
88
  }
55
89
 
56
90
  let cached;
@@ -58,11 +92,12 @@ module.exports.resolveHostname = (options, callback) => {
58
92
  if (dnsCache.has(options.host)) {
59
93
  cached = dnsCache.get(options.host);
60
94
  if (!cached.expires || cached.expires >= Date.now()) {
61
- return callback(null, {
62
- host: cached.value.host,
63
- servername: cached.value.servername,
64
- _cached: true
65
- });
95
+ return callback(
96
+ null,
97
+ formatDNSValue(cached.value, {
98
+ cached: true
99
+ })
100
+ );
66
101
  }
67
102
  }
68
103
 
@@ -70,40 +105,68 @@ module.exports.resolveHostname = (options, callback) => {
70
105
  if (err) {
71
106
  if (cached) {
72
107
  // ignore error, use expired value
73
- return callback(null, cached.value);
108
+ return callback(
109
+ null,
110
+ formatDNSValue(cached.value, {
111
+ cached: true,
112
+ error: err
113
+ })
114
+ );
74
115
  }
75
116
  return callback(err);
76
117
  }
118
+
77
119
  if (addresses && addresses.length) {
78
120
  let value = {
79
- host: addresses[0] || options.host,
121
+ addresses,
80
122
  servername: options.servername || options.host
81
123
  };
124
+
82
125
  dnsCache.set(options.host, {
83
126
  value,
84
127
  expires: Date.now() + DNS_TTL
85
128
  });
86
- return callback(null, value);
129
+
130
+ return callback(
131
+ null,
132
+ formatDNSValue(value, {
133
+ cached: false
134
+ })
135
+ );
87
136
  }
88
137
 
89
138
  resolver(6, options.host, (err, addresses) => {
90
139
  if (err) {
91
140
  if (cached) {
92
141
  // ignore error, use expired value
93
- return callback(null, cached.value);
142
+ return callback(
143
+ null,
144
+ formatDNSValue(cached.value, {
145
+ cached: true,
146
+ error: err
147
+ })
148
+ );
94
149
  }
95
150
  return callback(err);
96
151
  }
152
+
97
153
  if (addresses && addresses.length) {
98
154
  let value = {
99
- host: addresses[0] || options.host,
155
+ addresses,
100
156
  servername: options.servername || options.host
101
157
  };
158
+
102
159
  dnsCache.set(options.host, {
103
160
  value,
104
161
  expires: Date.now() + DNS_TTL
105
162
  });
106
- return callback(null, value);
163
+
164
+ return callback(
165
+ null,
166
+ formatDNSValue(value, {
167
+ cached: false
168
+ })
169
+ );
107
170
  }
108
171
 
109
172
  try {
@@ -111,30 +174,54 @@ module.exports.resolveHostname = (options, callback) => {
111
174
  if (err) {
112
175
  if (cached) {
113
176
  // ignore error, use expired value
114
- return callback(null, cached.value);
177
+ return callback(
178
+ null,
179
+ formatDNSValue(cached.value, {
180
+ cached: true,
181
+ error: err
182
+ })
183
+ );
115
184
  }
116
185
  return callback(err);
117
186
  }
118
187
 
119
188
  if (!address && cached) {
120
189
  // nothing was found, fallback to cached value
121
- return callback(null, cached.value);
190
+ return callback(
191
+ null,
192
+ formatDNSValue(cached.value, {
193
+ cached: true
194
+ })
195
+ );
122
196
  }
123
197
 
124
198
  let value = {
125
- host: address || options.host,
199
+ addresses: address ? [address] : [options.host],
126
200
  servername: options.servername || options.host
127
201
  };
202
+
128
203
  dnsCache.set(options.host, {
129
204
  value,
130
205
  expires: Date.now() + DNS_TTL
131
206
  });
132
- return callback(null, value);
207
+
208
+ return callback(
209
+ null,
210
+ formatDNSValue(value, {
211
+ cached: false
212
+ })
213
+ );
133
214
  });
134
215
  } catch (err) {
135
216
  if (cached) {
136
217
  // ignore error, use expired value
137
- return callback(null, cached.value);
218
+ return callback(
219
+ null,
220
+ formatDNSValue(cached.value, {
221
+ cached: true,
222
+ error: err
223
+ })
224
+ );
138
225
  }
139
226
  return callback(err);
140
227
  }
@@ -261,12 +261,12 @@ class SMTPConnection extends EventEmitter {
261
261
  tnx: 'dns',
262
262
  source: opts.host,
263
263
  resolved: resolved.host,
264
- cached: !!resolved._cached
264
+ cached: !!resolved.cached
265
265
  },
266
266
  'Resolved %s as %s [cache %s]',
267
267
  opts.host,
268
268
  resolved.host,
269
- resolved._cached ? 'hit' : 'miss'
269
+ resolved.cached ? 'hit' : 'miss'
270
270
  );
271
271
  Object.keys(resolved).forEach(key => {
272
272
  if (key.charAt(0) !== '_' && resolved[key]) {
@@ -299,12 +299,12 @@ class SMTPConnection extends EventEmitter {
299
299
  tnx: 'dns',
300
300
  source: opts.host,
301
301
  resolved: resolved.host,
302
- cached: !!resolved._cached
302
+ cached: !!resolved.cached
303
303
  },
304
304
  'Resolved %s as %s [cache %s]',
305
305
  opts.host,
306
306
  resolved.host,
307
- resolved._cached ? 'hit' : 'miss'
307
+ resolved.cached ? 'hit' : 'miss'
308
308
  );
309
309
  Object.keys(resolved).forEach(key => {
310
310
  if (key.charAt(0) !== '_' && resolved[key]) {
@@ -332,12 +332,12 @@ class SMTPConnection extends EventEmitter {
332
332
  tnx: 'dns',
333
333
  source: opts.host,
334
334
  resolved: resolved.host,
335
- cached: !!resolved._cached
335
+ cached: !!resolved.cached
336
336
  },
337
337
  'Resolved %s as %s [cache %s]',
338
338
  opts.host,
339
339
  resolved.host,
340
- resolved._cached ? 'hit' : 'miss'
340
+ resolved.cached ? 'hit' : 'miss'
341
341
  );
342
342
  Object.keys(resolved).forEach(key => {
343
343
  if (key.charAt(0) !== '_' && resolved[key]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "6.6.4",
3
+ "version": "6.7.2",
4
4
  "description": "Easy as cake e-mail sending from your Node.js applications",
5
5
  "main": "lib/nodemailer.js",
6
6
  "scripts": {
@@ -20,24 +20,24 @@
20
20
  },
21
21
  "homepage": "https://nodemailer.com/",
22
22
  "devDependencies": {
23
- "@aws-sdk/client-ses": "3.33.0",
24
- "aws-sdk": "2.993.0",
23
+ "@aws-sdk/client-ses": "3.41.0",
24
+ "aws-sdk": "2.1028.0",
25
25
  "bunyan": "1.8.15",
26
26
  "chai": "4.3.4",
27
27
  "eslint-config-nodemailer": "1.2.0",
28
28
  "eslint-config-prettier": "8.3.0",
29
29
  "grunt": "1.4.1",
30
30
  "grunt-cli": "1.4.3",
31
- "grunt-eslint": "23.0.0",
31
+ "grunt-eslint": "24.0.0",
32
32
  "grunt-mocha-test": "0.13.3",
33
33
  "libbase64": "1.2.1",
34
34
  "libmime": "5.0.0",
35
35
  "libqp": "1.1.0",
36
- "mocha": "9.1.1",
36
+ "mocha": "9.1.3",
37
37
  "nodemailer-ntlm-auth": "1.0.1",
38
38
  "proxy": "1.0.2",
39
39
  "proxy-test-server": "1.0.0",
40
- "sinon": "11.1.2",
40
+ "sinon": "12.0.1",
41
41
  "smtp-server": "3.9.0"
42
42
  },
43
43
  "engines": {