haraka 0.0.33 → 3.3.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.
- package/.githooks/pre-commit +41 -0
- package/.prettierignore +7 -0
- package/.qlty/.gitignore +7 -0
- package/.qlty/configs/.shellcheckrc +1 -0
- package/.qlty/qlty.toml +15 -0
- package/CHANGELOG.md +1898 -0
- package/CONTRIBUTORS.md +34 -0
- package/Dockerfile +50 -0
- package/LICENSE +22 -0
- package/Plugins.md +227 -0
- package/README.md +119 -4
- package/SECURITY.md +178 -0
- package/TODO +22 -0
- package/bin/haraka +593 -0
- package/bin/haraka_grep +32 -0
- package/config/aliases +2 -0
- package/config/auth_flat_file.ini +7 -0
- package/config/auth_vpopmaild.ini +9 -0
- package/config/connection.ini +79 -0
- package/config/delay_deny.ini +7 -0
- package/config/host_list +3 -0
- package/config/host_list_regex +6 -0
- package/config/http.ini +11 -0
- package/config/lmtp.ini +7 -0
- package/config/log.ini +11 -0
- package/config/outbound.bounce_message +18 -0
- package/config/outbound.bounce_message_html +36 -0
- package/config/outbound.bounce_message_image +106 -0
- package/config/outbound.ini +24 -0
- package/config/plugins +67 -0
- package/config/smtp.ini +37 -0
- package/config/smtp_bridge.ini +4 -0
- package/config/smtp_forward.ini +31 -0
- package/config/smtp_proxy.ini +27 -0
- package/config/tarpit.timeout +1 -0
- package/config/tls.ini +83 -0
- package/config/watch.ini +12 -0
- package/config/xclient.hosts +2 -0
- package/connection.js +1865 -0
- package/contrib/Haraka.cf +6 -0
- package/contrib/Haraka.pm +35 -0
- package/contrib/bad_smtp_server.pl +25 -0
- package/contrib/bsd-rc.d/haraka +63 -0
- package/contrib/debian-init.d/haraka +87 -0
- package/contrib/haraka.init +96 -0
- package/contrib/haraka.service +23 -0
- package/contrib/plugin2npm.sh +81 -0
- package/contrib/ubuntu-upstart/haraka.conf +27 -0
- package/docs/Body.md +1 -0
- package/docs/Config.md +1 -0
- package/docs/Connection.md +153 -0
- package/docs/CoreConfig.md +96 -0
- package/docs/CustomReturnCodes.md +3 -0
- package/docs/HAProxy.md +62 -0
- package/docs/Header.md +1 -0
- package/docs/Logging.md +129 -0
- package/docs/Outbound.md +210 -0
- package/docs/Plugins.md +372 -0
- package/docs/Results.md +7 -0
- package/docs/Transaction.md +135 -0
- package/docs/Tutorial.md +183 -0
- package/docs/deprecated/access.md +3 -0
- package/docs/deprecated/backscatterer.md +9 -0
- package/docs/deprecated/connect.rdns_access.md +53 -0
- package/docs/deprecated/data.headers.md +3 -0
- package/docs/deprecated/data.nomsgid.md +7 -0
- package/docs/deprecated/data.noreceived.md +11 -0
- package/docs/deprecated/data.rfc5322_header_checks.md +11 -0
- package/docs/deprecated/dkim_sign.md +97 -0
- package/docs/deprecated/dkim_verify.md +28 -0
- package/docs/deprecated/dnsbl.md +80 -0
- package/docs/deprecated/dnswl.md +73 -0
- package/docs/deprecated/lookup_rdns.strict.md +67 -0
- package/docs/deprecated/mail_from.access.md +52 -0
- package/docs/deprecated/mail_from.blocklist.md +18 -0
- package/docs/deprecated/mail_from.nobounces.md +8 -0
- package/docs/deprecated/rcpt_to.access.md +53 -0
- package/docs/deprecated/rcpt_to.blocklist.md +18 -0
- package/docs/deprecated/rcpt_to.routes.md +3 -0
- package/docs/deprecated/rdns.regexp.md +30 -0
- package/docs/plugins/aliases.md +3 -0
- package/docs/plugins/auth/auth_bridge.md +34 -0
- package/docs/plugins/auth/auth_ldap.md +4 -0
- package/docs/plugins/auth/auth_proxy.md +36 -0
- package/docs/plugins/auth/auth_vpopmaild.md +33 -0
- package/docs/plugins/auth/flat_file.md +40 -0
- package/docs/plugins/block_me.md +18 -0
- package/docs/plugins/data.signatures.md +11 -0
- package/docs/plugins/delay_deny.md +23 -0
- package/docs/plugins/max_unrecognized_commands.md +6 -0
- package/docs/plugins/prevent_credential_leaks.md +22 -0
- package/docs/plugins/process_title.md +42 -0
- package/docs/plugins/queue/deliver.md +3 -0
- package/docs/plugins/queue/discard.md +32 -0
- package/docs/plugins/queue/lmtp.md +24 -0
- package/docs/plugins/queue/qmail-queue.md +16 -0
- package/docs/plugins/queue/quarantine.md +87 -0
- package/docs/plugins/queue/smtp_bridge.md +32 -0
- package/docs/plugins/queue/smtp_forward.md +127 -0
- package/docs/plugins/queue/smtp_proxy.md +68 -0
- package/docs/plugins/queue/test.md +7 -0
- package/docs/plugins/rcpt_to.in_host_list.md +34 -0
- package/docs/plugins/rcpt_to.max_count.md +3 -0
- package/docs/plugins/record_envelope_addresses.md +20 -0
- package/docs/plugins/relay.md +3 -0
- package/docs/plugins/reseed_rng.md +16 -0
- package/docs/plugins/status.md +41 -0
- package/docs/plugins/tarpit.md +50 -0
- package/docs/plugins/tls.md +235 -0
- package/docs/plugins/toobusy.md +27 -0
- package/docs/plugins/xclient.md +10 -0
- package/docs/tutorials/Migrating_from_v1_to_v2.md +96 -0
- package/docs/tutorials/SettingUpOutbound.md +62 -0
- package/eslint.config.mjs +2 -0
- package/haraka.js +74 -0
- package/haraka.sh +2 -0
- package/http/html/404.html +58 -0
- package/http/html/index.html +47 -0
- package/http/package.json +21 -0
- package/line_socket.js +24 -0
- package/logger.js +322 -0
- package/outbound/client_pool.js +59 -0
- package/outbound/config.js +134 -0
- package/outbound/hmail.js +1504 -0
- package/outbound/index.js +349 -0
- package/outbound/qfile.js +93 -0
- package/outbound/queue.js +399 -0
- package/outbound/tls.js +85 -0
- package/outbound/todo.js +17 -0
- package/package.json +100 -4
- package/plugins/.eslintrc.yaml +3 -0
- package/plugins/auth/auth_base.js +261 -0
- package/plugins/auth/auth_bridge.js +20 -0
- package/plugins/auth/auth_proxy.js +227 -0
- package/plugins/auth/auth_vpopmaild.js +162 -0
- package/plugins/auth/flat_file.js +44 -0
- package/plugins/block_me.js +88 -0
- package/plugins/data.signatures.js +30 -0
- package/plugins/delay_deny.js +153 -0
- package/plugins/prevent_credential_leaks.js +61 -0
- package/plugins/process_title.js +197 -0
- package/plugins/profile.js +11 -0
- package/plugins/queue/deliver.js +12 -0
- package/plugins/queue/discard.js +27 -0
- package/plugins/queue/lmtp.js +45 -0
- package/plugins/queue/qmail-queue.js +93 -0
- package/plugins/queue/quarantine.js +133 -0
- package/plugins/queue/smtp_bridge.js +45 -0
- package/plugins/queue/smtp_forward.js +371 -0
- package/plugins/queue/smtp_proxy.js +142 -0
- package/plugins/queue/test.js +15 -0
- package/plugins/rcpt_to.host_list_base.js +65 -0
- package/plugins/rcpt_to.in_host_list.js +56 -0
- package/plugins/record_envelope_addresses.js +17 -0
- package/plugins/reseed_rng.js +7 -0
- package/plugins/status.js +274 -0
- package/plugins/tarpit.js +45 -0
- package/plugins/tls.js +164 -0
- package/plugins/toobusy.js +47 -0
- package/plugins/xclient.js +124 -0
- package/plugins.js +605 -0
- package/run_tests +11 -0
- package/server.js +827 -0
- package/smtp_client.js +504 -0
- package/test/.eslintrc.yaml +11 -0
- package/test/config/auth_flat_file.ini +5 -0
- package/test/config/block_me.recipient +1 -0
- package/test/config/block_me.senders +1 -0
- package/test/config/dhparams.pem +8 -0
- package/test/config/host_list +2 -0
- package/test/config/outbound_tls_cert.pem +1 -0
- package/test/config/outbound_tls_key.pem +1 -0
- package/test/config/plugins +7 -0
- package/test/config/smtp.ini +11 -0
- package/test/config/smtp_forward.ini +30 -0
- package/test/config/tls/example.com/_.example.com.key +28 -0
- package/test/config/tls/example.com/example.com.crt +25 -0
- package/test/config/tls/haraka.local.pem +51 -0
- package/test/config/tls.ini +45 -0
- package/test/config/tls_cert.pem +21 -0
- package/test/config/tls_key.pem +28 -0
- package/test/connection.js +820 -0
- package/test/fixtures/haproxy_allowed/config/connection.ini +3 -0
- package/test/fixtures/haproxy_disabled/config/connection.ini +3 -0
- package/test/fixtures/haproxy_untrusted/config/connection.ini +3 -0
- package/test/fixtures/line_socket.js +21 -0
- package/test/fixtures/todo_qfile.txt +0 -0
- package/test/fixtures/util_hmailitem.js +156 -0
- package/test/installation/config/test-plugin-flat +1 -0
- package/test/installation/config/test-plugin.ini +10 -0
- package/test/installation/config/tls.ini +1 -0
- package/test/installation/node_modules/load_first/index.js +5 -0
- package/test/installation/node_modules/load_first/package.json +11 -0
- package/test/installation/node_modules/test-plugin/config/test-plugin-flat +1 -0
- package/test/installation/node_modules/test-plugin/config/test-plugin.ini +9 -0
- package/test/installation/node_modules/test-plugin/package.json +5 -0
- package/test/installation/node_modules/test-plugin/test-plugin.js +5 -0
- package/test/installation/plugins/base_plugin.js +3 -0
- package/test/installation/plugins/folder_plugin/index.js +3 -0
- package/test/installation/plugins/folder_plugin/package.json +11 -0
- package/test/installation/plugins/inherits.js +7 -0
- package/test/installation/plugins/load_first.js +3 -0
- package/test/installation/plugins/plugin.js +1 -0
- package/test/installation/plugins/tls.js +3 -0
- package/test/logger.js +217 -0
- package/test/loud/config/dhparams.pem +0 -0
- package/test/loud/config/tls/goobered.pem +45 -0
- package/test/loud/config/tls.ini +43 -0
- package/test/mail_specimen/base64-root-part.txt +23 -0
- package/test/mail_specimen/varied-fold-lengths-preserve-data.txt +283 -0
- package/test/outbound/bounce_net_errors.js +133 -0
- package/test/outbound/bounce_rfc3464.js +226 -0
- package/test/outbound/hmail.js +210 -0
- package/test/outbound/index.js +385 -0
- package/test/outbound/qfile.js +124 -0
- package/test/outbound/queue.js +325 -0
- package/test/plugins/auth/auth_base.js +620 -0
- package/test/plugins/auth/auth_bridge.js +80 -0
- package/test/plugins/auth/auth_vpopmaild.js +81 -0
- package/test/plugins/auth/flat_file.js +123 -0
- package/test/plugins/block_me.js +141 -0
- package/test/plugins/data.signatures.js +111 -0
- package/test/plugins/delay_deny.js +262 -0
- package/test/plugins/prevent_credential_leaks.js +174 -0
- package/test/plugins/process_title.js +141 -0
- package/test/plugins/queue/deliver.js +98 -0
- package/test/plugins/queue/discard.js +78 -0
- package/test/plugins/queue/lmtp.js +137 -0
- package/test/plugins/queue/qmail-queue.js +98 -0
- package/test/plugins/queue/quarantine.js +80 -0
- package/test/plugins/queue/smtp_bridge.js +152 -0
- package/test/plugins/queue/smtp_forward.js +1023 -0
- package/test/plugins/queue/smtp_proxy.js +138 -0
- package/test/plugins/rcpt_to.host_list_base.js +102 -0
- package/test/plugins/rcpt_to.in_host_list.js +186 -0
- package/test/plugins/record_envelope_addresses.js +66 -0
- package/test/plugins/reseed_rng.js +34 -0
- package/test/plugins/status.js +207 -0
- package/test/plugins/tarpit.js +90 -0
- package/test/plugins/tls.js +86 -0
- package/test/plugins/toobusy.js +198 -0
- package/test/plugins/xclient.js +119 -0
- package/test/plugins.js +230 -0
- package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
- package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
- package/test/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
- package/test/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
- package/test/queue/zero-length +0 -0
- package/test/server.js +1012 -0
- package/test/smtp_client.js +1303 -0
- package/test/tls_socket.js +321 -0
- package/test/transaction.js +554 -0
- package/tls_socket.js +771 -0
- package/transaction.js +267 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Core Configuration Files
|
|
2
|
+
|
|
3
|
+
Haraka reads the configuration files in this document directly. Plugins typically own their own files (named after the plugin); see the individual plugin docs.
|
|
4
|
+
|
|
5
|
+
See also [Logging](Logging.md), [HAProxy](HAProxy.md), and [Outbound](Outbound.md).
|
|
6
|
+
|
|
7
|
+
## smtp.yaml / smtp.json
|
|
8
|
+
|
|
9
|
+
If either of these files exists it is loaded first. It uses the YAML/JSON override mechanism from [haraka-config](https://github.com/haraka/haraka-config) and can provide the entire configuration as a single file.
|
|
10
|
+
|
|
11
|
+
## plugins
|
|
12
|
+
|
|
13
|
+
A newline-delimited list of plugins to load. Lines starting with `#` are ignored.
|
|
14
|
+
|
|
15
|
+
## smtp.ini
|
|
16
|
+
|
|
17
|
+
Controls the SMTP listener and the master process.
|
|
18
|
+
|
|
19
|
+
| Key | Default | Description |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| `listen` | `[::0]:25` | Comma-separated `IP:port` pairs to listen on (e.g. `127.0.0.1:25,127.0.0.1:587`). |
|
|
22
|
+
| `listen_host` / `port` | — | Legacy. If set, a `<listen_host>:<port>` entry is prepended to `listen`. Prefer `listen`. |
|
|
23
|
+
| `smtps_port` | `465` | Port used by the optional implicit-TLS listener. |
|
|
24
|
+
| `public_ip` | none | The server's public IP. Helps NAT-aware plugins (SPF, GeoIP) when Haraka is behind NAT. If `stun` is on `$PATH` Haraka will try to discover it automatically. |
|
|
25
|
+
| `inactivity_timeout` | `300` | Idle seconds before a client socket is dropped. |
|
|
26
|
+
| `nodes` | `1` | Number of worker processes to fork. The string `cpus` forks one per CPU. |
|
|
27
|
+
| `user` / `group` | — | User and group to drop privileges to (name or numeric ID). |
|
|
28
|
+
| `ignore_bad_plugins` | `0` | If `1`, Haraka starts even if some plugins fail to compile. |
|
|
29
|
+
| `daemonize` | `false` | If `true`, fork into the background at start-up. |
|
|
30
|
+
| `daemon_log_file` | `/var/log/haraka.log` | Where to redirect stdout/stderr when daemonized. |
|
|
31
|
+
| `daemon_pid_file` | `/var/run/haraka.pid` | Where to write the PID file. |
|
|
32
|
+
| `graceful_shutdown` | `false` | If `true`, wait for in-flight sockets on shutdown. |
|
|
33
|
+
| `force_shutdown_timeout` | `30` | Seconds to wait before forcing shutdown. |
|
|
34
|
+
|
|
35
|
+
## me
|
|
36
|
+
|
|
37
|
+
A single-line file containing the server name used in `Received:` headers
|
|
38
|
+
and elsewhere. Defaults to `hostname(1)`.
|
|
39
|
+
|
|
40
|
+
## connection.ini
|
|
41
|
+
|
|
42
|
+
Per-connection limits and behaviours. See inline comments in the shipped
|
|
43
|
+
`config/connection.ini` for full details.
|
|
44
|
+
|
|
45
|
+
| Section / Key | Default | Description |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| `main.spool_dir` | `/tmp` | Directory for temporary spool files. |
|
|
48
|
+
| `main.spool_after` | `-1` | Size (bytes) at which to spool the message to disk. `-1` never spools; `0` always spools. |
|
|
49
|
+
| `main.strict_rfc1869` | `false` | Reject `MAIL FROM` / `RCPT TO` that violates RFC 1869/821 (spurious spaces, missing brackets). |
|
|
50
|
+
| `main.smtputf8` | `true` | Advertise `SMTPUTF8` (RFC 6531). |
|
|
51
|
+
| `main.postel` | `false` | Liberal envelope parsing. |
|
|
52
|
+
| `haproxy.enabled` | `true` | Enable HAProxy PROXY protocol handling. Set `false` to bypass PROXY support. |
|
|
53
|
+
| `haproxy.hosts` | empty | Array of IPs/CIDRs allowed to send the PROXY protocol. See [HAProxy.md](HAProxy.md). |
|
|
54
|
+
| `headers.add_received` | `true` | Add a `Received:` header to incoming mail. |
|
|
55
|
+
| `headers.clean_auth_results` | `true` | Strip inbound `Authentication-Results:` headers before plugins run. |
|
|
56
|
+
| `headers.show_version` | `true` | Include the Haraka version in the SMTP banner and the `Received:` header. |
|
|
57
|
+
| `headers.max_lines` | `1000` | Maximum number of header lines accepted. |
|
|
58
|
+
| `headers.max_received` | `100` | Maximum number of `Received:` headers before mail is rejected as looping. |
|
|
59
|
+
| `max.bytes` | `26214400` | Maximum message size (advertised as the `SIZE` ESMTP extension). |
|
|
60
|
+
| `max.line_length` | `512` | SMTP command line length cap. Clients exceeding this are dropped with `521`. |
|
|
61
|
+
| `max.data_line_length` | `992` | Maximum line length in `DATA`. Longer lines are wrapped with `CRLF SPACE` (Sendmail behaviour) and `transaction.notes.data_line_length_exceeded` is set. |
|
|
62
|
+
| `max.mime_parts` | `1000` | Maximum MIME parts per message. |
|
|
63
|
+
| `message.greeting` | — | Array. Lines used as the SMTP greeting banner. |
|
|
64
|
+
| `message.helo` | `Haraka is at your service.` | Reply text for `HELO` / `EHLO`. |
|
|
65
|
+
| `message.close` | `closing connection. …` | Reply text on `QUIT`. |
|
|
66
|
+
| `uuid.banner_chars` | `6` | Number of UUID chars included in the SMTP banner (`0` to disable, `40` for the full UUID). |
|
|
67
|
+
| `uuid.deny_chars` | `0` | Number of UUID chars prepended (in brackets) to deny messages. |
|
|
68
|
+
|
|
69
|
+
## plugin_timeout
|
|
70
|
+
|
|
71
|
+
Single-integer file. Seconds to allow a plugin hook to run before Haraka
|
|
72
|
+
automatically advances to the next hook. Default: `30`.
|
|
73
|
+
|
|
74
|
+
A per-plugin override may be placed at `config/<plugin>.timeout`. A value
|
|
75
|
+
of `0` disables the timeout for that plugin — use with care. Plugins in
|
|
76
|
+
subdirectories need a matching path: `queue/smtp_forward` looks for
|
|
77
|
+
`config/queue/smtp_forward.timeout`.
|
|
78
|
+
|
|
79
|
+
## outbound.ini
|
|
80
|
+
|
|
81
|
+
Configures the outbound delivery engine. The most common keys are listed
|
|
82
|
+
below; see [Outbound.md](Outbound.md) for the full set.
|
|
83
|
+
|
|
84
|
+
| Key | Default | Description |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `disabled` | `false` | Disable outbound delivery entirely. |
|
|
87
|
+
| `concurrency_max` | `100` | Maximum simultaneous outbound deliveries. |
|
|
88
|
+
| `enable_tls` | `true` | Use STARTTLS opportunistically on outbound deliveries. |
|
|
89
|
+
| `maxTempFailures` | `13` | Number of temporary failures before a message bounces. |
|
|
90
|
+
| `always_split` | `false` | Create one queue file per recipient instead of one per destination domain. |
|
|
91
|
+
| `received_header` | `Haraka outbound` | Value used in the outbound `Received:` header. |
|
|
92
|
+
| `inet_prefer` | `default` | IP family preference for MX lookups: `v4`, `v6`, or `default` (OS preference). |
|
|
93
|
+
|
|
94
|
+
## outbound.bounce_message
|
|
95
|
+
|
|
96
|
+
Template used when an outbound message bounces. The default is usually fine. Available template variables are documented in the source of `outbound/hmail.js`.
|
package/docs/HAProxy.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# HAProxy PROXY Protocol Support
|
|
2
|
+
|
|
3
|
+
Haraka supports version 1 (text format) of the HAProxy [PROXY protocol][proxy-spec], which allows an upstream proxy to tell Haraka the real client IP and port. DNSBLs, allow-lists, and other IP-based plugins then see the original client rather than the proxy.
|
|
4
|
+
|
|
5
|
+
The PROXY v2 binary header is not currently supported.
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
PROXY support is enabled by default, but inactive until trusted proxy IPs or CIDRs are listed in `connection.ini`:
|
|
10
|
+
|
|
11
|
+
```ini
|
|
12
|
+
[haproxy]
|
|
13
|
+
enabled=true
|
|
14
|
+
hosts[] = 192.0.2.4
|
|
15
|
+
hosts[] = 192.0.2.5/30
|
|
16
|
+
hosts[] = 2001:db8::1
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Set `enabled=false` to disable PROXY protocol handling entirely. On SMTPS listeners this bypasses pre-TLS PROXY parsing and uses the standard implicit TLS server.
|
|
20
|
+
|
|
21
|
+
Connections from any other IP get a `DENYSOFTDISCONNECT` if they send a `PROXY` command. `DENYSOFT` is deliberate — it avoids permanently rejecting valid mail when a misconfiguration causes a legitimate proxy to fall outside the allow-list.
|
|
22
|
+
|
|
23
|
+
When a listed proxy connects, Haraka **does not** send the SMTP banner; it waits for the `PROXY` command. If none arrives within 30 seconds the connection is closed with `421 PROXY timed out`.
|
|
24
|
+
|
|
25
|
+
## What plugins see after PROXY is parsed
|
|
26
|
+
|
|
27
|
+
| Property | Value |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `connection.remote.ip` / `.port` | the **real** client address from the PROXY header |
|
|
30
|
+
| `connection.local.ip` / `.port` | the destination IP/port from the PROXY header |
|
|
31
|
+
| `connection.proxy.allowed` | `true` |
|
|
32
|
+
| `connection.proxy.ip` | the proxy's address (i.e. the original socket peer) |
|
|
33
|
+
| `connection.proxy.type` | `'haproxy'` |
|
|
34
|
+
| `connection.notes.proxy` | full parsed record: `{ type, proto, src_ip, src_port, dst_ip, dst_port, proxy_ip }` |
|
|
35
|
+
|
|
36
|
+
## HAProxy configuration
|
|
37
|
+
|
|
38
|
+
You need HAProxy ≥ 1.5. The `send-proxy` option on each backend server tells HAProxy to emit the v1 header on every connection.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
listen smtp :25
|
|
42
|
+
mode tcp
|
|
43
|
+
option tcplog
|
|
44
|
+
balance roundrobin
|
|
45
|
+
server smtp1 ip.of.haraka1:25 check-send-proxy check inter 10s send-proxy
|
|
46
|
+
server smtp2 ip.of.haraka2:25 check-send-proxy check inter 10s send-proxy
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `check-send-proxy` flag is required for HAProxy's health checks because Haraka does not respond with a banner before the PROXY header arrives.
|
|
50
|
+
|
|
51
|
+
### Health checks
|
|
52
|
+
|
|
53
|
+
`option smtpchk` drops the connection mid-handshake and shows up as `CONNRESET` in Haraka's logs. A cleaner check is to use `tcp-check` and politely close with `QUIT`:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
option tcp-check
|
|
57
|
+
tcp-check expect rstring ^220
|
|
58
|
+
tcp-check send QUIT\r\n
|
|
59
|
+
tcp-check expect rstring ^221
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
[proxy-spec]: https://www.haproxy.org/download/2.8/doc/proxy-protocol.txt
|
package/docs/Header.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
moved to [Header](https://github.com/haraka/email-message#header)
|
package/docs/Logging.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Haraka Logging
|
|
2
|
+
|
|
3
|
+
Haraka has a built-in logger (described below) and a plugin hook (`log`) that lets log plugins ship messages elsewhere — for example to syslog via [haraka-plugin-syslog](https://github.com/haraka/haraka-plugin-syslog).
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
### log.ini
|
|
8
|
+
|
|
9
|
+
```ini
|
|
10
|
+
[main]
|
|
11
|
+
; data, protocol, debug, info, notice, warn, error, crit, alert, emerg
|
|
12
|
+
level=info
|
|
13
|
+
|
|
14
|
+
; prepend ISO-8601 timestamps to log entries (built-in logger only)
|
|
15
|
+
timestamps=false
|
|
16
|
+
|
|
17
|
+
; default, logfmt, json
|
|
18
|
+
format=default
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### loglevel
|
|
22
|
+
|
|
23
|
+
A single-line file for quick CLI tweaks:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
echo DEBUG > config/loglevel
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
When both `log.ini` and the `loglevel` file are present, whichever was edited most recently wins at runtime — `loglevel` is convenient for an interactive bump without touching `log.ini`.
|
|
30
|
+
|
|
31
|
+
### log_timestamps
|
|
32
|
+
|
|
33
|
+
A single-value file that toggles timestamp prepending. Equivalent to `main.timestamps` in `log.ini`. If either source enables timestamps, they are enabled.
|
|
34
|
+
|
|
35
|
+
## Log Levels
|
|
36
|
+
|
|
37
|
+
In ascending severity (and decreasing verbosity):
|
|
38
|
+
|
|
39
|
+
| Level | Numeric | Use |
|
|
40
|
+
| -------- | ------- | --- |
|
|
41
|
+
| DATA | 9 | message body bytes — extremely verbose |
|
|
42
|
+
| PROTOCOL | 8 | SMTP wire protocol |
|
|
43
|
+
| DEBUG | 7 | developer diagnostics |
|
|
44
|
+
| INFO | 6 | general informational |
|
|
45
|
+
| NOTICE | 5 | normal but significant events (connect/disconnect, summary lines) |
|
|
46
|
+
| WARN | 4 | recoverable problems |
|
|
47
|
+
| ERROR | 3 | non-fatal errors |
|
|
48
|
+
| CRIT | 2 | critical errors |
|
|
49
|
+
| ALERT | 1 | needs immediate attention |
|
|
50
|
+
| EMERG | 0 | unusable |
|
|
51
|
+
|
|
52
|
+
A message is emitted when its level ≤ the configured level.
|
|
53
|
+
|
|
54
|
+
## Logging API
|
|
55
|
+
|
|
56
|
+
Every log call ultimately produces:
|
|
57
|
+
|
|
58
|
+
[level] [uuid] [origin] message
|
|
59
|
+
|
|
60
|
+
`origin` is `core` or the plugin name; `uuid` is the connection UUID (with `.N` appended for the Nth transaction).
|
|
61
|
+
|
|
62
|
+
The simplest call is on the connection or plugin object — origin and uuid are filled in automatically:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
connection.logdebug('turtles all the way down')
|
|
66
|
+
plugin.loginfo('checking sender', connection)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Each of the level names has a matching method:
|
|
70
|
+
`logdata`, `logprotocol`, `logdebug`, `loginfo`, `lognotice`, `logwarn`,
|
|
71
|
+
`logerror`, `logcrit`, `logalert`, `logemerg`.
|
|
72
|
+
|
|
73
|
+
Calling the logger directly works too — pass the plugin and/or connection anywhere in the arguments and the logger sniffs them:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
logger.logdebug('i like turtles', plugin, connection)
|
|
77
|
+
// → [DEBUG] [7F1C820F-…] [dnsbl] i like turtles
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Plain objects mixed into the arguments are merged into the log record (in `logfmt` / `json` formats) or stringified (`key=value` pairs in the default format).
|
|
81
|
+
|
|
82
|
+
## Log Formats
|
|
83
|
+
|
|
84
|
+
Set `main.format` in `log.ini` to one of `default`, `logfmt`, or `json`.
|
|
85
|
+
|
|
86
|
+
`logfmt`:
|
|
87
|
+
|
|
88
|
+
level=PROTOCOL uuid=9FF7F70E-…1 source=core message="S: 354 go ahead, make my day"
|
|
89
|
+
|
|
90
|
+
`json`:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"level": "PROTOCOL",
|
|
95
|
+
"uuid": "9FF7F70E-…1",
|
|
96
|
+
"source": "core",
|
|
97
|
+
"message": "S: 354 go ahead, make my day"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
A typical structured disconnect line looks like:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"level": "NOTICE",
|
|
106
|
+
"uuid": "9FF7F70E-…1",
|
|
107
|
+
"source": "core",
|
|
108
|
+
"message": "disconnect",
|
|
109
|
+
"ip": "127.0.0.1",
|
|
110
|
+
"rdns": "Unknown",
|
|
111
|
+
"helo": "3h2dnz8a0if",
|
|
112
|
+
"relay": "N",
|
|
113
|
+
"early": "N",
|
|
114
|
+
"esmtp": "N",
|
|
115
|
+
"tls": "N",
|
|
116
|
+
"pipe": "N",
|
|
117
|
+
"errors": 0,
|
|
118
|
+
"txns": 1,
|
|
119
|
+
"rcpts": "1/0/0",
|
|
120
|
+
"msgs": "1/0/0",
|
|
121
|
+
"bytes": 222,
|
|
122
|
+
"lr": "",
|
|
123
|
+
"time": 0.052
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## The `log` hook
|
|
128
|
+
|
|
129
|
+
Each log message becomes a `log` hook invocation. The built-in handler writes to stdout (with ANSI colour when stdout is a TTY); log plugins can return `OK` or `STOP` to suppress the built-in output and ship the message elsewhere. Messages emitted before plugins finish loading are buffered and replayed once the plugin chain is ready.
|
package/docs/Outbound.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Outbound Mail with Haraka
|
|
2
|
+
|
|
3
|
+
A default Haraka installation queues outbound mail to disk and delivers it to the appropriate MX for each recipient domain. Temporary failures are retried automatically using the configured backoff schedule.
|
|
4
|
+
|
|
5
|
+
A mail is treated as outbound when a plugin sets `connection.relaying` to `true`. The simplest way is SMTP AUTH using `auth/flat_file` or one of the [auth plugins](plugins/auth/); the `relay` plugin offers allow-list-based variants, and a custom plugin can apply any policy.
|
|
6
|
+
|
|
7
|
+
For live stats on the outbound queue see the [`process_title`](plugins/process_title.md) plugin.
|
|
8
|
+
|
|
9
|
+
To flush the temp-fail queue (e.g. after fixing network or DNS), send `SIGHUP` to the Haraka master process.
|
|
10
|
+
|
|
11
|
+
## Outbound Configuration
|
|
12
|
+
|
|
13
|
+
### outbound.ini
|
|
14
|
+
|
|
15
|
+
| Key | Default | Description |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `disabled` | `false` | Pause outbound delivery while still queuing inbound mail. Reloadable at runtime. |
|
|
18
|
+
| `concurrency_max` | `10000` | Maximum concurrent outbound deliveries **per worker**. Effective total is `concurrency_max × nodes`. |
|
|
19
|
+
| `enable_tls` | `true` | Use opportunistic STARTTLS on outbound. |
|
|
20
|
+
| `maxTempFailures` | `13` | Maximum temp-fail retries before the message bounces. Ignored if `temp_fail_intervals` is set. |
|
|
21
|
+
| `temp_fail_intervals` | derived | Comma-separated `<n><unit>[*<count>]` pattern. `1m, 5m*2, 1h*3` → `[60,300,300,3600,3600,3600]` seconds. `none` bounces on first temp-fail. |
|
|
22
|
+
| `always_split` | `false` | Create one queue file per recipient (instead of one per destination domain). Hurts throughput but simplifies bounce handling. |
|
|
23
|
+
| `received_header` | `Haraka outbound` | Text used in the outbound `Received:` header. Set to the literal `disabled` to omit it. |
|
|
24
|
+
| `connect_timeout` | `30` | Seconds to wait for TCP connect to the remote MX. |
|
|
25
|
+
| `local_mx_ok` | `false` | Allow outbound delivery to local/private IPs (otherwise blocked to prevent loops). |
|
|
26
|
+
| `inet_prefer` | `default` | `default` (prefer IPv6 at equal MX priority), `v4`, or `v6`. Delivery still follows MX priority. |
|
|
27
|
+
|
|
28
|
+
TLS configuration is shared with the `tls` plugin (`tls_key.pem`, `tls_cert.pem`, and `tls.ini`). Outbound-specific overrides go under `[outbound]` in `tls.ini`:
|
|
29
|
+
|
|
30
|
+
```ini
|
|
31
|
+
[outbound]
|
|
32
|
+
ciphers=!DES
|
|
33
|
+
minVersion=TLSv1.2
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### outbound.bounce_message
|
|
37
|
+
|
|
38
|
+
Template for the bounce message body. See "Bounce Messages" below.
|
|
39
|
+
|
|
40
|
+
## The HMail Object
|
|
41
|
+
|
|
42
|
+
Most outbound hooks pass an `hmail` (HMailItem). You rarely need its methods, but these properties are useful:
|
|
43
|
+
|
|
44
|
+
| Property | Description |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `path` | Full filesystem path to the queue file. |
|
|
47
|
+
| `filename` | Queue file's base name. |
|
|
48
|
+
| `num_failures` | Number of temp-fail attempts so far. |
|
|
49
|
+
| `notes` | Plain object for plugin state, scoped to this queue item. |
|
|
50
|
+
| `todo` | The `TODOItem` describing what to deliver (see below). |
|
|
51
|
+
|
|
52
|
+
## The TODO Object
|
|
53
|
+
|
|
54
|
+
`hmail.todo` describes the delivery:
|
|
55
|
+
|
|
56
|
+
| Property | Description |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `mail_from` | `Address`<sup>[1](#fn1)</sup> — the envelope sender. |
|
|
59
|
+
| `rcpt_to` | `Address`<sup>[1](#fn1)</sup> array — envelope recipients. |
|
|
60
|
+
| `domain` | Recipient domain (a single domain unless `always_split` is set). |
|
|
61
|
+
| `notes` | The original `transaction.notes`. Keys you may set: |
|
|
62
|
+
| `notes.outbound_ip` | IP to bind the outbound socket to. **Set via the `get_mx` hook**, not directly. |
|
|
63
|
+
| `notes.outbound_helo` | EHLO domain. **Set via the `get_mx` hook**, not directly. |
|
|
64
|
+
| `queue_time` | When the mail was queued (epoch ms). |
|
|
65
|
+
| `uuid` | Inherited from the source `transaction.uuid`. |
|
|
66
|
+
| `force_tls` | If `true`, defer instead of delivering in plaintext. |
|
|
67
|
+
|
|
68
|
+
## Outbound Hooks
|
|
69
|
+
|
|
70
|
+
### queue_outbound
|
|
71
|
+
|
|
72
|
+
Runs before queuing. Returning `CONT` (or having no hook) queues the mail. `OK` indicates the plugin queued it itself; the `DENY*` codes reject the message.
|
|
73
|
+
|
|
74
|
+
### pre_send_trans_email
|
|
75
|
+
|
|
76
|
+
Parameters: `next, connection`
|
|
77
|
+
|
|
78
|
+
Fired by `outbound.send_trans_email()` before the transaction is serialized to disk. Useful for plugins that synthesize mail programmatically — they can attach final headers or notes here.
|
|
79
|
+
|
|
80
|
+
### send_email
|
|
81
|
+
|
|
82
|
+
Parameters: `next, hmail`
|
|
83
|
+
|
|
84
|
+
Called just before delivery starts. `next(DELAY, seconds)` defers the attempt.
|
|
85
|
+
|
|
86
|
+
### get_mx
|
|
87
|
+
|
|
88
|
+
Parameters: `next, hmail, domain`
|
|
89
|
+
|
|
90
|
+
Called when delivery begins, with the destination domain. Plugins can override MX lookup; most installs leave Haraka to do DNS. Respond with `next(OK, mx)` where `mx` is a [HarakaMx][url-harakamx] object, an array of them, or any HarakaMx-compatible input. Set `mx.auth_user` / `mx.auth_pass` to AUTH against the remote, or `mx.bind` / `mx.bind_helo`
|
|
91
|
+
to control source address and EHLO.
|
|
92
|
+
|
|
93
|
+
### deferred
|
|
94
|
+
|
|
95
|
+
Parameters: `next, hmail, { delay, err }`
|
|
96
|
+
|
|
97
|
+
Fired on temporary failure. Return `OK` to drop the mail silently; return `DENYSOFT, seconds` to override the retry delay (useful for custom backoff indexed on `hmail.num_failures`).
|
|
98
|
+
|
|
99
|
+
### bounce
|
|
100
|
+
|
|
101
|
+
Parameters: `next, hmail, error`
|
|
102
|
+
|
|
103
|
+
Fired on permanent failure (5xx). Not called for temp-fails. `error` may carry:
|
|
104
|
+
|
|
105
|
+
- `mx` — the MX that caused the bounce
|
|
106
|
+
- `deferred_rcpt` — recipients that eventually bounced after deferrals
|
|
107
|
+
- `bounced_rcpt` — recipients that bounced outright
|
|
108
|
+
|
|
109
|
+
Return `OK` to suppress the DSN to the original sender.
|
|
110
|
+
|
|
111
|
+
### delivered
|
|
112
|
+
|
|
113
|
+
Parameters: `next, hmail, [host, ip, response, delay, port, mode, ok_recips, secured, authenticated]`
|
|
114
|
+
|
|
115
|
+
Fired after a successful delivery. Return codes are ignored; the hook is for logging / accounting.
|
|
116
|
+
|
|
117
|
+
| Element | Description |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `host` | Hostname of the receiving MX. |
|
|
120
|
+
| `ip` | IP we delivered to. |
|
|
121
|
+
| `response` | Remote SMTP response text (typically includes the remote queue ID). |
|
|
122
|
+
| `delay` | Seconds between queue write and delivery. |
|
|
123
|
+
| `port` | Destination port. |
|
|
124
|
+
| `mode` | `'smtp'` or `'lmtp'`. |
|
|
125
|
+
| `ok_recips` | `Address`<sup>[1](#fn1)</sup> array of successfully delivered recipients. |
|
|
126
|
+
| `secured` | `true` if STARTTLS succeeded. |
|
|
127
|
+
| `authenticated` | `true` if outbound AUTH succeeded. |
|
|
128
|
+
|
|
129
|
+
## Outbound IP Address
|
|
130
|
+
|
|
131
|
+
By default the OS routing table chooses the source IP. To pin outbound to a specific IP (per-sender, per-domain, etc.), bind that address to a local interface or alias, then set `mx.bind` (source IP) and `mx.bind_helo` (EHLO domain) in your `get_mx` hook.
|
|
132
|
+
|
|
133
|
+
## Outbound AUTH
|
|
134
|
+
|
|
135
|
+
Force AUTH for a domain or smart host by returning an MX with `auth_user` and `auth_pass` set from the `get_mx` hook. If the remote end does not advertise AUTH (or no compatible mechanism is found), delivery proceeds without AUTH and a warning is logged.
|
|
136
|
+
|
|
137
|
+
## Bounce Messages
|
|
138
|
+
|
|
139
|
+
The bounce body comes from `config/outbound.bounce_message`. Curly-brace template variables are filled in at bounce time:
|
|
140
|
+
|
|
141
|
+
- `pid` — current process id
|
|
142
|
+
- `date` — bounce timestamp
|
|
143
|
+
- `me` — contents of `config/me`
|
|
144
|
+
- `from` — original sender
|
|
145
|
+
- `msgid` — original message UUID
|
|
146
|
+
- `to` — original recipient (or first, for multi-recipient mail)
|
|
147
|
+
- `reason` — remote server's rejection text
|
|
148
|
+
|
|
149
|
+
The original message is appended to the bounce.
|
|
150
|
+
|
|
151
|
+
For HTML bounces, add `config/outbound.bounce_message_html` (and optionally an inline image in `config/outbound.bounce_message_image`).
|
|
152
|
+
|
|
153
|
+
## Generating Mail from a Plugin
|
|
154
|
+
|
|
155
|
+
To create and queue a new message from inside a plugin, use the `outbound` module:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
const outbound = require('./outbound')
|
|
159
|
+
|
|
160
|
+
const from = 'sender@example.com'
|
|
161
|
+
const to = 'user@example.com'
|
|
162
|
+
|
|
163
|
+
const contents = [
|
|
164
|
+
`From: ${from}`,
|
|
165
|
+
`To: ${to}`,
|
|
166
|
+
'MIME-Version: 1.0',
|
|
167
|
+
'Content-Type: text/plain; charset=us-ascii',
|
|
168
|
+
'Subject: Hello',
|
|
169
|
+
'',
|
|
170
|
+
'Body here.',
|
|
171
|
+
'',
|
|
172
|
+
].join('\n')
|
|
173
|
+
|
|
174
|
+
outbound.send_email(from, to, contents, (code, msg) => {
|
|
175
|
+
switch (code) {
|
|
176
|
+
case OK:
|
|
177
|
+
plugin.loginfo('queued')
|
|
178
|
+
break
|
|
179
|
+
case DENY:
|
|
180
|
+
plugin.logerror(`queue failed: ${msg}`)
|
|
181
|
+
break
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The callback fires when the mail is **queued**, not delivered — hook `delivered` and `bounce` to observe delivery outcomes.
|
|
187
|
+
|
|
188
|
+
The callback may be omitted if you don't need to handle queue failure:
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
outbound.send_email(from, to, contents)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Options accepted by `send_email(from, to, contents, next, options)`:
|
|
195
|
+
|
|
196
|
+
| Option | Description |
|
|
197
|
+
| --- | --- |
|
|
198
|
+
| `dot_stuffed: true` | Content is already SMTP dot-stuffed. |
|
|
199
|
+
| `notes: { … }` | Seed the new transaction's `notes`. |
|
|
200
|
+
| `remove_msgid: true` | Drop any existing `Message-Id:` so Haraka generates one. Useful when releasing from quarantine. |
|
|
201
|
+
| `remove_date: true` | Drop any existing `Date:` so Haraka generates one. |
|
|
202
|
+
| `origin: <object>` | Object passed to the logger to identify the source plugin / connection / HMailItem. |
|
|
203
|
+
|
|
204
|
+
To send an already-built `Transaction` directly, use `outbound.send_trans_email(transaction, next)`. This is what `send_email()` calls internally and fires the `pre_send_trans_email` hook.
|
|
205
|
+
|
|
206
|
+
<a name="fn1">1</a>: `Address` objects are [@haraka/email-address](https://github.com/haraka/email-address) objects.
|
|
207
|
+
|
|
208
|
+
[url-tls]: plugins/tls.md
|
|
209
|
+
[url-harakamx]: https://github.com/haraka/haraka-net-utils?tab=readme-ov-file#harakamx
|
|
210
|
+
[url-rfc2821]: https://tools.ietf.org/html/rfc2821#section-4.5.2
|