Haraka 3.0.5 → 3.1.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.
Files changed (53) hide show
  1. package/CONTRIBUTORS.md +6 -5
  2. package/Changes.md +172 -27
  3. package/LICENSE +1 -1
  4. package/Plugins.md +3 -3
  5. package/bin/haraka +2 -1
  6. package/config/connection.ini +63 -0
  7. package/config/smtp.ini +0 -18
  8. package/connection.js +53 -63
  9. package/docs/CoreConfig.md +17 -78
  10. package/docs/HAProxy.md +10 -28
  11. package/docs/Outbound.md +8 -9
  12. package/docs/plugins/aliases.md +4 -6
  13. package/docs/plugins/block_me.md +2 -4
  14. package/docs/plugins/data.signatures.md +2 -4
  15. package/docs/plugins/max_unrecognized_commands.md +2 -4
  16. package/docs/plugins/prevent_credential_leaks.md +2 -5
  17. package/docs/plugins/process_title.md +1 -2
  18. package/docs/plugins/queue/test.md +9 -0
  19. package/docs/plugins/rcpt_to.in_host_list.md +1 -2
  20. package/docs/plugins/rcpt_to.max_count.md +2 -10
  21. package/docs/plugins/record_envelope_addresses.md +3 -6
  22. package/docs/plugins/relay.md +1 -155
  23. package/docs/plugins/reseed_rng.md +1 -2
  24. package/docs/plugins/tarpit.md +7 -10
  25. package/docs/plugins/toobusy.md +2 -4
  26. package/docs/plugins/xclient.md +1 -2
  27. package/eslint.config.mjs +27 -0
  28. package/logger.js +1 -8
  29. package/outbound/hmail.js +8 -1
  30. package/package.json +56 -53
  31. package/plugins/auth/auth_base.js +0 -1
  32. package/plugins/queue/test.js +5 -3
  33. package/server.js +0 -14
  34. package/test/connection.js +18 -7
  35. package/.eslintrc.yaml +0 -11
  36. package/config/connection_close_message +0 -1
  37. package/config/databytes +0 -1
  38. package/config/dhparams.pem +0 -8
  39. package/config/early_talker.ini +0 -11
  40. package/config/mail_from.is_resolvable.ini +0 -6
  41. package/config/max_unrecognized_commands +0 -1
  42. package/config/smtp.json +0 -17
  43. package/docs/plugins/early_talker.md +0 -22
  44. package/docs/plugins/mail_from.is_resolvable.md +0 -29
  45. package/plugins/early_talker.js +0 -155
  46. package/plugins/mail_from.is_resolvable.js +0 -132
  47. package/plugins/relay.js +0 -207
  48. package/test/plugins/early_talker.js +0 -104
  49. package/test/plugins/mail_from.is_resolvable.js +0 -35
  50. package/test/plugins/relay.js +0 -303
  51. /package/docs/{plugins → deprecated}/access.md +0 -0
  52. /package/docs/{plugins → deprecated}/backscatterer.md +0 -0
  53. /package/docs/{plugins → deprecated}/data.headers.md +0 -0
package/connection.js CHANGED
@@ -24,33 +24,33 @@ const outbound = require('./outbound');
24
24
 
25
25
  const states = constants.connection.state;
26
26
 
27
- // Load HAProxy hosts into an object for fast lookups
28
- // as this list is checked on every new connection.
29
- let haproxy_hosts_ipv4 = [];
30
- let haproxy_hosts_ipv6 = [];
31
- function loadHAProxyHosts () {
32
- const hosts = config.get('haproxy_hosts', 'list', loadHAProxyHosts);
33
- const new_ipv4_hosts = [];
34
- const new_ipv6_hosts = [];
35
- for (let i=0; i<hosts.length; i++) {
36
- const host = hosts[i].split(/\//);
37
- if (net.isIPv6(host[0])) {
38
- new_ipv6_hosts[i] = [ipaddr.IPv6.parse(host[0]), parseInt(host[1] || 64)];
39
- }
40
- else {
41
- new_ipv4_hosts[i] = [ipaddr.IPv4.parse(host[0]), parseInt(host[1] || 32)];
42
- }
27
+ const cfg = config.get('connection.ini', {
28
+ booleans: [
29
+ '-main.strict_rfc1869',
30
+ '+main.smtputf8',
31
+ '+headers.add_received',
32
+ '+headers.show_version',
33
+ '+headers.clean_auth_results',
34
+ ]
35
+ });
36
+
37
+ const haproxy_hosts_ipv4 = [];
38
+ const haproxy_hosts_ipv6 = [];
39
+
40
+ for (const ip of cfg.haproxy.hosts) {
41
+ if (!ip) continue;
42
+ if (net.isIPv6(ip.split('/')[0])) {
43
+ haproxy_hosts_ipv6.push([ipaddr.IPv6.parse(ip.split('/')[0]), parseInt(ip.split('/')[1] || 64)]);
44
+ }
45
+ else {
46
+ haproxy_hosts_ipv4.push([ipaddr.IPv4.parse(ip.split('/')[0]), parseInt(ip.split('/')[1] || 32)]);
43
47
  }
44
- haproxy_hosts_ipv4 = new_ipv4_hosts;
45
- haproxy_hosts_ipv6 = new_ipv6_hosts;
46
48
  }
47
- loadHAProxyHosts();
48
49
 
49
50
  class Connection {
50
- constructor (client, server, cfg) {
51
+ constructor (client, server, smtp_cfg) {
51
52
  this.client = client;
52
53
  this.server = server;
53
- this.cfg = cfg;
54
54
 
55
55
  this.local = {
56
56
  ip: null,
@@ -97,10 +97,6 @@ class Connection {
97
97
  this.transaction = null;
98
98
  this.tran_count = 0;
99
99
  this.capabilities = null;
100
- this.ehlo_hello_message = config.get('ehlo_hello_message') || 'Haraka is at your service.';
101
- this.connection_close_message = config.get('connection_close_message') || 'closing connection. Have a jolly good day.';
102
- this.banner_includes_uuid = !!config.get('banner_includes_uuid');
103
- this.deny_includes_uuid = config.get('deny_includes_uuid') || null;
104
100
  this.early_talker = false;
105
101
  this.pipelining = false;
106
102
  this._relaying = false;
@@ -109,8 +105,6 @@ class Connection {
109
105
  this.hooks_to_run = [];
110
106
  this.start_time = Date.now();
111
107
  this.last_reject = '';
112
- this.max_bytes = parseInt(config.get('databytes')) || 0;
113
- this.max_mime_parts = parseInt(config.get('max_mime_parts')) || 1000;
114
108
  this.totalbytes = 0;
115
109
  this.rcpt_count = {
116
110
  accept: 0,
@@ -122,13 +116,11 @@ class Connection {
122
116
  tempfail: 0,
123
117
  reject: 0,
124
118
  };
125
- this.max_line_length = parseInt(config.get('max_line_length')) || 512;
126
- this.max_data_line_length = parseInt(config.get('max_data_line_length')) || 992;
127
119
  this.results = new ResultStore(this);
128
120
  this.errors = 0;
129
121
  this.last_rcpt_msg = null;
130
122
  this.hook = null;
131
- if (this.cfg.headers.show_version) {
123
+ if (cfg.headers.show_version) {
132
124
  this.local.info += `/${utils.getVersion(__dirname)}`;
133
125
  }
134
126
  Connection.setupClient(this);
@@ -200,7 +192,6 @@ class Connection {
200
192
  });
201
193
 
202
194
  const ha_list = net.isIPv6(self.remote.ip) ? haproxy_hosts_ipv6 : haproxy_hosts_ipv4;
203
-
204
195
  if (ha_list.some((element, index, array) => {
205
196
  return ipaddr.parse(self.remote.ip).match(element[0], element[1]);
206
197
  })) {
@@ -220,7 +211,7 @@ class Connection {
220
211
  this.set('hello', 'host', undefined);
221
212
  this.set('tls', 'enabled', true);
222
213
  for (const t of ['cipher','verified','verifyError','peerCertificate']) {
223
- if (obj[t] === undefined) return;
214
+ if (obj[t] === undefined) continue;
224
215
  this.set('tls', t, obj[t]);
225
216
  }
226
217
  // prior to 2017-07, authorized and verified were both used. Verified
@@ -401,10 +392,10 @@ class Connection {
401
392
 
402
393
  let maxlength;
403
394
  if (this.state === states.PAUSE_DATA || this.state === states.DATA) {
404
- maxlength = this.max_data_line_length;
395
+ maxlength = cfg.max.data_line_length;
405
396
  }
406
397
  else {
407
- maxlength = this.max_line_length;
398
+ maxlength = cfg.max.line_length;
408
399
  }
409
400
 
410
401
  let offset;
@@ -535,10 +526,10 @@ class Connection {
535
526
 
536
527
  if (code >= 400) {
537
528
  this.last_reject = `${code} ${messages.join(' ')}`;
538
- if (this.deny_includes_uuid) {
529
+ if (cfg.uuid.deny_chars) {
539
530
  uuid = (this.transaction || this).uuid;
540
- if (this.deny_includes_uuid > 1) {
541
- uuid = uuid.substr(0, this.deny_includes_uuid);
531
+ if (cfg.uuid.deny_chars > 1) {
532
+ uuid = uuid.substr(0, cfg.uuid.deny_chars);
542
533
  }
543
534
  }
544
535
  }
@@ -649,7 +640,7 @@ class Connection {
649
640
  }
650
641
  init_transaction (cb) {
651
642
  this.reset_transaction(() => {
652
- this.transaction = trans.createTransaction(this.tran_uuid(), this.cfg);
643
+ this.transaction = trans.createTransaction(this.tran_uuid(), cfg);
653
644
  // Catch any errors from the message_stream
654
645
  this.transaction.message_stream.on('error', (err) => {
655
646
  this.logcrit(`message_stream error: ${err.message}`);
@@ -792,19 +783,20 @@ class Connection {
792
783
  });
793
784
  break;
794
785
  default: {
795
- let greeting = config.get('smtpgreeting', 'list');
796
- if (greeting.length) {
786
+ let greeting;
787
+ if (cfg.message.greeting?.length) {
797
788
  // RFC5321 section 4.2
798
789
  // Hostname/domain should appear after the 220
790
+ greeting = [...cfg.message.greeting];
799
791
  greeting[0] = `${this.local.host} ESMTP ${greeting[0]}`;
800
- if (this.banner_includes_uuid) {
801
- greeting[0] += ` (${this.uuid})`;
792
+ if (cfg.uuid.banner_chars) {
793
+ greeting[0] += ` (${this.uuid.substr(0, cfg.uuid.banner_chars)})`;
802
794
  }
803
795
  }
804
796
  else {
805
797
  greeting = `${this.local.host} ESMTP ${this.local.info} ready`;
806
- if (this.banner_includes_uuid) {
807
- greeting += ` (${this.uuid})`;
798
+ if (cfg.uuid.banner_chars) {
799
+ greeting += ` (${this.uuid.substr(0, cfg.uuid.banner_chars)})`;
808
800
  }
809
801
  }
810
802
  this.respond(220, msg || greeting);
@@ -850,7 +842,7 @@ class Connection {
850
842
  default:
851
843
  // RFC5321 section 4.1.1.1
852
844
  // Hostname/domain should appear after 250
853
- this.respond(250, `${this.local.host} Hello ${this.get_remote('host')}, ${this.ehlo_hello_message}`);
845
+ this.respond(250, `${this.local.host} Hello ${this.get_remote('host')}, ${cfg.message.helo}`);
854
846
  }
855
847
  }
856
848
  ehlo_respond (retval, msg) {
@@ -883,16 +875,14 @@ class Connection {
883
875
  // Hostname/domain should appear after 250
884
876
 
885
877
  const response = [
886
- `${this.local.host} Hello ${this.get_remote('host')}, ${this.ehlo_hello_message}`,
878
+ `${this.local.host} Hello ${this.get_remote('host')}, ${cfg.message.helo}`,
887
879
  "PIPELINING",
888
880
  "8BITMIME",
889
881
  ];
890
882
 
891
- if (this.cfg.main.smtputf8) {
892
- response.push("SMTPUTF8");
893
- }
883
+ if (cfg.main.smtputf8) response.push("SMTPUTF8");
894
884
 
895
- response.push(`SIZE ${this.max_bytes}`);
885
+ response.push(`SIZE ${cfg.max.bytes}`);
896
886
 
897
887
  this.capabilities = response;
898
888
 
@@ -905,7 +895,7 @@ class Connection {
905
895
  this.respond(250, this.capabilities);
906
896
  }
907
897
  quit_respond (retval, msg) {
908
- this.respond(221, msg || `${this.local.host} ${this.connection_close_message}`, () => {
898
+ this.respond(221, msg || `${this.local.host} ${cfg.message.close}`, () => {
909
899
  this.disconnect();
910
900
  });
911
901
  }
@@ -1314,7 +1304,7 @@ class Connection {
1314
1304
 
1315
1305
  let results;
1316
1306
  try {
1317
- results = rfc1869.parse('mail', line, this.cfg.main.strict_rfc1869 && !this.relaying);
1307
+ results = rfc1869.parse('mail', line, (!this.relaying && cfg.main.strict_rfc1869));
1318
1308
  }
1319
1309
  catch (err) {
1320
1310
  this.errors++;
@@ -1356,7 +1346,7 @@ class Connection {
1356
1346
 
1357
1347
  // Handle SIZE extension
1358
1348
  if (params?.SIZE && params.SIZE > 0) {
1359
- if (this.max_bytes > 0 && params.SIZE > this.max_bytes) {
1349
+ if (cfg.max.bytes > 0 && params.SIZE > cfg.max.bytes) {
1360
1350
  return this.respond(550, 'Message too big!');
1361
1351
  }
1362
1352
  }
@@ -1378,7 +1368,7 @@ class Connection {
1378
1368
 
1379
1369
  let results;
1380
1370
  try {
1381
- results = rfc1869.parse('rcpt', line, this.cfg.main.strict_rfc1869 && !this.relaying);
1371
+ results = rfc1869.parse('rcpt', line, cfg.main.strict_rfc1869 && !this.relaying);
1382
1372
  }
1383
1373
  catch (err) {
1384
1374
  this.errors++;
@@ -1512,7 +1502,7 @@ class Connection {
1512
1502
  return this.respond(503, "RCPT required first");
1513
1503
  }
1514
1504
 
1515
- if (this.cfg.headers.add_received) {
1505
+ if (cfg.headers.add_received) {
1516
1506
  this.accumulate_data(`Received: ${this.received_line()}\r\n`);
1517
1507
  }
1518
1508
  plugins.run_hooks('data', this);
@@ -1577,11 +1567,11 @@ class Connection {
1577
1567
  }
1578
1568
 
1579
1569
  // Stop accumulating data as we're going to reject at dot.
1580
- if (this.max_bytes && this.transaction.data_bytes > this.max_bytes) {
1570
+ if (cfg.max.bytes && this.transaction.data_bytes > cfg.max.bytes) {
1581
1571
  return;
1582
1572
  }
1583
1573
 
1584
- if (this.transaction.mime_part_count >= this.max_mime_parts) {
1574
+ if (this.transaction.mime_part_count >= cfg.max.mime_parts) {
1585
1575
  this.logcrit("Possible DoS attempt - too many MIME parts");
1586
1576
  this.respond(554, "Transaction failed due to too many MIME parts", () => {
1587
1577
  this.disconnect();
@@ -1596,13 +1586,13 @@ class Connection {
1596
1586
  this.totalbytes += this.transaction.data_bytes;
1597
1587
 
1598
1588
  // Check message size limit
1599
- if (this.max_bytes && this.transaction.data_bytes > this.max_bytes) {
1600
- this.lognotice(`Incoming message exceeded databytes size of ${this.max_bytes}`);
1589
+ if (cfg.max.bytes && this.transaction.data_bytes > cfg.max.bytes) {
1590
+ this.lognotice(`Incoming message exceeded max size of ${cfg.max.bytes}`);
1601
1591
  return plugins.run_hooks('max_data_exceeded', this);
1602
1592
  }
1603
1593
 
1604
1594
  // Check max received headers count
1605
- if (this.transaction.header.get_all('received').length > this.cfg.headers.max_received) {
1595
+ if (this.transaction.header.get_all('received').length > cfg.headers.max_received) {
1606
1596
  this.logerror("Incoming message had too many Received headers");
1607
1597
  this.respond(550, "Too many received headers - possible mail loop", () => {
1608
1598
  this.reset_transaction();
@@ -1611,11 +1601,11 @@ class Connection {
1611
1601
  }
1612
1602
 
1613
1603
  // Warn if we hit the maximum parsed header lines limit
1614
- if (this.transaction.header_lines.length >= this.cfg.headers.max_lines) {
1615
- this.logwarn(`Incoming message reached maximum parsing limit of ${this.cfg.headers.max_lines} header lines`);
1604
+ if (this.transaction.header_lines.length >= cfg.headers.max_lines) {
1605
+ this.logwarn(`Incoming message reached maximum parsing limit of ${cfg.headers.max_lines} header lines`);
1616
1606
  }
1617
1607
 
1618
- if (this.cfg.headers.clean_auth_results) {
1608
+ if (cfg.headers.clean_auth_results) {
1619
1609
  this.auth_results_clean(); // rename old A-R headers
1620
1610
  }
1621
1611
  const ar_field = this.auth_results(); // assemble new one
@@ -11,10 +11,6 @@ If either of these files exist then they are loaded first.
11
11
  This file is designed to use the JSON/YAML file overrides documented in
12
12
  [haraka-config](https://github.com/haraka/haraka-config) to optionally provide the entire configuration in a single file.
13
13
 
14
- * databytes
15
-
16
- Contains the maximum SIZE of an email that Haraka will receive.
17
-
18
14
  * plugins
19
15
 
20
16
  The list of plugins to load
@@ -40,35 +36,29 @@ The list of plugins to load
40
36
  specify -1 to disable spooling completely or 0 to force all messages to be spooled to disk.
41
37
  * graceful\_shutdown - (default: false) enable this to wait for sockets on shutdown instead of closing them quickly
42
38
  * force_shutdown_timeout - (default: 30) number of seconds to wait for a graceful shutdown
43
- * smtputf8 - (default: true) advertise support for SMTPUTF8
44
- * strict\_rfc1869 - (default: false) Requires senders to conform to RFC 1869 and RFC 821 when sending the MAIL FROM and RCPT TO commands. In particular,
45
- the inclusion of spurious spaces or missing angle brackets will be rejected.
46
39
 
47
40
  * me
48
41
 
49
42
  A name to use for this server. Used in received lines and elsewhere. Setup
50
43
  by default to be your hostname.
51
44
 
52
- * deny\_includes\_uuid
53
-
54
- Each connection and mail in Haraka includes a UUID which is also in most log
55
- messages. If you put a `1` in this file then every denied mail (either via
56
- DENY/5xx or DENYSOFT/4xx return codes) will include the uuid at the start
57
- of each line of the deny message in brackets, making it easy to track
58
- problems back to the logs.
59
-
60
- Because UUIDs are long, if you put a number greater than 1 in the config
61
- file, it will be truncated to that length. We recommend a 6 as a good
62
- balance of finding in the logs and not making lines too long.
63
-
64
- * banner\_includes\_uuid
65
-
66
- This will add the full UUID to the first line of the SMTP greeting banner.
45
+ * connection.ini
67
46
 
68
- * early\_talker\_delay
47
+ See inline comments in connection.ini for the following settings:
69
48
 
70
- If clients talk early we *punish* them with a delay of this many milliseconds
71
- default: 1000.
49
+ * haproxy.hosts\_ipv4
50
+ * haproxy.hosts\_ipv6
51
+ * headers.\*
52
+ * max.bytes
53
+ * max.line\_length
54
+ * max.data\_line\_length
55
+ * max.mime\_parts
56
+ * message.greeting
57
+ * message.close
58
+ * smtputf8
59
+ * strict\_rfc1869
60
+ * uuid.deny\_chars
61
+ * uuid.banner\_bytes
72
62
 
73
63
  * plugin\_timeout
74
64
 
@@ -81,59 +71,8 @@ The list of plugins to load
81
71
  If the plugin is in a sub-directory of plugins, then you must create this file
82
72
  in the equivalent path e.g. the queue/smtp_forward would need a timeout file in `config/queue/smtp_forward.timeout`
83
73
 
84
- * smtpgreeting
85
-
86
- The greeting line used when a client connects. This can be multiple lines
87
- if required (this may cause some connecting machines to fail - though
88
- usually only spam-bots).
89
-
90
- * max\_received\_count
91
-
92
- The maximum number of "Received" headers allowed in an email. This is a
93
- simple protection against mail loops. Defaults to 100.
94
-
95
- * max\_line\_length
96
-
97
- The maximum length of lines in SMTP session commands (e.g. RCPT, HELO etc).
98
- Defaults to 512 (bytes) which is mandated by RFC 5321 §4.5.3.1.4. Clients
99
- exceeding this limit will be immediately disconnected with a "521 Command
100
- line too long" error.
101
-
102
- * max\_data\_line\_length
103
-
104
- The maximum length of lines in the DATA section of emails. Defaults to 992
105
- (bytes) which is the limit set by Sendmail. When this limit is exceeded the
106
- three bytes "\r\n " (0x0d 0x0a 0x20) are inserted into the stream to "fix"
107
- it. This has the potential to "break" some email, but makes it more likely
108
- to be accepted by upstream/downstream services, and is the same behaviour
109
- as Sendmail. Also when the data line length limit is exceeded
110
- `transaction.notes.data_line_length_exceeded` is set to `true`.
111
-
112
- * outbound.concurrency\_max
113
-
114
- Maximum concurrency to use when delivering mails outbound. Defaults to 100.
115
-
116
- * outbound.disabled
117
-
118
- Put a `1` in this file to temporarily disable outbound delivery. Useful
119
- while figuring out network issues or testing.
74
+ * outbound.ini
120
75
 
121
76
  * outbound.bounce\_message
122
77
 
123
- The bounce message if delivery of the message fails. The default is normally fine. Bounce messages contain a number of template
124
- replacement values which are best discovered by looking at the source code.
125
-
126
- * haproxy\_hosts
127
-
128
- A list of HAProxy hosts that Haraka should enable the PROXY protocol from.
129
- See [HAProxy.md](HAProxy.md)
130
-
131
- * max_mime_parts
132
-
133
- Defaults to 1000. There's a potential denial of service in large numbers of
134
- MIME parts in carefully crafted emails. If this limit is too low for some
135
- reason you can increase it by setting a value in this file.
136
-
137
- * connection\_close\_message
138
-
139
- Defaults to `closing connection. Have a jolly good day.` can be overrridden with custom text
78
+ The bounce message if delivery of the message fails. The default is normally fine. Bounce messages contain a number of template replacement values which are best discovered by looking at the source code.
package/docs/HAProxy.md CHANGED
@@ -1,34 +1,20 @@
1
- HAProxy PROXY protocol extension support
2
- ========================================
1
+ # HAProxy PROXY protocol extension support
3
2
 
4
- Haraka natively supports the PROXY protocol [1].
3
+ Haraka supports PROXY protocol [1].
5
4
 
6
- This allows an upstream proxy to pass IP address and port of the client which
7
- Haraka will use instead of the socket IP address (which is of the proxy).
8
- This allows DNSBLs and access control lists to operate on the proxied address.
5
+ This allows an upstream proxy to pass the IP address and port of the remote client. Haraka will use the remote IP instead of the socket IP address (which is the proxy). This allows DNSBLs and access control lists to use the correct source address.
9
6
 
10
- Support is disabled by default and if HAProxy or other attempts to send a
11
- PROXY command then Haraka will return a DENYSOFTDISCONNECT error.
12
- DENYSOFT is used to prevent configuration errors from rejecting valid mail.
7
+ Support is disabled by default. Attempts to send a PROXY command will return a DENYSOFTDISCONNECT error. DENYSOFT is used to prevent configuration errors from rejecting valid mail.
13
8
 
14
- To enable support for PROXY you must create a `haproxy_hosts` configuration
15
- file which should contain a list of IP addresses of the HAProxy hosts
16
- that should be allowed to send the PROXY command. A range of IP
17
- addresses can be specified by it's CIDR network address.
9
+ To enable support for PROXY you must populate connection.ini[haproxy]hosts[] with the IP addresses of the HAProxy hosts that MUST send the PROXY command. Ranges can be specified with CIDR notation.
18
10
 
19
- When a host connects to Haraka that matches an IP address present in the
20
- `haproxy_hosts` file - a banner is not sent, instead Haraka waits for the
21
- PROXY command to be sent before proceeding. The connection will timeout
22
- with `421 PROXY timed out` if the command is not sent within 30 seconds.
11
+ When a proxy host connects to Haraka, a banner is not sent. Instead Haraka awaits the PROXY command. The connection will timeout with `421 PROXY timed out` if the command is not sent within 30 seconds.
23
12
 
24
- NOTE: because Haraka does not send a banner when a listed HAProxy host
25
- connects you must set check-send-proxy to ensure that the service checks
26
- send a PROXY command before they run.
13
+ NOTE: because Haraka does not send a banner when a listed HAProxy host connects you must set check-send-proxy to ensure that the service checks send a PROXY command before they run.
27
14
 
28
15
  [1] http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
29
16
 
30
- HAProxy supports the PROXY protocol in version 1.5 or later however there
31
- are patches available to add support for 1.4.
17
+ HAProxy supports the PROXY protocol in version 1.5 or later.
32
18
 
33
19
  Here is an example listener section for haproxy.cfg:
34
20
 
@@ -45,13 +31,9 @@ listen smtp :25
45
31
  server smtp5 ip.of.haraka.server5:25 check-send-proxy check inter 10s send-proxy
46
32
  ```
47
33
 
48
- The important part is `send-proxy` which causes HAProxy to send the PROXY
49
- extension on connection.
34
+ The important part is `send-proxy` which causes HAProxy to send the PROXY extension on connection.
50
35
 
51
- When using `option smtpchk` you will see CONNRESET errors reported in the Haraka logs as
52
- smtpchk drops the connection before the HELO response is still being written.
53
- You can use the `option tcp-check` instead to provide a better service check by having
54
- the check wait for the banner, send QUIT and then check the response:
36
+ When using `option smtpchk` you will see CONNRESET errors reported in the Haraka logs as smtpchk drops the connection before the HELO response is still being written. You can use the `option tcp-check` instead to provide a better service check by having the check wait for the banner, send QUIT and then check the response:
55
37
 
56
38
  ```
57
39
  option tcp-check
package/docs/Outbound.md CHANGED
@@ -51,8 +51,7 @@ Default: false. By default, outbound to a local IP is disabled, to avoid creatin
51
51
 
52
52
  * `temp_fail_intervals`
53
53
 
54
- Set this to specify the delay intervals to use between trying to re-send an email that has a temporary failure condition. The setting is a comma separated list of time spans and multipliers. The time span is a number followed by `s`, `m`, `h`, or `d` to represent seconds, minutes, hours, and days, respectively. The multiplier is an asterisk followed by an integer representing the number of times to repeat the interval. For example, the entry `1m, 5m*2, 1h*3` results in an array of delay times of
55
- `[60,300,300,3600,3600,3600]` in seconds. The email will be bounced when the array runs out of intervals (the 7th failure in this case). Set this to `none` to bounce the email on the first temporary failure.
54
+ Set this to specify the delay intervals to use between trying to re-send an email that has a temporary failure condition. The setting is a comma separated list of time spans and multipliers. The time span is a number followed by `s`, `m`, `h`, or `d` to represent seconds, minutes, hours, and days, respectively. The multiplier is an asterisk followed by an integer representing the number of times to repeat the interval. For example, the entry `1m, 5m*2, 1h*3` results in an array of delay times of `[60,300,300,3600,3600,3600]` in seconds. The email will be bounced when the array runs out of intervals (the 7th failure in this case). Set this to `none` to bounce the email on the first temporary failure.
56
55
 
57
56
  ### outbound.bounce\_message
58
57
 
@@ -137,11 +136,11 @@ Parameters: `next, hmail, params`
137
136
  Params is a list of: `[host, ip, response, delay, port, mode, ok_recips, secured]`
138
137
 
139
138
  When mails are successfully delivered to the remote end then the `delivered` hook is called. The return codes from this hook have no effect, so it is only useful for logging the fact that a successful delivery occurred.
140
-
139
+
141
140
  * `host` - Hostname of the MX that the message was delivered to,
142
141
  * `ip` - IP address of the host that the message was delivered to,
143
142
  * `response` - Variable contains the SMTP response text returned by the host that received the message and will typically contain the remote queue ID and
144
- * `delay` - Time taken between the queue file being created and the message being delivered.
143
+ * `delay` - Time taken between the queue file being created and the message being delivered.
145
144
  * `port` - Port number that the message was delivered to.
146
145
  * `mode` - Shows whether SMTP or LMTP was used to deliver the mail.
147
146
  * `ok_recips` - an `Address`<sup>[1](#fn1)</sup> array containing all of the recipients that were successfully delivered to.
@@ -149,7 +148,7 @@ When mails are successfully delivered to the remote end then the `delivered` hoo
149
148
 
150
149
  ## Outbound IP address
151
150
 
152
- Normally the OS will decide which IP address will be used for outbound connections using the IP routing table.
151
+ Normally the OS will decide which IP address will be used for outbound connections using the IP routing table.
153
152
 
154
153
  There are instances where you may want to separate outbound traffic on different IP addresses based on sender, domain or some other identifier. To do this, the IP address that you want to use *must* be bound to an interface (or alias) on the local system.
155
154
 
@@ -235,9 +234,9 @@ Where `options` is a Object that may contain the following keys:
235
234
  |------------------------|-------------|
236
235
  | `dot_stuffed: true` | Use this if you are passing your content dot-stuffed (a dot at the start of a line is doubled, like it is in SMTP conversation, see [RFC 2821][url-rfc2821].|
237
236
  | `notes: { key: value}` | In case you need notes in the new transaction that `send_email()` creates. |
238
- | `remove_msgid: true` | Remove any Message-Id header found in the message. If you are reading a message in from the filesystem and you want to ensure that a generated Message-Id header is used in preference over the original. This is useful if you are releasing mail from a quarantine. |
239
- | `remove_date: true` | Remove any Date header found in the message. If you are reading a message in from the filesystem and you want to ensure that a generated Date header is used in preference over the original. This is useful if you are releasing mail from a quarantine. |
240
- | `origin: Object` | Adds object as argument to logger.log calls inside outbound.send_email. Useful for tracking which Plugin/Connection/HMailItem object generated email. |
237
+ | `remove_msgid: true` | Remove any Message-Id header found in the message. If you are reading a message in from the filesystem and you want to ensure that a generated Message-Id header is used in preference over the original. This is useful if you are releasing mail from a quarantine. |
238
+ | `remove_date: true` | Remove any Date header found in the message. If you are reading a message in from the filesystem and you want to ensure that a generated Date header is used in preference over the original. This is useful if you are releasing mail from a quarantine. |
239
+ | `origin: Object` | Adds object as argument to logger.log calls inside outbound.send_email. Useful for tracking which Plugin/Connection/HMailItem object generated email. |
241
240
 
242
241
 
243
242
  ```js
@@ -248,4 +247,4 @@ outbound.send_email(from, to, contents, outnext, { notes: transaction.notes });
248
247
 
249
248
  [url-tls]: https://haraka.github.io/plugins/tls
250
249
  [url-harakamx]: https://github.com/haraka/haraka-net-utils?tab=readme-ov-file#harakamx
251
- [url-rfc2821]: https://tools.ietf.org/html/rfc2821#section-4.5.2
250
+ [url-rfc2821]: https://tools.ietf.org/html/rfc2821#section-4.5.2
@@ -1,5 +1,4 @@
1
- aliases
2
- =======
1
+ # aliases
3
2
 
4
3
  This plugin allows one to configure aliases that may perform an action or
5
4
  change the RCPT address in a number of ways. All aliases are specified in
@@ -12,8 +11,7 @@ that run on hook_rcpt
12
11
 
13
12
  WARNING: DO NOT USE THIS PLUGIN WITH queue/smtp\_proxy.
14
13
 
15
- Configuration
16
- -------------
14
+ ## Configuration
17
15
 
18
16
  * aliases
19
17
 
@@ -135,8 +133,8 @@ Configuration
135
133
  aliases on a single domain that map to other local parts at the
136
134
  same domain.
137
135
 
138
- Example Configuration
139
- ---------------------
136
+ ### Example Configuration
137
+
140
138
  {
141
139
  "test1" : { "action" : "drop" },
142
140
  "test2" : { "action" : "drop" },
@@ -1,5 +1,4 @@
1
- block\_me
2
- ========
1
+ # block\_me
3
2
 
4
3
  This plugin allows you to configure an address which mail sent to will be
5
4
  parsed for a From: address in the body of the message, and will add that
@@ -10,8 +9,7 @@ particular mailbox to block them in the future.
10
9
 
11
10
  Note that this is a system-wide block, and not per-user. Be careful with this.
12
11
 
13
- Configuration
14
- -------------
12
+ ## Configuration
15
13
 
16
14
  * `config/block_me.recipient` - a file containing the address to email to
17
15
  get something blocked. For example: **spam@domain.com**.
@@ -1,12 +1,10 @@
1
- data.signatures
2
- ===============
1
+ # data.signatures
3
2
 
4
3
  This plugin allows you to add string signatures to a configuration file and
5
4
  have this plugin scan the body text of an email for those strings. Mails
6
5
  matching these signatures will be blocked.
7
6
 
8
- Configuration
9
- -------------
7
+ ## Configuration
10
8
 
11
9
  * data.signatures
12
10
 
@@ -1,5 +1,4 @@
1
- max\_unrecognized\_commands
2
- =========================
1
+ # max\_unrecognized\_commands
3
2
 
4
3
  This plugin places a maximum limit on the number of unrecognized commands
5
4
  allowed before recognising that the connection is bad.
@@ -13,8 +12,7 @@ runs after any plugins that use the unrecognized_command hook to implement
13
12
  other SMTP verbs and extensions (such as the auth/* plugins), otherwise
14
13
  commands valid for these plugins will be counted as unknown by this plugin.
15
14
 
16
- Configuration
17
- -------------
15
+ ## Configuration
18
16
 
19
17
  * max\_unrecognized\_commands
20
18
 
@@ -1,5 +1,4 @@
1
- prevent\_credential\_leaks
2
- ========
1
+ # prevent\_credential\_leaks
3
2
 
4
3
  This plugin prevents an authenticated user (via SMTP AUTH) from sending
5
4
  their username and password out in a message (e.g. like replying to a
@@ -16,9 +15,7 @@ Note that if the username is qualified e.g. user@domain.com - then the
16
15
  plugin will search for both `user` and `user@domain.com` for maximum
17
16
  effectiveness.
18
17
 
19
-
20
- Configuration
21
- -------------
18
+ ## Configuration
22
19
 
23
20
  No configuration is required. Simply add the plugin to your `config/plugins`
24
21
  file. It should be added before any other plugins that run on hook_data_post
@@ -1,5 +1,4 @@
1
- process\_title
2
- =============
1
+ # process\_title
3
2
 
4
3
  This plugin causes the process title seen by the UNIX 'ps' command to
5
4
  be modified from this:
@@ -0,0 +1,9 @@
1
+ queue/test
2
+ ==========
3
+
4
+ This plugin saves incoming E-Mail to your temporary directory, as `mail_{message_id}.eml`, where message_id is a UUID.
5
+
6
+ This plugin can be useful to quickly test if you're able to receive incoming E-Mail and just dump them to disk.
7
+
8
+ The temporary directory is determined using Node's [`os.tmpdir()`](https://nodejs.org/api/os.html#ostmpdir), which respects standard platform configurations.
9
+
@@ -1,5 +1,4 @@
1
- rcpt\_to.in\_host\_list
2
- =====================
1
+ # rcpt\_to.in\_host\_list
3
2
 
4
3
  This plugin is the mainstay of an inbound Haraka server. It should list the
5
4
  domains that are local to the host. Mails that have RCPT TO not matching
@@ -1,11 +1,3 @@
1
- rcpt\_to.max\_count
2
- =================
1
+ # rcpt\_to.max\_count
3
2
 
4
- This plugin sets a maximum limit on RCPT TOs. Violators will be disconnected.
5
-
6
- Configuration
7
- -------------
8
-
9
- * rcpt\_to.max\_count
10
-
11
- The maximum number of recipients. Default: 40.
3
+ The functionality of this plugin was integrated in to [haraka-plugin-limit](https://github.com/haraka/haraka-plugin-limit).