Haraka 2.8.28 → 3.0.1

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 (135) hide show
  1. package/.eslintrc.yaml +2 -10
  2. package/Changes.md +84 -2
  3. package/Dockerfile +1 -1
  4. package/Plugins.md +9 -4
  5. package/README.md +2 -6
  6. package/bin/haraka +5 -4
  7. package/config/outbound.ini +0 -7
  8. package/config/plugins +1 -1
  9. package/config/smtp.ini +1 -1
  10. package/config/smtp_forward.ini +2 -8
  11. package/config/smtp_proxy.ini +0 -6
  12. package/connection.js +178 -204
  13. package/coverage/lcov.info +13863 -0
  14. package/coverage/tmp/coverage-42958-1658373250585-0.json +1 -0
  15. package/coverage/tmp/coverage-42961-1658373250529-0.json +1 -0
  16. package/dkim.js +66 -73
  17. package/docs/Body.md +1 -22
  18. package/docs/CoreConfig.md +2 -2
  19. package/docs/Header.md +1 -47
  20. package/docs/Outbound.md +8 -36
  21. package/endpoint.js +1 -1
  22. package/haraka.js +1 -1
  23. package/host_pool.js +8 -12
  24. package/logger.js +25 -32
  25. package/outbound/client_pool.js +11 -153
  26. package/outbound/config.js +5 -11
  27. package/outbound/hmail.js +109 -143
  28. package/outbound/index.js +13 -25
  29. package/outbound/mx_lookup.js +10 -7
  30. package/outbound/queue.js +8 -12
  31. package/outbound/timer_queue.js +2 -4
  32. package/outbound/tls.js +17 -18
  33. package/outbound/todo.js +1 -0
  34. package/package.json +57 -55
  35. package/plugins/auth/auth_base.js +39 -63
  36. package/plugins/auth/auth_bridge.js +3 -4
  37. package/plugins/auth/auth_proxy.js +16 -16
  38. package/plugins/auth/auth_vpopmaild.js +30 -37
  39. package/plugins/auth/flat_file.js +9 -13
  40. package/plugins/avg.js +9 -11
  41. package/plugins/backscatterer.js +1 -1
  42. package/plugins/block_me.js +2 -6
  43. package/plugins/bounce.js +106 -124
  44. package/plugins/clamd.js +59 -63
  45. package/plugins/data.signatures.js +6 -6
  46. package/plugins/data.uribl.js +1 -415
  47. package/plugins/delay_deny.js +19 -20
  48. package/plugins/dkim_sign.js +56 -62
  49. package/plugins/dkim_verify.js +9 -8
  50. package/plugins/dns_list_base.js +43 -42
  51. package/plugins/dnsbl.js +41 -46
  52. package/plugins/dnswl.js +23 -26
  53. package/plugins/early_talker.js +24 -28
  54. package/plugins/esets.js +8 -11
  55. package/plugins/greylist.js +161 -190
  56. package/plugins/helo.checks.js +175 -197
  57. package/plugins/mail_from.is_resolvable.js +38 -38
  58. package/plugins/messagesniffer.js +33 -40
  59. package/plugins/prevent_credential_leaks.js +7 -5
  60. package/plugins/process_title.js +16 -17
  61. package/plugins/queue/deliver.js +2 -2
  62. package/plugins/queue/lmtp.js +5 -6
  63. package/plugins/queue/qmail-queue.js +11 -13
  64. package/plugins/queue/quarantine.js +25 -34
  65. package/plugins/queue/rabbitmq.js +3 -2
  66. package/plugins/queue/rabbitmq_amqplib.js +9 -9
  67. package/plugins/queue/smtp_bridge.js +5 -4
  68. package/plugins/queue/smtp_forward.js +81 -89
  69. package/plugins/queue/smtp_proxy.js +21 -22
  70. package/plugins/queue/test.js +2 -1
  71. package/plugins/rcpt_to.host_list_base.js +20 -30
  72. package/plugins/rcpt_to.in_host_list.js +12 -14
  73. package/plugins/rcpt_to.max_count.js +7 -5
  74. package/plugins/record_envelope_addresses.js +4 -6
  75. package/plugins/relay.js +64 -74
  76. package/plugins/reseed_rng.js +1 -2
  77. package/plugins/spamassassin.js +56 -68
  78. package/plugins/status.js +2 -3
  79. package/plugins/tarpit.js +8 -11
  80. package/plugins/tls.js +14 -17
  81. package/plugins/toobusy.js +6 -8
  82. package/plugins/xclient.js +14 -25
  83. package/plugins.js +24 -29
  84. package/rfc1869.js +2 -2
  85. package/server.js +3 -13
  86. package/smtp_client.js +138 -215
  87. package/tests/config/smtp_forward.ini +0 -6
  88. package/tests/fixtures/line_socket.js +1 -1
  89. package/tests/fixtures/util_hmailitem.js +5 -7
  90. package/tests/fixtures/vm_harness.js +2 -2
  91. package/tests/host_pool.js +13 -14
  92. package/tests/installation/plugins/inherits.js +1 -2
  93. package/tests/logger.js +2 -2
  94. package/tests/plugins/bounce.js +6 -8
  95. package/tests/plugins/dkim_signer.js +7 -7
  96. package/tests/plugins/dns_list_base.js +7 -7
  97. package/tests/plugins/helo.checks.js +1 -1
  98. package/tests/plugins/mail_from.is_resolvable.js +10 -54
  99. package/tests/plugins/queue/smtp_forward.js +11 -11
  100. package/tests/plugins/rcpt_to.host_list_base.js +1 -1
  101. package/tests/plugins/rcpt_to.in_host_list.js +1 -1
  102. package/tests/plugins/spamassassin.js +1 -1
  103. package/tests/queue/multibyte +0 -0
  104. package/tests/queue/plain +0 -0
  105. package/tests/rfc1869.js +4 -1
  106. package/tests/server.js +15 -9
  107. package/tests/smtp_client/auth.js +4 -14
  108. package/tests/smtp_client/basic.js +5 -15
  109. package/tests/smtp_client.js +7 -3
  110. package/tests/transaction.js +72 -19
  111. package/tls_socket.js +75 -85
  112. package/transaction.js +7 -9
  113. package/attachment_stream.js +0 -118
  114. package/bin/spf +0 -48
  115. package/chunkemitter.js +0 -75
  116. package/config/data.uribl.excludes +0 -202
  117. package/config/data.uribl.ini +0 -37
  118. package/config/spf.ini +0 -1
  119. package/docs/plugins/attachment.md +0 -92
  120. package/docs/plugins/data.uribl.md +0 -120
  121. package/docs/plugins/spf.md +0 -142
  122. package/mailbody.js +0 -502
  123. package/mailheader.js +0 -304
  124. package/messagestream.js +0 -441
  125. package/plugins/aliases.js +0 -120
  126. package/plugins/attachment.js +0 -503
  127. package/plugins/connect.p0f.js +0 -5
  128. package/plugins/spf.js +0 -327
  129. package/spf.js +0 -689
  130. package/tests/mailbody.js +0 -348
  131. package/tests/mailheader.js +0 -138
  132. package/tests/messagestream.js +0 -34
  133. package/tests/plugins/aliases.js +0 -376
  134. package/tests/plugins/spf.js +0 -251
  135. package/tests/spf.js +0 -96
package/outbound/hmail.js CHANGED
@@ -6,17 +6,17 @@ const dns = require('dns');
6
6
  const path = require('path');
7
7
  const net = require('net');
8
8
 
9
- const Address = require('address-rfc2821').Address;
9
+ const { Address } = require('address-rfc2821');
10
10
  const config = require('haraka-config');
11
11
  const constants = require('haraka-constants');
12
12
  const DSN = require('haraka-dsn');
13
+ const message = require('haraka-email-message')
13
14
  const net_utils = require('haraka-net-utils');
14
15
  const Notes = require('haraka-notes');
15
16
  const utils = require('haraka-utils');
16
17
 
17
18
  const logger = require('../logger');
18
19
  const plugins = require('../plugins');
19
- const Header = require('../mailheader').Header;
20
20
 
21
21
  const client_pool = require('./client_pool');
22
22
  const _qfile = require('./qfile');
@@ -48,9 +48,8 @@ class HMailItem extends events.EventEmitter {
48
48
  super();
49
49
 
50
50
  const parts = _qfile.parts(filename);
51
- if (!parts) {
52
- throw new Error(`Bad filename: ${filename}`);
53
- }
51
+ if (!parts) throw new Error(`Bad filename: ${filename}`);
52
+
54
53
  this.path = filePath;
55
54
  this.filename = filename;
56
55
  this.next_process = parts.next_attempt;
@@ -158,14 +157,12 @@ class HMailItem extends events.EventEmitter {
158
157
  if (obc.cfg.disabled) {
159
158
  // try again in 1 second if delivery is disabled
160
159
  this.logdebug("delivery disabled temporarily. Retrying in 1s.");
161
- const hmail = this;
162
- setTimeout(() => { hmail.send(); }, 1000);
160
+ setTimeout(() => { this.send(); }, 1000);
163
161
  return;
164
162
  }
165
163
 
166
164
  if (!this.todo) {
167
- const self = this;
168
- this.once('ready', () => { self._send(); });
165
+ this.once('ready', () => { this._send(); });
169
166
  }
170
167
  else {
171
168
  this._send();
@@ -180,9 +177,8 @@ class HMailItem extends events.EventEmitter {
180
177
  if (retval === constants.delay) {
181
178
  // Try again in 'delay' seconds.
182
179
  this.logdebug(`Delivery of this email delayed for ${delay_seconds} seconds`);
183
- const hmail = this;
184
- hmail.next_cb();
185
- temp_fail_queue.add(hmail.filename, delay_seconds * 1000, () => { delivery_queue.push(hmail); });
180
+ this.next_cb();
181
+ temp_fail_queue.add(this.filename, delay_seconds * 1000, () => { delivery_queue.push(this); });
186
182
  }
187
183
  else {
188
184
  this.logdebug(`Sending mail: ${this.filename}`);
@@ -191,12 +187,11 @@ class HMailItem extends events.EventEmitter {
191
187
  }
192
188
 
193
189
  get_mx () {
194
- const domain = this.todo.domain;
190
+ const { domain } = this.todo;
195
191
  plugins.run_hooks('get_mx', this, domain);
196
192
  }
197
193
 
198
194
  get_mx_respond (retval, mx) {
199
- const hmail = this;
200
195
  switch (retval) {
201
196
  case constants.ok: {
202
197
  let mx_list;
@@ -214,49 +209,48 @@ class HMailItem extends events.EventEmitter {
214
209
  }
215
210
  mx_list = [{priority: 0, exchange: matches[1], port: matches[3]}];
216
211
  }
217
- hmail.logdebug(`Got a MX from Plugin: ${hmail.todo.domain} => 0 ${JSON.stringify(mx)}`);
218
- return hmail.found_mx(null, mx_list);
212
+ this.logdebug(`Got a MX from Plugin: ${this.todo.domain} => 0 ${JSON.stringify(mx)}`);
213
+ return this.found_mx(null, mx_list);
219
214
  }
220
215
  case constants.deny:
221
- hmail.logwarn(`get_mx plugin returned DENY: ${mx}`);
222
- hmail.todo.rcpt_to.forEach(rcpt => {
223
- hmail.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No MX for ${hmail.todo.domain}`));
216
+ this.logwarn(`get_mx plugin returned DENY: ${mx}`);
217
+ this.todo.rcpt_to.forEach(rcpt => {
218
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No MX for ${this.todo.domain}`));
224
219
  });
225
- return hmail.bounce(`No MX for ${hmail.todo.domain}`);
220
+ return this.bounce(`No MX for ${this.todo.domain}`);
226
221
  case constants.denysoft:
227
- hmail.logwarn(`get_mx plugin returned DENYSOFT: ${mx}`);
228
- hmail.todo.rcpt_to.forEach(rcpt => {
229
- hmail.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Temporary MX lookup error for ${hmail.todo.domain}`, 450));
222
+ this.logwarn(`get_mx plugin returned DENYSOFT: ${mx}`);
223
+ this.todo.rcpt_to.forEach(rcpt => {
224
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Temporary MX lookup error for ${this.todo.domain}`, 450));
230
225
  });
231
- return hmail.temp_fail(`Temporary MX lookup error for ${hmail.todo.domain}`);
226
+ return this.temp_fail(`Temporary MX lookup error for ${this.todo.domain}`);
232
227
  }
233
228
 
234
229
  // if none of the above return codes, drop through to this...
235
230
  mx_lookup.lookup_mx(this.todo.domain, (err, mxs) => {
236
- hmail.found_mx(err, mxs);
231
+ this.found_mx(err, mxs);
237
232
  });
238
233
  }
239
234
 
240
235
  found_mx (err, mxs) {
241
- const hmail = this;
242
236
  if (err) {
243
237
  this.lognotice(`MX Lookup for ${this.todo.domain} failed: ${err}`);
244
238
  if (err.code === dns.NXDOMAIN || err.code === dns.NOTFOUND) {
245
239
  this.todo.rcpt_to.forEach(rcpt => {
246
- hmail.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No Such Domain: ${hmail.todo.domain}`));
240
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No Such Domain: ${this.todo.domain}`));
247
241
  });
248
242
  this.bounce(`No Such Domain: ${this.todo.domain}`);
249
243
  }
250
244
  else if (err.code === 'NOMX') {
251
245
  this.todo.rcpt_to.forEach(rcpt => {
252
- hmail.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Nowhere to deliver mail to for domain: ${hmail.todo.domain}`));
246
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Nowhere to deliver mail to for domain: ${this.todo.domain}`));
253
247
  });
254
- this.bounce(`Nowhere to deliver mail to for domain: ${hmail.todo.domain}`);
248
+ this.bounce(`Nowhere to deliver mail to for domain: ${this.todo.domain}`);
255
249
  }
256
250
  else {
257
251
  // every other error is transient
258
252
  this.todo.rcpt_to.forEach(rcpt => {
259
- hmail.extend_rcpt_with_dsn(rcpt, DSN.addr_unspecified(`DNS lookup failure: ${hmail.todo.domain}`));
253
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_unspecified(`DNS lookup failure: ${this.todo.domain}`));
260
254
  });
261
255
  this.temp_fail(`DNS lookup failure: ${err}`);
262
256
  }
@@ -267,7 +261,7 @@ class HMailItem extends events.EventEmitter {
267
261
  // support draft-delany-nullmx-02
268
262
  if (mxlist.length === 1 && mxlist[0].priority === 0 && mxlist[0].exchange === '') {
269
263
  this.todo.rcpt_to.forEach(rcpt => {
270
- hmail.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Domain ${hmail.todo.domain} sends and receives no email (NULL MX)`));
264
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Domain ${this.todo.domain} sends and receives no email (NULL MX)`));
271
265
  });
272
266
  return this.bounce(`Domain ${this.todo.domain} sends and receives no email (NULL MX)`);
273
267
  }
@@ -294,105 +288,100 @@ class HMailItem extends events.EventEmitter {
294
288
  }
295
289
 
296
290
  try_deliver () {
297
- const self = this;
298
291
 
299
292
  // check if there are any MXs left
300
293
  if (this.mxlist.length === 0) {
301
294
  this.todo.rcpt_to.forEach(rcpt => {
302
- self.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Tried all MXs ${self.todo.domain}`));
295
+ this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Tried all MXs ${this.todo.domain}`));
303
296
  });
304
297
  return this.temp_fail("Tried all MXs");
305
298
  }
306
299
 
307
300
  const mx = this.mxlist.shift();
308
- let host = mx.exchange;
301
+ const host = mx.exchange;
309
302
 
310
- self.force_tls = false;
311
- if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, host)) {
312
- this.logdebug(`Forcing TLS for host ${host}`);
313
- self.force_tls = true;
314
- }
315
- if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, self.todo.domain)) {
316
- this.logdebug(`Forcing TLS for domain ${self.todo.domain}`);
317
- self.force_tls = true;
318
- }
303
+ this.force_tls = this.todo.force_tls;
304
+ if (!this.force_tls) {
305
+ if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, host)) {
306
+ this.logdebug(`Forcing TLS for host ${host}`);
307
+ this.force_tls = true;
308
+ }
309
+ if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, this.todo.domain)) {
310
+ this.logdebug(`Forcing TLS for domain ${this.todo.domain}`);
311
+ this.force_tls = true;
312
+ }
319
313
 
320
- // IP or IP:port
321
- if (net.isIP(host)) {
322
- self.hostlist = [ host ];
323
- return self.try_deliver_host(mx);
314
+ // IP or IP:port
315
+ if (net.isIP(host)) {
316
+ this.hostlist = [ host ];
317
+ return this.try_deliver_host(mx);
318
+ }
324
319
  }
325
320
 
326
- host = mx.exchange;
327
- const family = mx.family;
328
-
329
- this.loginfo(`Looking up ${family} records for: ${host}`);
330
-
331
321
  // we have a host, look up the addresses for the host
332
322
  // and try each in order they appear
333
- // IS: IPv6 compatible
334
- dns.resolve(host, family, (err, addresses) => {
323
+ dns.resolve(host, mx.family, (err, addresses) => {
335
324
  if (err) {
336
- self.lognotice(`DNS lookup of ${host} failed: ${err}`);
337
- return self.try_deliver(); // try next MX
325
+ this.lognotice(`DNS (${mx.family}) for ${host} failed: ${err}`);
326
+ return this.try_deliver(); // try next MX
338
327
  }
339
328
  if (addresses.length === 0) {
340
329
  // NODATA or empty host list
341
- self.lognotice(`DNS lookup of ${host} resulted in no data`);
342
- return self.try_deliver(); // try next MX
330
+ this.lognotice(`DNS (${mx.family}) for ${host} resulted in no data`);
331
+ return this.try_deliver(); // try next MX
343
332
  }
344
- self.hostlist = addresses;
345
- self.try_deliver_host(mx);
333
+ this.logdebug(`DNS (${mx.family}) for ${host} -> ${addresses.join(',')}`);
334
+ this.hostlist = addresses;
335
+ this.try_deliver_host(mx);
346
336
  });
347
337
  }
348
338
 
349
339
  try_deliver_host (mx) {
350
- const self = this;
351
340
 
352
- if (self.hostlist.length === 0) {
353
- return self.try_deliver(); // try next MX
341
+ if (this.hostlist.length === 0) {
342
+ return this.try_deliver(); // try next MX
354
343
  }
355
344
 
356
345
  // Allow transaction notes to set outbound IP
357
- if (!mx.bind && self.todo.notes.outbound_ip) {
358
- mx.bind = self.todo.notes.outbound_ip;
346
+ if (!mx.bind && this.todo.notes.outbound_ip) {
347
+ mx.bind = this.todo.notes.outbound_ip;
359
348
  }
360
349
 
361
350
  // Allow transaction notes to set outbound IP helo
362
351
  if (!mx.bind_helo){
363
- if (self.todo.notes.outbound_helo) {
364
- mx.bind_helo = self.todo.notes.outbound_helo;
352
+ if (this.todo.notes.outbound_helo) {
353
+ mx.bind_helo = this.todo.notes.outbound_helo;
365
354
  }
366
355
  else {
367
356
  mx.bind_helo = net_utils.get_primary_host_name();
368
357
  }
369
358
  }
370
359
 
371
- let host = self.hostlist.shift();
360
+ let host = this.hostlist.shift();
372
361
  const port = mx.port || 25;
373
362
 
374
363
  if (mx.path) {
375
364
  host = mx.path;
376
365
  }
377
366
 
378
- this.loginfo(`Attempting to deliver to: ${host}:${port}${mx.using_lmtp ? " using LMTP" : ""} (${delivery_queue.length()}) (${temp_fail_queue.length()})`);
367
+ this.logdebug(`delivering from: ${mx.bind_helo} to: ${host}:${port}${mx.using_lmtp ? " using LMTP" : ""} (${delivery_queue.length()}) (${temp_fail_queue.length()})`)
379
368
  client_pool.get_client(port, host, mx.bind, !!mx.path, (err, socket) => {
380
369
  if (err) {
381
- if (err.match(/connection timed out|connect ECONNREFUSED/)) {
382
- logger.lognotice(`[outbound] Failed to get pool entry: ${err}`);
370
+ if (/connection timed out|connect ECONNREFUSED/.test(err)) {
371
+ logger.lognotice(`[outbound] Failed to get socket: ${err}`);
383
372
  }
384
373
  else {
385
- logger.logerror(`[outbound] Failed to get pool entry: ${err}`);
374
+ logger.logerror(`[outbound] Failed to get socket: ${err}`);
386
375
  }
387
376
  // try next host
388
- return self.try_deliver_host(mx);
377
+ return this.try_deliver_host(mx);
389
378
  }
390
- self.try_deliver_host_on_socket(mx, host, port, socket);
379
+ this.try_deliver_host_on_socket(mx, host, port, socket);
391
380
  });
392
381
  }
393
382
 
394
383
  try_deliver_host_on_socket (mx, host, port, socket) {
395
- const self = this;
384
+ const self = this;
396
385
  let processing_mail = true;
397
386
  let command = mx.using_lmtp ? 'connect_lmtp' : 'connect';
398
387
 
@@ -406,24 +395,24 @@ class HMailItem extends events.EventEmitter {
406
395
  });
407
396
 
408
397
  socket.once('error', err => {
409
- if (processing_mail) {
410
- self.logerror(`Ongoing connection failed to ${host}:${port} : ${err}`);
411
- processing_mail = false;
412
- client_pool.release_client(socket, port, host, mx.bind, true);
413
- if (err.source === 'tls') // exception thrown from tls_socket during tls upgrade
414
- return obtls.mark_tls_nogo(host, () => { return self.try_deliver_host(mx); });
415
- // try the next MX
416
- return self.try_deliver_host(mx);
417
- }
418
- });
398
+ if (!processing_mail) return
399
+
400
+ self.logerror(`Ongoing connection failed to ${host}:${port} : ${err}`);
401
+ processing_mail = false;
402
+ client_pool.release_client(socket, port, host, mx.bind, true);
403
+ if (err.source === 'tls') // exception thrown from tls_socket during tls upgrade
404
+ return obtls.mark_tls_nogo(host, () => { return self.try_deliver_host(mx); });
405
+ // try the next MX
406
+ self.try_deliver_host(mx);
407
+ })
419
408
 
420
409
  socket.once('close', () => {
421
- if (processing_mail) {
422
- self.logerror(`Remote end ${host}:${port} closed connection while we were processing mail. Trying next MX.`);
423
- processing_mail = false;
424
- client_pool.release_client(socket, port, host, mx.bind, true);
425
- return self.try_deliver_host(mx);
426
- }
410
+ if (!processing_mail) return
411
+
412
+ self.logerror(`Remote end ${host}:${port} closed connection while we were processing mail. Trying next MX.`);
413
+ processing_mail = false;
414
+ client_pool.release_client(socket, port, host, mx.bind, true);
415
+ self.try_deliver_host(mx);
427
416
  });
428
417
 
429
418
  let fin_sent = false;
@@ -559,7 +548,7 @@ class HMailItem extends events.EventEmitter {
559
548
 
560
549
  switch (mx.auth_type.toUpperCase()) {
561
550
  case 'PLAIN':
562
- return send_command('AUTH', `PLAIN ${utils.base64(`${mx.auth_user}\0${mx.auth_user}\0${mx.auth_pass}`)}`);
551
+ return send_command('AUTH', `PLAIN ${utils.base64(`\0${mx.auth_user}\0${mx.auth_pass}`)}`);
563
552
  case 'LOGIN':
564
553
  authenticating = true;
565
554
  return send_command('AUTH', 'LOGIN');
@@ -667,15 +656,7 @@ class HMailItem extends events.EventEmitter {
667
656
  self.discard();
668
657
  }
669
658
 
670
- if (obc.cfg.pool_concurrency_max && success) {
671
- client_pool.release_client(socket, port, host, mx.bind, fin_sent);
672
- }
673
- else if (obc.cfg.pool_concurrency_max && !mx.using_lmtp) {
674
- send_command('RSET');
675
- }
676
- else {
677
- send_command('QUIT');
678
- }
659
+ send_command('QUIT');
679
660
  }
680
661
 
681
662
  socket.on('line', line => {
@@ -742,7 +723,7 @@ class HMailItem extends events.EventEmitter {
742
723
  rcpt.dsn_smtp_response = response.join(' ');
743
724
  rcpt.dsn_remote_mta = mx.exchange;
744
725
  });
745
- send_command(obc.cfg.pool_concurrency_max && !mx.using_lmtp ? 'RSET' : 'QUIT');
726
+ send_command('QUIT');
746
727
  processing_mail = false;
747
728
  return self.temp_fail(`Upstream error: ${code} ${(extc) ? `${extc} ` : ''}${reason}`);
748
729
  }
@@ -780,7 +761,7 @@ class HMailItem extends events.EventEmitter {
780
761
  rcpt.dsn_smtp_response = response.join(' ');
781
762
  rcpt.dsn_remote_mta = mx.exchange;
782
763
  });
783
- send_command(obc.cfg.pool_concurrency_max && !mx.using_lmtp ? 'RSET' : 'QUIT');
764
+ send_command('QUIT');
784
765
  processing_mail = false;
785
766
  return self.temp_fail(`Upstream error: ${code} ${(extc) ? `${extc} ` : ''}${reason}`);
786
767
  }
@@ -831,7 +812,7 @@ class HMailItem extends events.EventEmitter {
831
812
  rcpt.dsn_smtp_response = response.join(' ');
832
813
  rcpt.dsn_remote_mta = mx.exchange;
833
814
  });
834
- send_command(obc.cfg.pool_concurrency_max && !mx.using_lmtp ? 'RSET' : 'QUIT');
815
+ send_command('QUIT');
835
816
  processing_mail = false;
836
817
  return self.bounce(reason, { mx });
837
818
  }
@@ -862,13 +843,13 @@ class HMailItem extends events.EventEmitter {
862
843
  loginfo.version = cipher.version;
863
844
  }
864
845
  if (verifyError) loginfo.error = verifyError;
865
- if (cert && cert.subject) {
846
+ if (cert?.subject) {
866
847
  loginfo.cn = cert.subject.CN;
867
848
  loginfo.organization = cert.subject.O;
868
849
  }
869
- if (cert && cert.issuer) loginfo.issuer = cert.issuer.O;
870
- if (cert && cert.valid_to) loginfo.expires = cert.valid_to;
871
- if (cert && cert.fingerprint) loginfo.fingerprint = cert.fingerprint;
850
+ if (cert?.issuer) loginfo.issuer = cert.issuer.O;
851
+ if (cert?.valid_to) loginfo.expires = cert.valid_to;
852
+ if (cert?.fingerprint) loginfo.fingerprint = cert.fingerprint;
872
853
  self.loginfo('secured', loginfo);
873
854
 
874
855
  if (self.force_tls && !authorized) {
@@ -935,13 +916,6 @@ class HMailItem extends events.EventEmitter {
935
916
  }
936
917
  break;
937
918
  case 'quit':
938
- if (obc.cfg.pool_concurrency_max) {
939
- self.logerror("We should NOT have sent QUIT from here...");
940
- }
941
- else {
942
- client_pool.release_client(socket, port, host, mx.bind, fin_sent);
943
- }
944
- break;
945
919
  case 'rset':
946
920
  client_pool.release_client(socket, port, host, mx.bind, fin_sent);
947
921
  break;
@@ -953,9 +927,9 @@ class HMailItem extends events.EventEmitter {
953
927
  });
954
928
 
955
929
  if (socket.__fromPool) {
956
- logger.logdebug('[outbound] got pooled socket, trying to deliver');
930
+ logger.logdebug('[outbound] got socket, trying to deliver');
957
931
  secured = socket.isEncrypted();
958
- logger.logdebug(`[outbound] got pooled ${secured ? 'TLS ' : '' }socket, trying to deliver`);
932
+ logger.logdebug(`[outbound] got ${secured ? 'TLS ' : '' }socket, trying to deliver`);
959
933
  send_command('MAIL', `FROM:${self.todo.mail_from.format(!smtp_properties.smtp_utf8)}`);
960
934
  }
961
935
  }
@@ -973,12 +947,11 @@ class HMailItem extends events.EventEmitter {
973
947
  }
974
948
 
975
949
  populate_bounce_message (from, to, reason, cb) {
976
- const self = this;
977
950
 
978
951
  let buf = '';
979
952
  const original_header_lines = [];
980
953
  let headers_done = false;
981
- const header = new Header();
954
+ const header = new message.Header();
982
955
 
983
956
  try {
984
957
  const data_stream = this.data_stream();
@@ -1001,14 +974,14 @@ class HMailItem extends events.EventEmitter {
1001
974
  if (original_header_lines.length > 0) {
1002
975
  header.parse(original_header_lines);
1003
976
  }
1004
- self.populate_bounce_message_with_headers(from, to, reason, header, cb);
977
+ this.populate_bounce_message_with_headers(from, to, reason, header, cb);
1005
978
  });
1006
979
  data_stream.on('error', err => {
1007
980
  cb(err);
1008
981
  });
1009
982
  }
1010
983
  catch (err) {
1011
- self.populate_bounce_message_with_headers(from, to, reason, header, cb);
984
+ this.populate_bounce_message_with_headers(from, to, reason, header, cb);
1012
985
  }
1013
986
  }
1014
987
 
@@ -1035,7 +1008,6 @@ class HMailItem extends events.EventEmitter {
1035
1008
  * @param cb - a callback for fn(err, message_body_lines)
1036
1009
  */
1037
1010
  populate_bounce_message_with_headers (from, to, reason, header, cb) {
1038
- const self = this;
1039
1011
  const CRLF = '\r\n';
1040
1012
 
1041
1013
  const originalMessageId = header.get('Message-Id');
@@ -1175,10 +1147,10 @@ class HMailItem extends events.EventEmitter {
1175
1147
  bounce_body.push(`Original-Envelope-Id: ${originalMessageId.replace(/(\r?\n)*$/, '')}${CRLF}`);
1176
1148
  }
1177
1149
  bounce_body.push(`Reporting-MTA: dns;${net_utils.get_primary_host_name()}${CRLF}`);
1178
- if (self.todo.queue_time) {
1179
- bounce_body.push(`Arrival-Date: ${utils.date_to_str(new Date(self.todo.queue_time))}${CRLF}`);
1150
+ if (this.todo.queue_time) {
1151
+ bounce_body.push(`Arrival-Date: ${utils.date_to_str(new Date(this.todo.queue_time))}${CRLF}`);
1180
1152
  }
1181
- self.todo.rcpt_to.forEach(rcpt_to => {
1153
+ this.todo.rcpt_to.forEach(rcpt_to => {
1182
1154
  bounce_body.push(CRLF);
1183
1155
  bounce_body.push(`Final-Recipient: rfc822;${rcpt_to.address()}${CRLF}`);
1184
1156
  let dsn_action = null;
@@ -1211,7 +1183,7 @@ class HMailItem extends events.EventEmitter {
1211
1183
  bounce_body.push(`Action: ${dsn_action}${CRLF}`);
1212
1184
  }
1213
1185
  if (rcpt_to.dsn_status) {
1214
- let dsn_status = rcpt_to.dsn_status;
1186
+ let { dsn_status } = rcpt_to;
1215
1187
  if (rcpt_to.dsn_code || rcpt_to.dsn_msg) {
1216
1188
  dsn_status += " (";
1217
1189
  if (rcpt_to.dsn_code) {
@@ -1266,9 +1238,7 @@ class HMailItem extends events.EventEmitter {
1266
1238
  bounce (err, opts) {
1267
1239
  this.loginfo(`bouncing mail: ${err}`);
1268
1240
  if (!this.todo) {
1269
- // haven't finished reading the todo, delay here...
1270
- const self = this;
1271
- self.once('ready', () => { self._bounce(err, opts); });
1241
+ this.once('ready', () => { this._bounce(err, opts); });
1272
1242
  return;
1273
1243
  }
1274
1244
  this._bounce(err, opts);
@@ -1394,20 +1364,18 @@ class HMailItem extends events.EventEmitter {
1394
1364
  parts.next_attempt = Date.now() + delay;
1395
1365
  parts.attempts = this.num_failures;
1396
1366
  const new_filename = _qfile.name(parts);
1397
- // const new_filename = this`.filename.replace(/^(\d+)_(\d+)_/, until + '_' + this.num_failures + '_');
1398
1367
 
1399
- const hmail = this;
1400
1368
  fs.rename(this.path, path.join(queue_dir, new_filename), err => {
1401
1369
  if (err) {
1402
- return hmail.bounce(`Error re-queueing email: ${err}`);
1370
+ return this.bounce(`Error re-queueing email: ${err}`);
1403
1371
  }
1404
1372
 
1405
- hmail.path = path.join(queue_dir, new_filename);
1406
- hmail.filename = new_filename;
1373
+ this.path = path.join(queue_dir, new_filename);
1374
+ this.filename = new_filename;
1407
1375
 
1408
- hmail.next_cb();
1376
+ this.next_cb();
1409
1377
 
1410
- temp_fail_queue.add(hmail.filename, delay, () => { delivery_queue.push(hmail); });
1378
+ temp_fail_queue.add(this.filename, delay, () => { delivery_queue.push(this); });
1411
1379
  });
1412
1380
  }
1413
1381
 
@@ -1458,17 +1426,15 @@ class HMailItem extends events.EventEmitter {
1458
1426
  fs.rename(tmp_path, dest_path, err => {
1459
1427
  if (err) {
1460
1428
  err_handler(err, "tmp file rename");
1429
+ return
1461
1430
  }
1462
- else {
1463
- const split_mail = new HMailItem (fname, dest_path, hmail.notes);
1464
- split_mail.once('ready', () => {
1465
- cb(split_mail);
1466
- });
1467
- }
1431
+ const split_mail = new HMailItem (fname, dest_path, hmail.notes);
1432
+ split_mail.once('ready', () => {
1433
+ cb(split_mail);
1434
+ });
1468
1435
  });
1469
1436
  });
1470
1437
  ws.destroySoon();
1471
- return;
1472
1438
  });
1473
1439
  }
1474
1440
 
package/outbound/index.js CHANGED
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
6
  const async = require('async');
7
- const Address = require('address-rfc2821').Address;
7
+ const { Address } = require('address-rfc2821');
8
8
  const config = require('haraka-config');
9
9
  const constants = require('haraka-constants');
10
10
  const net_utils = require('haraka-net-utils');
@@ -20,12 +20,9 @@ const obc = require('./config');
20
20
  const queuelib = require('./queue');
21
21
  const HMailItem = require('./hmail');
22
22
  const TODOItem = require('./todo');
23
- const pools = require('./client_pool');
24
23
  const _qfile = exports.qfile = require('./qfile');
25
24
 
26
- const queue_dir = queuelib.queue_dir;
27
- const temp_fail_queue = queuelib.temp_fail_queue;
28
- const delivery_queue = queuelib.delivery_queue;
25
+ const { queue_dir, temp_fail_queue, delivery_queue } = queuelib;
29
26
 
30
27
  exports.temp_fail_queue = temp_fail_queue;
31
28
  exports.delivery_queue = delivery_queue;
@@ -42,34 +39,30 @@ exports.load_pid_queue = queuelib.load_pid_queue;
42
39
  exports.ensure_queue_dir = queuelib.ensure_queue_dir;
43
40
  exports.load_queue = queuelib.load_queue;
44
41
  exports.stats = queuelib.stats;
45
- exports.drain_pools = pools.drain_pools;
46
42
 
47
43
  process.on('message', msg => {
48
- if (msg.event && msg.event === 'outbound.load_pid_queue') {
44
+ if (!msg.event) return
45
+
46
+ if (msg.event === 'outbound.load_pid_queue') {
49
47
  exports.load_pid_queue(msg.data);
50
48
  return;
51
49
  }
52
- if (msg.event && msg.event === 'outbound.flush_queue') {
50
+ if (msg.event === 'outbound.flush_queue') {
53
51
  exports.flush_queue(msg.domain, process.pid);
54
52
  return;
55
53
  }
56
- if (msg.event && msg.event === 'outbound.shutdown') {
54
+ if (msg.event === 'outbound.shutdown') {
57
55
  logger.loginfo("[outbound] Shutting down temp fail queue");
58
- exports.drain_pools();
59
56
  temp_fail_queue.shutdown();
60
57
  return;
61
58
  }
62
- if (msg.event && msg.event === 'outbound.drain_pools') {
63
- exports.drain_pools();
64
- return;
65
- }
66
59
  // ignores the message
67
60
  });
68
61
 
69
62
  exports.send_email = function () {
70
63
 
71
64
  if (arguments.length === 2) {
72
- logger.loginfo("[outbound] Sending email as a transaction");
65
+ logger.logdebug("[outbound] Sending email as a transaction");
73
66
  return this.send_trans_email(arguments[0], arguments[1]);
74
67
  }
75
68
 
@@ -227,7 +220,6 @@ function get_deliveries (transaction) {
227
220
  }
228
221
 
229
222
  exports.send_trans_email = function (transaction, next) {
230
- const self = this;
231
223
 
232
224
  // add potentially missing headers
233
225
  if (!transaction.header.get_all('Message-Id').length) {
@@ -243,9 +235,7 @@ exports.send_trans_email = function (transaction, next) {
243
235
  transaction.add_leading_header('Received', `(${obc.cfg.received_header}); ${utils.date_to_str(new Date())}`);
244
236
  }
245
237
 
246
- const connection = {
247
- transaction,
248
- };
238
+ const connection = { transaction };
249
239
 
250
240
  logger.add_log_methods(connection);
251
241
  if (!transaction.results) {
@@ -264,7 +254,7 @@ exports.send_trans_email = function (transaction, next) {
264
254
  const todo = new TODOItem(deliv.domain, deliv.rcpts, transaction);
265
255
  todo.uuid = `${todo.uuid}.${todo_index}`;
266
256
  todo_index++;
267
- self.process_delivery(ok_paths, todo, hmails, cb);
257
+ this.process_delivery(ok_paths, todo, hmails, cb);
268
258
  },
269
259
  (err) => {
270
260
  if (err) {
@@ -276,8 +266,7 @@ exports.send_trans_email = function (transaction, next) {
276
266
  return;
277
267
  }
278
268
 
279
- for (let j=0; j<hmails.length; j++) {
280
- const hmail = hmails[j];
269
+ for (const hmail of hmails) {
281
270
  delivery_queue.push(hmail);
282
271
  }
283
272
 
@@ -292,8 +281,7 @@ exports.send_trans_email = function (transaction, next) {
292
281
  }
293
282
 
294
283
  exports.process_delivery = function (ok_paths, todo, hmails, cb) {
295
- const self = this;
296
- logger.loginfo(`[outbound] Processing delivery for domain: ${todo.domain}`);
284
+ logger.loginfo(`[outbound] Transaction delivery for domain: ${todo.domain}`);
297
285
  const fname = _qfile.name();
298
286
  const tmp_path = path.join(queue_dir, `${_qfile.platformDOT}${fname}`);
299
287
  const ws = new FsyncWriteStream(tmp_path, { flags: constants.WRITE_EXCL });
@@ -321,7 +309,7 @@ exports.process_delivery = function (ok_paths, todo, hmails, cb) {
321
309
  cb("Queueing failed");
322
310
  })
323
311
 
324
- self.build_todo(todo, ws, () => {
312
+ this.build_todo(todo, ws, () => {
325
313
  todo.message_stream.pipe(ws, { line_endings: '\r\n', dot_stuffing: true, ending_dot: false });
326
314
  });
327
315
  }