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.
Files changed (254) hide show
  1. package/.githooks/pre-commit +41 -0
  2. package/.prettierignore +7 -0
  3. package/.qlty/.gitignore +7 -0
  4. package/.qlty/configs/.shellcheckrc +1 -0
  5. package/.qlty/qlty.toml +15 -0
  6. package/CHANGELOG.md +1898 -0
  7. package/CONTRIBUTORS.md +34 -0
  8. package/Dockerfile +50 -0
  9. package/LICENSE +22 -0
  10. package/Plugins.md +227 -0
  11. package/README.md +119 -4
  12. package/SECURITY.md +178 -0
  13. package/TODO +22 -0
  14. package/bin/haraka +593 -0
  15. package/bin/haraka_grep +32 -0
  16. package/config/aliases +2 -0
  17. package/config/auth_flat_file.ini +7 -0
  18. package/config/auth_vpopmaild.ini +9 -0
  19. package/config/connection.ini +79 -0
  20. package/config/delay_deny.ini +7 -0
  21. package/config/host_list +3 -0
  22. package/config/host_list_regex +6 -0
  23. package/config/http.ini +11 -0
  24. package/config/lmtp.ini +7 -0
  25. package/config/log.ini +11 -0
  26. package/config/outbound.bounce_message +18 -0
  27. package/config/outbound.bounce_message_html +36 -0
  28. package/config/outbound.bounce_message_image +106 -0
  29. package/config/outbound.ini +24 -0
  30. package/config/plugins +67 -0
  31. package/config/smtp.ini +37 -0
  32. package/config/smtp_bridge.ini +4 -0
  33. package/config/smtp_forward.ini +31 -0
  34. package/config/smtp_proxy.ini +27 -0
  35. package/config/tarpit.timeout +1 -0
  36. package/config/tls.ini +83 -0
  37. package/config/watch.ini +12 -0
  38. package/config/xclient.hosts +2 -0
  39. package/connection.js +1865 -0
  40. package/contrib/Haraka.cf +6 -0
  41. package/contrib/Haraka.pm +35 -0
  42. package/contrib/bad_smtp_server.pl +25 -0
  43. package/contrib/bsd-rc.d/haraka +63 -0
  44. package/contrib/debian-init.d/haraka +87 -0
  45. package/contrib/haraka.init +96 -0
  46. package/contrib/haraka.service +23 -0
  47. package/contrib/plugin2npm.sh +81 -0
  48. package/contrib/ubuntu-upstart/haraka.conf +27 -0
  49. package/docs/Body.md +1 -0
  50. package/docs/Config.md +1 -0
  51. package/docs/Connection.md +153 -0
  52. package/docs/CoreConfig.md +96 -0
  53. package/docs/CustomReturnCodes.md +3 -0
  54. package/docs/HAProxy.md +62 -0
  55. package/docs/Header.md +1 -0
  56. package/docs/Logging.md +129 -0
  57. package/docs/Outbound.md +210 -0
  58. package/docs/Plugins.md +372 -0
  59. package/docs/Results.md +7 -0
  60. package/docs/Transaction.md +135 -0
  61. package/docs/Tutorial.md +183 -0
  62. package/docs/deprecated/access.md +3 -0
  63. package/docs/deprecated/backscatterer.md +9 -0
  64. package/docs/deprecated/connect.rdns_access.md +53 -0
  65. package/docs/deprecated/data.headers.md +3 -0
  66. package/docs/deprecated/data.nomsgid.md +7 -0
  67. package/docs/deprecated/data.noreceived.md +11 -0
  68. package/docs/deprecated/data.rfc5322_header_checks.md +11 -0
  69. package/docs/deprecated/dkim_sign.md +97 -0
  70. package/docs/deprecated/dkim_verify.md +28 -0
  71. package/docs/deprecated/dnsbl.md +80 -0
  72. package/docs/deprecated/dnswl.md +73 -0
  73. package/docs/deprecated/lookup_rdns.strict.md +67 -0
  74. package/docs/deprecated/mail_from.access.md +52 -0
  75. package/docs/deprecated/mail_from.blocklist.md +18 -0
  76. package/docs/deprecated/mail_from.nobounces.md +8 -0
  77. package/docs/deprecated/rcpt_to.access.md +53 -0
  78. package/docs/deprecated/rcpt_to.blocklist.md +18 -0
  79. package/docs/deprecated/rcpt_to.routes.md +3 -0
  80. package/docs/deprecated/rdns.regexp.md +30 -0
  81. package/docs/plugins/aliases.md +3 -0
  82. package/docs/plugins/auth/auth_bridge.md +34 -0
  83. package/docs/plugins/auth/auth_ldap.md +4 -0
  84. package/docs/plugins/auth/auth_proxy.md +36 -0
  85. package/docs/plugins/auth/auth_vpopmaild.md +33 -0
  86. package/docs/plugins/auth/flat_file.md +40 -0
  87. package/docs/plugins/block_me.md +18 -0
  88. package/docs/plugins/data.signatures.md +11 -0
  89. package/docs/plugins/delay_deny.md +23 -0
  90. package/docs/plugins/max_unrecognized_commands.md +6 -0
  91. package/docs/plugins/prevent_credential_leaks.md +22 -0
  92. package/docs/plugins/process_title.md +42 -0
  93. package/docs/plugins/queue/deliver.md +3 -0
  94. package/docs/plugins/queue/discard.md +32 -0
  95. package/docs/plugins/queue/lmtp.md +24 -0
  96. package/docs/plugins/queue/qmail-queue.md +16 -0
  97. package/docs/plugins/queue/quarantine.md +87 -0
  98. package/docs/plugins/queue/smtp_bridge.md +32 -0
  99. package/docs/plugins/queue/smtp_forward.md +127 -0
  100. package/docs/plugins/queue/smtp_proxy.md +68 -0
  101. package/docs/plugins/queue/test.md +7 -0
  102. package/docs/plugins/rcpt_to.in_host_list.md +34 -0
  103. package/docs/plugins/rcpt_to.max_count.md +3 -0
  104. package/docs/plugins/record_envelope_addresses.md +20 -0
  105. package/docs/plugins/relay.md +3 -0
  106. package/docs/plugins/reseed_rng.md +16 -0
  107. package/docs/plugins/status.md +41 -0
  108. package/docs/plugins/tarpit.md +50 -0
  109. package/docs/plugins/tls.md +235 -0
  110. package/docs/plugins/toobusy.md +27 -0
  111. package/docs/plugins/xclient.md +10 -0
  112. package/docs/tutorials/Migrating_from_v1_to_v2.md +96 -0
  113. package/docs/tutorials/SettingUpOutbound.md +62 -0
  114. package/eslint.config.mjs +2 -0
  115. package/haraka.js +74 -0
  116. package/haraka.sh +2 -0
  117. package/http/html/404.html +58 -0
  118. package/http/html/index.html +47 -0
  119. package/http/package.json +21 -0
  120. package/line_socket.js +24 -0
  121. package/logger.js +322 -0
  122. package/outbound/client_pool.js +59 -0
  123. package/outbound/config.js +134 -0
  124. package/outbound/hmail.js +1504 -0
  125. package/outbound/index.js +349 -0
  126. package/outbound/qfile.js +93 -0
  127. package/outbound/queue.js +399 -0
  128. package/outbound/tls.js +85 -0
  129. package/outbound/todo.js +17 -0
  130. package/package.json +100 -4
  131. package/plugins/.eslintrc.yaml +3 -0
  132. package/plugins/auth/auth_base.js +261 -0
  133. package/plugins/auth/auth_bridge.js +20 -0
  134. package/plugins/auth/auth_proxy.js +227 -0
  135. package/plugins/auth/auth_vpopmaild.js +162 -0
  136. package/plugins/auth/flat_file.js +44 -0
  137. package/plugins/block_me.js +88 -0
  138. package/plugins/data.signatures.js +30 -0
  139. package/plugins/delay_deny.js +153 -0
  140. package/plugins/prevent_credential_leaks.js +61 -0
  141. package/plugins/process_title.js +197 -0
  142. package/plugins/profile.js +11 -0
  143. package/plugins/queue/deliver.js +12 -0
  144. package/plugins/queue/discard.js +27 -0
  145. package/plugins/queue/lmtp.js +45 -0
  146. package/plugins/queue/qmail-queue.js +93 -0
  147. package/plugins/queue/quarantine.js +133 -0
  148. package/plugins/queue/smtp_bridge.js +45 -0
  149. package/plugins/queue/smtp_forward.js +371 -0
  150. package/plugins/queue/smtp_proxy.js +142 -0
  151. package/plugins/queue/test.js +15 -0
  152. package/plugins/rcpt_to.host_list_base.js +65 -0
  153. package/plugins/rcpt_to.in_host_list.js +56 -0
  154. package/plugins/record_envelope_addresses.js +17 -0
  155. package/plugins/reseed_rng.js +7 -0
  156. package/plugins/status.js +274 -0
  157. package/plugins/tarpit.js +45 -0
  158. package/plugins/tls.js +164 -0
  159. package/plugins/toobusy.js +47 -0
  160. package/plugins/xclient.js +124 -0
  161. package/plugins.js +605 -0
  162. package/run_tests +11 -0
  163. package/server.js +827 -0
  164. package/smtp_client.js +504 -0
  165. package/test/.eslintrc.yaml +11 -0
  166. package/test/config/auth_flat_file.ini +5 -0
  167. package/test/config/block_me.recipient +1 -0
  168. package/test/config/block_me.senders +1 -0
  169. package/test/config/dhparams.pem +8 -0
  170. package/test/config/host_list +2 -0
  171. package/test/config/outbound_tls_cert.pem +1 -0
  172. package/test/config/outbound_tls_key.pem +1 -0
  173. package/test/config/plugins +7 -0
  174. package/test/config/smtp.ini +11 -0
  175. package/test/config/smtp_forward.ini +30 -0
  176. package/test/config/tls/example.com/_.example.com.key +28 -0
  177. package/test/config/tls/example.com/example.com.crt +25 -0
  178. package/test/config/tls/haraka.local.pem +51 -0
  179. package/test/config/tls.ini +45 -0
  180. package/test/config/tls_cert.pem +21 -0
  181. package/test/config/tls_key.pem +28 -0
  182. package/test/connection.js +820 -0
  183. package/test/fixtures/haproxy_allowed/config/connection.ini +3 -0
  184. package/test/fixtures/haproxy_disabled/config/connection.ini +3 -0
  185. package/test/fixtures/haproxy_untrusted/config/connection.ini +3 -0
  186. package/test/fixtures/line_socket.js +21 -0
  187. package/test/fixtures/todo_qfile.txt +0 -0
  188. package/test/fixtures/util_hmailitem.js +156 -0
  189. package/test/installation/config/test-plugin-flat +1 -0
  190. package/test/installation/config/test-plugin.ini +10 -0
  191. package/test/installation/config/tls.ini +1 -0
  192. package/test/installation/node_modules/load_first/index.js +5 -0
  193. package/test/installation/node_modules/load_first/package.json +11 -0
  194. package/test/installation/node_modules/test-plugin/config/test-plugin-flat +1 -0
  195. package/test/installation/node_modules/test-plugin/config/test-plugin.ini +9 -0
  196. package/test/installation/node_modules/test-plugin/package.json +5 -0
  197. package/test/installation/node_modules/test-plugin/test-plugin.js +5 -0
  198. package/test/installation/plugins/base_plugin.js +3 -0
  199. package/test/installation/plugins/folder_plugin/index.js +3 -0
  200. package/test/installation/plugins/folder_plugin/package.json +11 -0
  201. package/test/installation/plugins/inherits.js +7 -0
  202. package/test/installation/plugins/load_first.js +3 -0
  203. package/test/installation/plugins/plugin.js +1 -0
  204. package/test/installation/plugins/tls.js +3 -0
  205. package/test/logger.js +217 -0
  206. package/test/loud/config/dhparams.pem +0 -0
  207. package/test/loud/config/tls/goobered.pem +45 -0
  208. package/test/loud/config/tls.ini +43 -0
  209. package/test/mail_specimen/base64-root-part.txt +23 -0
  210. package/test/mail_specimen/varied-fold-lengths-preserve-data.txt +283 -0
  211. package/test/outbound/bounce_net_errors.js +133 -0
  212. package/test/outbound/bounce_rfc3464.js +226 -0
  213. package/test/outbound/hmail.js +210 -0
  214. package/test/outbound/index.js +385 -0
  215. package/test/outbound/qfile.js +124 -0
  216. package/test/outbound/queue.js +325 -0
  217. package/test/plugins/auth/auth_base.js +620 -0
  218. package/test/plugins/auth/auth_bridge.js +80 -0
  219. package/test/plugins/auth/auth_vpopmaild.js +81 -0
  220. package/test/plugins/auth/flat_file.js +123 -0
  221. package/test/plugins/block_me.js +141 -0
  222. package/test/plugins/data.signatures.js +111 -0
  223. package/test/plugins/delay_deny.js +262 -0
  224. package/test/plugins/prevent_credential_leaks.js +174 -0
  225. package/test/plugins/process_title.js +141 -0
  226. package/test/plugins/queue/deliver.js +98 -0
  227. package/test/plugins/queue/discard.js +78 -0
  228. package/test/plugins/queue/lmtp.js +137 -0
  229. package/test/plugins/queue/qmail-queue.js +98 -0
  230. package/test/plugins/queue/quarantine.js +80 -0
  231. package/test/plugins/queue/smtp_bridge.js +152 -0
  232. package/test/plugins/queue/smtp_forward.js +1023 -0
  233. package/test/plugins/queue/smtp_proxy.js +138 -0
  234. package/test/plugins/rcpt_to.host_list_base.js +102 -0
  235. package/test/plugins/rcpt_to.in_host_list.js +186 -0
  236. package/test/plugins/record_envelope_addresses.js +66 -0
  237. package/test/plugins/reseed_rng.js +34 -0
  238. package/test/plugins/status.js +207 -0
  239. package/test/plugins/tarpit.js +90 -0
  240. package/test/plugins/tls.js +86 -0
  241. package/test/plugins/toobusy.js +198 -0
  242. package/test/plugins/xclient.js +119 -0
  243. package/test/plugins.js +230 -0
  244. package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  245. package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  246. package/test/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  247. package/test/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  248. package/test/queue/zero-length +0 -0
  249. package/test/server.js +1012 -0
  250. package/test/smtp_client.js +1303 -0
  251. package/test/tls_socket.js +321 -0
  252. package/test/transaction.js +554 -0
  253. package/tls_socket.js +771 -0
  254. 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`.
@@ -0,0 +1,3 @@
1
+ # Custom Return Codes
2
+
3
+ This content has moved to [haraka-dsn](https://github.com/haraka/haraka-dsn).
@@ -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)
@@ -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.
@@ -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