nodemailer 4.6.8 → 4.7.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.
package/.prettierrc.js ADDED
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ printWidth: 160,
3
+ tabWidth: 4,
4
+ singleQuote: true
5
+ };
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 4.7.0 2018-11-19
4
+
5
+ - Cleaned up List-\* header generation
6
+ - Fixed 'full' return option for DSN (klaronix) [23b93a3b]
7
+ - Support promises `for mailcomposer.build()`
8
+
3
9
  ## 4.6.8 2018-08-15
4
10
 
5
11
  - Use first IP address from DNS resolution when using a proxy (Limbozz) [d4ca847c]
@@ -87,8 +87,8 @@ class Encoder extends Transform {
87
87
  }
88
88
 
89
89
  if (chunk.length % 3) {
90
- this._remainingBytes = chunk.slice(chunk.length - chunk.length % 3);
91
- chunk = chunk.slice(0, chunk.length - chunk.length % 3);
90
+ this._remainingBytes = chunk.slice(chunk.length - (chunk.length % 3));
91
+ chunk = chunk.slice(0, chunk.length - (chunk.length % 3));
92
92
  } else {
93
93
  this._remainingBytes = false;
94
94
  }
@@ -256,26 +256,45 @@ class MailMessage {
256
256
  // make sure an url looks like <protocol:url>
257
257
  return Object.keys(listData).map(key => ({
258
258
  key: 'list-' + key.toLowerCase().trim(),
259
- value: [].concat(listData[key] || []).map(value => {
260
- if (typeof value === 'string') {
261
- return this._formatListUrl(value);
262
- }
263
- return {
264
- prepared: true,
265
- value: []
266
- .concat(value || [])
267
- .map(value => {
268
- if (typeof value === 'string') {
269
- return this._formatListUrl(value);
259
+ value: [].concat(listData[key] || []).map(value => ({
260
+ prepared: true,
261
+ foldLines: true,
262
+ value: []
263
+ .concat(value || [])
264
+ .map(value => {
265
+ if (typeof value === 'string') {
266
+ value = {
267
+ url: value
268
+ };
269
+ }
270
+
271
+ if (value && value.url) {
272
+ if (key.toLowerCase().trim() === 'id') {
273
+ // List-ID: "comment" <domain>
274
+ let comment = value.comment || '';
275
+ if (mimeFuncs.isPlainText(comment)) {
276
+ comment = '"' + comment + '"';
277
+ } else {
278
+ comment = mimeFuncs.encodeWord(comment);
279
+ }
280
+
281
+ return (value.comment ? comment + ' ' : '') + this._formatListUrl(value.url).replace(/^<[^:]+\/{,2}/, '');
270
282
  }
271
- if (value && value.url) {
272
- return this._formatListUrl(value.url) + (value.comment ? ' (' + value.comment + ')' : '');
283
+
284
+ // List-*: <http://domain> (comment)
285
+ let comment = value.comment || '';
286
+ if (!mimeFuncs.isPlainText(comment)) {
287
+ comment = mimeFuncs.encodeWord(comment);
273
288
  }
274
- return '';
275
- })
276
- .join(', ')
277
- };
278
- })
289
+
290
+ return this._formatListUrl(value.url) + (value.comment ? ' (' + comment + ')' : '');
291
+ }
292
+
293
+ return '';
294
+ })
295
+ .filter(value => value)
296
+ .join(', ')
297
+ }))
279
298
  }));
280
299
  }
281
300
 
@@ -78,7 +78,7 @@ module.exports = {
78
78
  });
79
79
  } else if (mimeWordEncoding === 'B') {
80
80
  encodedStr = typeof data === 'string' ? data : base64.encode(data);
81
- maxLength = maxLength ? Math.max(3, (maxLength - maxLength % 4) / 4 * 3) : 0;
81
+ maxLength = maxLength ? Math.max(3, ((maxLength - (maxLength % 4)) / 4) * 3) : 0;
82
82
  }
83
83
 
84
84
  if (maxLength && (mimeWordEncoding !== 'B' ? encodedStr : base64.encode(data)).length > maxLength) {
@@ -1,4 +1,4 @@
1
- /* eslint no-undefined: 0, prefer-spread: 0 */
1
+ /* eslint no-undefined: 0, prefer-spread: 0, no-control-regex: 0 */
2
2
 
3
3
  'use strict';
4
4
 
@@ -7,6 +7,7 @@ const os = require('os');
7
7
  const fs = require('fs');
8
8
  const punycode = require('punycode');
9
9
  const PassThrough = require('stream').PassThrough;
10
+ const shared = require('../shared');
10
11
 
11
12
  const mimeFuncs = require('../mime-funcs');
12
13
  const qp = require('../qp');
@@ -391,6 +392,14 @@ class MimeNode {
391
392
  }
392
393
 
393
394
  build(callback) {
395
+ let promise;
396
+
397
+ if (!callback && typeof Promise === 'function') {
398
+ promise = new Promise((resolve, reject) => {
399
+ callback = shared.callbackPromise(resolve, reject);
400
+ });
401
+ }
402
+
394
403
  let stream = this.createReadStream();
395
404
  let buf = [];
396
405
  let buflen = 0;
@@ -426,6 +435,8 @@ class MimeNode {
426
435
  }
427
436
  return callback(null, Buffer.concat(buf, buflen));
428
437
  });
438
+
439
+ return promise;
429
440
  }
430
441
 
431
442
  getTransferEncoding() {
@@ -513,7 +524,11 @@ class MimeNode {
513
524
 
514
525
  if (options.prepared) {
515
526
  // header value is
516
- headers.push(key + ': ' + value);
527
+ if (options.foldLines) {
528
+ headers.push(mimeFuncs.foldLines(key + ': ' + value));
529
+ } else {
530
+ headers.push(key + ': ' + value);
531
+ }
517
532
  return;
518
533
  }
519
534
 
@@ -703,9 +718,12 @@ class MimeNode {
703
718
  if (['quoted-printable', 'base64'].includes(transferEncoding)) {
704
719
  contentStream = new (transferEncoding === 'base64' ? base64 : qp).Encoder(options);
705
720
 
706
- contentStream.pipe(outputStream, {
707
- end: false
708
- });
721
+ contentStream.pipe(
722
+ outputStream,
723
+ {
724
+ end: false
725
+ }
726
+ );
709
727
  contentStream.once('end', finalize);
710
728
  contentStream.once('error', err => callback(err));
711
729
 
@@ -714,9 +732,12 @@ class MimeNode {
714
732
  } else {
715
733
  // anything that is not QP or Base54 passes as-is
716
734
  localStream = this._getStream(this.content);
717
- localStream.pipe(outputStream, {
718
- end: false
719
- });
735
+ localStream.pipe(
736
+ outputStream,
737
+ {
738
+ end: false
739
+ }
740
+ );
720
741
  localStream.once('end', finalize);
721
742
  }
722
743
 
@@ -773,9 +794,12 @@ class MimeNode {
773
794
  }
774
795
 
775
796
  let raw = this._getStream(this._raw);
776
- raw.pipe(outputStream, {
777
- end: false
778
- });
797
+ raw.pipe(
798
+ outputStream,
799
+ {
800
+ end: false
801
+ }
802
+ );
779
803
  raw.on('error', err => outputStream.emit('error', err));
780
804
  raw.on('end', finalize);
781
805
  });
@@ -57,73 +57,76 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
57
57
  callback(err);
58
58
  };
59
59
 
60
- socket = connect(options, () => {
61
- if (finished) {
62
- return;
63
- }
64
-
65
- let reqHeaders = {
66
- Host: destinationHost + ':' + destinationPort,
67
- Connection: 'close'
68
- };
69
- if (proxy.auth) {
70
- reqHeaders['Proxy-Authorization'] = 'Basic ' + Buffer.from(proxy.auth).toString('base64');
71
- }
72
-
73
- socket.write(
74
- // HTTP method
75
- 'CONNECT ' +
76
- destinationHost +
77
- ':' +
78
- destinationPort +
79
- ' HTTP/1.1\r\n' +
80
- // HTTP request headers
81
- Object.keys(reqHeaders)
82
- .map(key => key + ': ' + reqHeaders[key])
83
- .join('\r\n') +
84
- // End request
85
- '\r\n\r\n'
86
- );
87
-
88
- let headers = '';
89
- let onSocketData = chunk => {
90
- let match;
91
- let remainder;
92
-
60
+ socket = connect(
61
+ options,
62
+ () => {
93
63
  if (finished) {
94
64
  return;
95
65
  }
96
66
 
97
- headers += chunk.toString('binary');
98
- if ((match = headers.match(/\r\n\r\n/))) {
99
- socket.removeListener('data', onSocketData);
67
+ let reqHeaders = {
68
+ Host: destinationHost + ':' + destinationPort,
69
+ Connection: 'close'
70
+ };
71
+ if (proxy.auth) {
72
+ reqHeaders['Proxy-Authorization'] = 'Basic ' + Buffer.from(proxy.auth).toString('base64');
73
+ }
100
74
 
101
- remainder = headers.substr(match.index + match[0].length);
102
- headers = headers.substr(0, match.index);
103
- if (remainder) {
104
- socket.unshift(Buffer.from(remainder, 'binary'));
75
+ socket.write(
76
+ // HTTP method
77
+ 'CONNECT ' +
78
+ destinationHost +
79
+ ':' +
80
+ destinationPort +
81
+ ' HTTP/1.1\r\n' +
82
+ // HTTP request headers
83
+ Object.keys(reqHeaders)
84
+ .map(key => key + ': ' + reqHeaders[key])
85
+ .join('\r\n') +
86
+ // End request
87
+ '\r\n\r\n'
88
+ );
89
+
90
+ let headers = '';
91
+ let onSocketData = chunk => {
92
+ let match;
93
+ let remainder;
94
+
95
+ if (finished) {
96
+ return;
105
97
  }
106
98
 
107
- // proxy connection is now established
108
- finished = true;
99
+ headers += chunk.toString('binary');
100
+ if ((match = headers.match(/\r\n\r\n/))) {
101
+ socket.removeListener('data', onSocketData);
109
102
 
110
- // check response code
111
- match = headers.match(/^HTTP\/\d+\.\d+ (\d+)/i);
112
- if (!match || (match[1] || '').charAt(0) !== '2') {
113
- try {
114
- socket.destroy();
115
- } catch (E) {
116
- // ignore
103
+ remainder = headers.substr(match.index + match[0].length);
104
+ headers = headers.substr(0, match.index);
105
+ if (remainder) {
106
+ socket.unshift(Buffer.from(remainder, 'binary'));
117
107
  }
118
- return callback(new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || '')));
119
- }
120
108
 
121
- socket.removeListener('error', tempSocketErr);
122
- return callback(null, socket);
123
- }
124
- };
125
- socket.on('data', onSocketData);
126
- });
109
+ // proxy connection is now established
110
+ finished = true;
111
+
112
+ // check response code
113
+ match = headers.match(/^HTTP\/\d+\.\d+ (\d+)/i);
114
+ if (!match || (match[1] || '').charAt(0) !== '2') {
115
+ try {
116
+ socket.destroy();
117
+ } catch (E) {
118
+ // ignore
119
+ }
120
+ return callback(new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || '')));
121
+ }
122
+
123
+ socket.removeListener('error', tempSocketErr);
124
+ return callback(null, socket);
125
+ }
126
+ };
127
+ socket.on('data', onSocketData);
128
+ }
129
+ );
127
130
 
128
131
  socket.once('error', tempSocketErr);
129
132
  }
@@ -223,10 +223,14 @@ class SMTPConnection extends EventEmitter {
223
223
  // socket object is set up but not yet connected
224
224
  this._socket = this.options.socket;
225
225
  try {
226
- this._socket.connect(this.port, this.host, () => {
227
- this._socket.setKeepAlive(true);
228
- this._onConnect();
229
- });
226
+ this._socket.connect(
227
+ this.port,
228
+ this.host,
229
+ () => {
230
+ this._socket.setKeepAlive(true);
231
+ this._onConnect();
232
+ }
233
+ );
230
234
  } catch (E) {
231
235
  return setImmediate(() => this._onError(E, 'ECONNECTION', false, 'CONN'));
232
236
  }
@@ -238,20 +242,28 @@ class SMTPConnection extends EventEmitter {
238
242
  });
239
243
  }
240
244
  try {
241
- this._socket = tls.connect(this.port, this.host, opts, () => {
242
- this._socket.setKeepAlive(true);
243
- this._onConnect();
244
- });
245
+ this._socket = tls.connect(
246
+ this.port,
247
+ this.host,
248
+ opts,
249
+ () => {
250
+ this._socket.setKeepAlive(true);
251
+ this._onConnect();
252
+ }
253
+ );
245
254
  } catch (E) {
246
255
  return setImmediate(() => this._onError(E, 'ECONNECTION', false, 'CONN'));
247
256
  }
248
257
  } else {
249
258
  // connect using plaintext
250
259
  try {
251
- this._socket = net.connect(opts, () => {
252
- this._socket.setKeepAlive(true);
253
- this._onConnect();
254
- });
260
+ this._socket = net.connect(
261
+ opts,
262
+ () => {
263
+ this._socket.setKeepAlive(true);
264
+ this._onConnect();
265
+ }
266
+ );
255
267
  } catch (E) {
256
268
  return setImmediate(() => this._onError(E, 'ECONNECTION', false, 'CONN'));
257
269
  }
@@ -578,19 +590,6 @@ class SMTPConnection extends EventEmitter {
578
590
 
579
591
  err = this._formatError(err, type, data, command);
580
592
 
581
- let entry = {
582
- err
583
- };
584
- if (type) {
585
- entry.errorType = type;
586
- }
587
- if (data) {
588
- entry.errorData = data;
589
- }
590
- if (command) {
591
- entry.command = command;
592
- }
593
-
594
593
  this.logger.error(data, err.message);
595
594
 
596
595
  this.emit('error', err);
@@ -703,16 +702,19 @@ class SMTPConnection extends EventEmitter {
703
702
  });
704
703
 
705
704
  this.upgrading = true;
706
- this._socket = tls.connect(opts, () => {
707
- this.secure = true;
708
- this.upgrading = false;
709
- this._socket.on('data', chunk => this._onData(chunk));
705
+ this._socket = tls.connect(
706
+ opts,
707
+ () => {
708
+ this.secure = true;
709
+ this.upgrading = false;
710
+ this._socket.on('data', chunk => this._onData(chunk));
710
711
 
711
- socketPlain.removeAllListeners('close');
712
- socketPlain.removeAllListeners('end');
712
+ socketPlain.removeAllListeners('close');
713
+ socketPlain.removeAllListeners('end');
713
714
 
714
- return callback(null, true);
715
- });
715
+ return callback(null, true);
716
+ }
717
+ );
716
718
 
717
719
  this._socket.on('error', err => this._onError(err, 'ESOCKET', false, 'CONN'));
718
720
  this._socket.once('close', errored => this._onClose(errored));
@@ -897,7 +899,7 @@ class SMTPConnection extends EventEmitter {
897
899
  break;
898
900
  case 'FULL':
899
901
  case 'BODY':
900
- ret = 'full';
902
+ ret = 'FULL';
901
903
  break;
902
904
  }
903
905
  }
@@ -967,9 +969,12 @@ class SMTPConnection extends EventEmitter {
967
969
  });
968
970
  }
969
971
 
970
- dataStream.pipe(this._socket, {
971
- end: false
972
- });
972
+ dataStream.pipe(
973
+ this._socket,
974
+ {
975
+ end: false
976
+ }
977
+ );
973
978
 
974
979
  if (this.options.debug) {
975
980
  logStream = new PassThrough();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "4.6.8",
3
+ "version": "4.7.0",
4
4
  "description": "Easy as cake e-mail sending from your Node.js applications",
5
5
  "main": "lib/nodemailer.js",
6
6
  "scripts": {
@@ -21,10 +21,11 @@
21
21
  "homepage": "https://nodemailer.com/",
22
22
  "devDependencies": {
23
23
  "bunyan": "^1.8.12",
24
- "chai": "^4.1.2",
24
+ "chai": "^4.2.0",
25
25
  "eslint-config-nodemailer": "^1.2.0",
26
+ "eslint-config-prettier": "^3.3.0",
26
27
  "grunt": "^1.0.3",
27
- "grunt-cli": "^1.2.0",
28
+ "grunt-cli": "^1.3.2",
28
29
  "grunt-eslint": "^21.0.0",
29
30
  "grunt-mocha-test": "^0.13.3",
30
31
  "libbase64": "^1.0.3",
@@ -33,8 +34,8 @@
33
34
  "mocha": "^5.2.0",
34
35
  "proxy": "^0.2.4",
35
36
  "proxy-test-server": "^1.0.0",
36
- "sinon": "^6.1.5",
37
- "smtp-server": "^3.4.6"
37
+ "sinon": "^7.1.1",
38
+ "smtp-server": "^3.4.7"
38
39
  },
39
40
  "engines": {
40
41
  "node": ">=6.0.0"