haraka 0.0.33 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +28 -0
- package/.githooks/pre-commit +41 -0
- package/.prettierignore +6 -0
- package/.qlty/.gitignore +7 -0
- package/.qlty/configs/.shellcheckrc +1 -0
- package/.qlty/qlty.toml +15 -0
- package/CHANGELOG.md +1894 -0
- package/CLAUDE.md +40 -0
- package/CONTRIBUTORS.md +34 -0
- package/Dockerfile +50 -0
- package/GEMINI.md +38 -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/address.js +53 -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/dhparams.pem +8 -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/me +1 -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/tls_cert.pem +23 -0
- package/config/tls_key.pem +28 -0
- package/config/watch.ini +12 -0
- package/config/xclient.hosts +2 -0
- package/connection.js +1863 -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 +61 -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/coverage/coverage-final.json +2 -0
- package/coverage/coverage-summary.json +33 -0
- package/coverage/tmp/coverage-79131-1779241025146-0.json +1 -0
- package/coverage/tmp/coverage-79132-1779240999690-0.json +1 -0
- package/coverage/tmp/coverage-79172-1779241000095-0.json +1 -0
- package/coverage/tmp/coverage-79210-1779241000156-0.json +1 -0
- package/coverage/tmp/coverage-79211-1779241000209-0.json +1 -0
- package/coverage/tmp/coverage-79212-1779241000266-0.json +1 -0
- package/coverage/tmp/coverage-79213-1779241000441-0.json +1 -0
- package/coverage/tmp/coverage-79214-1779241000626-0.json +1 -0
- package/coverage/tmp/coverage-79215-1779241000795-0.json +1 -0
- package/coverage/tmp/coverage-79216-1779241000965-0.json +1 -0
- package/coverage/tmp/coverage-79218-1779241001013-0.json +1 -0
- package/coverage/tmp/coverage-79219-1779241001179-0.json +1 -0
- package/coverage/tmp/coverage-79220-1779241006249-0.json +1 -0
- package/coverage/tmp/coverage-79227-1779241011453-0.json +1 -0
- package/coverage/tmp/coverage-79229-1779241011537-0.json +1 -0
- package/coverage/tmp/coverage-79230-1779241011647-0.json +1 -0
- package/coverage/tmp/coverage-79231-1779241011765-0.json +1 -0
- package/coverage/tmp/coverage-79232-1779241011841-0.json +1 -0
- package/coverage/tmp/coverage-79233-1779241011909-0.json +1 -0
- package/coverage/tmp/coverage-79234-1779241011984-0.json +1 -0
- package/coverage/tmp/coverage-79235-1779241012055-0.json +1 -0
- package/coverage/tmp/coverage-79236-1779241012230-0.json +1 -0
- package/coverage/tmp/coverage-79237-1779241012300-0.json +1 -0
- package/coverage/tmp/coverage-79238-1779241012368-0.json +1 -0
- package/coverage/tmp/coverage-79239-1779241012438-0.json +1 -0
- package/coverage/tmp/coverage-79240-1779241012511-0.json +1 -0
- package/coverage/tmp/coverage-79241-1779241012582-0.json +1 -0
- package/coverage/tmp/coverage-79242-1779241012652-0.json +1 -0
- package/coverage/tmp/coverage-79243-1779241012814-0.json +1 -0
- package/coverage/tmp/coverage-79244-1779241012931-0.json +1 -0
- package/coverage/tmp/coverage-79245-1779241013007-0.json +1 -0
- package/coverage/tmp/coverage-79246-1779241013106-0.json +1 -0
- package/coverage/tmp/coverage-79247-1779241013178-0.json +1 -0
- package/coverage/tmp/coverage-79248-1779241013244-0.json +1 -0
- package/coverage/tmp/coverage-79249-1779241013409-0.json +1 -0
- package/coverage/tmp/coverage-79250-1779241013697-0.json +1 -0
- package/coverage/tmp/coverage-79251-1779241013847-0.json +1 -0
- package/coverage/tmp/coverage-79252-1779241014288-0.json +1 -0
- package/coverage/tmp/coverage-79253-1779241014378-0.json +1 -0
- package/coverage/tmp/coverage-79254-1779241014428-0.json +1 -0
- package/coverage/tmp/coverage-79255-1779241021774-0.json +1 -0
- package/coverage/tmp/coverage-80382-1779241021949-0.json +1 -0
- package/coverage/tmp/coverage-80383-1779241025019-0.json +1 -0
- package/coverage/tmp/coverage-80384-1779241025133-0.json +1 -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 +99 -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 +604 -0
- package/queue/1772642154987_1775581346001_4_82235_TGwgfd_2_mattbook-m3.home.simerson.net +0 -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 +817 -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 +21 -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
package/docs/Body.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
moved to [Body](https://github.com/haraka/email-message#body)
|
package/docs/Config.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This documentation has moved to [haraka-config](https://github.com/haraka/haraka-config).
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Connection Object
|
|
2
|
+
|
|
3
|
+
For each connection to Haraka there is one connection object. It is the first argument passed to almost every plugin hook and is the primary context object plugins use to inspect and act on the SMTP session.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
### connection.uuid
|
|
8
|
+
|
|
9
|
+
A unique UUID for this connection. Used as the connection identifier in logs and inherited by `transaction.uuid`.
|
|
10
|
+
|
|
11
|
+
### connection.remote
|
|
12
|
+
|
|
13
|
+
Information about the host connecting to Haraka.
|
|
14
|
+
|
|
15
|
+
- `ip` — remote IP address
|
|
16
|
+
- `port` — remote TCP port
|
|
17
|
+
- `host` — reverse DNS of the remote IP (populated by the `connect.rdns_access` / `connect` hooks)
|
|
18
|
+
- `info` — free-form descriptor (e.g. populated by FCrDNS)
|
|
19
|
+
- `closed` — `true` once the remote end has dropped the connection
|
|
20
|
+
- `is_private` — `true` if the remote IP is in a private range (RFC 1918, loopback, link-local, etc.)
|
|
21
|
+
- `is_local` — `true` if the remote IP is localhost / loopback
|
|
22
|
+
|
|
23
|
+
### connection.local
|
|
24
|
+
|
|
25
|
+
Information about the Haraka server endpoint handling this connection.
|
|
26
|
+
|
|
27
|
+
- `ip` — the IP of the Haraka server, as reported by the OS
|
|
28
|
+
- `port` — the port number handling the connection
|
|
29
|
+
- `host` — the primary host name of the Haraka server
|
|
30
|
+
- `info` — `Haraka` (with `/<version>` appended when `headers.show_version` is enabled in `connection.ini`)
|
|
31
|
+
|
|
32
|
+
### connection.hello
|
|
33
|
+
|
|
34
|
+
The greeting given by the client.
|
|
35
|
+
|
|
36
|
+
- `verb` — `EHLO` or `HELO`, whichever the client used
|
|
37
|
+
- `host` — the hostname argument
|
|
38
|
+
|
|
39
|
+
### connection.tls
|
|
40
|
+
|
|
41
|
+
State of the TLS layer on this connection.
|
|
42
|
+
|
|
43
|
+
- `enabled` — `true` once STARTTLS has been negotiated (or the listener is `smtps`)
|
|
44
|
+
- `advertised` — `true` if Haraka advertised STARTTLS in the EHLO response
|
|
45
|
+
- `verified` — `true` if the peer certificate validated against the configured CAs
|
|
46
|
+
- `cipher` — the negotiated cipher object (`name`, `version`, …)
|
|
47
|
+
- `verifyError` — the verification error, if any
|
|
48
|
+
- `peerCertificate` — the parsed peer certificate (when client certs are used)
|
|
49
|
+
|
|
50
|
+
### connection.proxy
|
|
51
|
+
|
|
52
|
+
Proxy-protocol state, set when the connection arrived via HAProxy (see [HAProxy.md](HAProxy.md)).
|
|
53
|
+
|
|
54
|
+
- `allowed` — `true` if the remote IP is in the `haproxy.hosts` allow-list
|
|
55
|
+
- `ip` — the proxy server's IP (the real client IP appears in `connection.remote.ip` once PROXY is parsed)
|
|
56
|
+
- `type` — currently `null` or `'haproxy'`
|
|
57
|
+
|
|
58
|
+
### connection.notes
|
|
59
|
+
|
|
60
|
+
A plain object that persists for the lifetime of the connection. Use it to share state between plugin hooks. For structured per-test results prefer `connection.results`. See also [haraka-notes](https://github.com/haraka/haraka-notes).
|
|
61
|
+
|
|
62
|
+
### connection.results
|
|
63
|
+
|
|
64
|
+
Structured store for plugin results. See [haraka-results](https://github.com/haraka/haraka-results).
|
|
65
|
+
|
|
66
|
+
### connection.transaction
|
|
67
|
+
|
|
68
|
+
The current `Transaction` object. Valid between `MAIL FROM` and the end of `queue` / `RSET` (or until `MAIL FROM` is rejected). See [Transaction.md](Transaction.md).
|
|
69
|
+
|
|
70
|
+
### connection.relaying
|
|
71
|
+
|
|
72
|
+
Boolean. `true` if this connection is allowed to relay (i.e. deliver mail outbound). Normally set by an auth plugin or an IP allow-list. Reading or writing this property transparently routes through the current transaction when one exists, so the flag survives across multiple messages in a single connection only when set on the connection.
|
|
73
|
+
|
|
74
|
+
### connection.capabilities
|
|
75
|
+
|
|
76
|
+
Array of ESMTP capabilities advertised in the EHLO response (e.g. `['PIPELINING', '8BITMIME', 'SIZE 0', 'STARTTLS', 'AUTH PLAIN LOGIN']`). Plugins may push additional capability strings during the `capabilities` hook.
|
|
77
|
+
|
|
78
|
+
### connection.esmtp
|
|
79
|
+
|
|
80
|
+
`true` if the client used `EHLO` (as opposed to `HELO`).
|
|
81
|
+
|
|
82
|
+
### connection.pipelining
|
|
83
|
+
|
|
84
|
+
`true` once Haraka has advertised, and the client has used, SMTP pipelining.
|
|
85
|
+
|
|
86
|
+
### connection.early_talker
|
|
87
|
+
|
|
88
|
+
`true` if the client sent data before Haraka issued its banner — a
|
|
89
|
+
common spam-bot signal.
|
|
90
|
+
|
|
91
|
+
### connection.tran_count
|
|
92
|
+
|
|
93
|
+
Number of transactions completed on this connection.
|
|
94
|
+
|
|
95
|
+
### connection.rcpt_count / connection.msg_count
|
|
96
|
+
|
|
97
|
+
Per-disposition counters (`accept`, `tempfail`, `reject`) tracking
|
|
98
|
+
recipients and full messages on this connection.
|
|
99
|
+
|
|
100
|
+
### connection.start_time
|
|
101
|
+
|
|
102
|
+
Connection start time, in epoch milliseconds (`Date.now()`).
|
|
103
|
+
|
|
104
|
+
### connection.last_response
|
|
105
|
+
|
|
106
|
+
The last SMTP response line Haraka sent to the client.
|
|
107
|
+
|
|
108
|
+
### connection.last_reject
|
|
109
|
+
|
|
110
|
+
The text of the last rejection issued to this client (used by
|
|
111
|
+
`max_unrecognized_commands` and similar throttling plugins).
|
|
112
|
+
|
|
113
|
+
### connection.errors
|
|
114
|
+
|
|
115
|
+
Count of protocol errors on this connection.
|
|
116
|
+
|
|
117
|
+
### connection.current_line
|
|
118
|
+
|
|
119
|
+
Low-level. The current line as sent by the remote end, verbatim. Useful
|
|
120
|
+
for botnet fingerprinting.
|
|
121
|
+
|
|
122
|
+
### connection.state
|
|
123
|
+
|
|
124
|
+
The connection's protocol state — one of the values in `haraka-constants`'s `connection.state` table (`PAUSE`, `CMD`, `LOOP`, `DATA`, `DISCONNECTING`, `DISCONNECTED`).
|
|
125
|
+
|
|
126
|
+
## Methods
|
|
127
|
+
|
|
128
|
+
### connection.respond(code, msg, cb)
|
|
129
|
+
|
|
130
|
+
Send an SMTP response to the client. `code` is the numeric SMTP code, `msg` is the human-readable text (a string or an array of strings for a multi-line response). The callback fires when the response has been written.
|
|
131
|
+
|
|
132
|
+
### connection.disconnect()
|
|
133
|
+
|
|
134
|
+
Close the connection after running the `disconnect` hook.
|
|
135
|
+
|
|
136
|
+
### connection.reset_transaction(cb)
|
|
137
|
+
|
|
138
|
+
Tear down the current transaction (equivalent to `RSET`) and invoke `cb` when complete.
|
|
139
|
+
|
|
140
|
+
### connection.set(path, value)
|
|
141
|
+
|
|
142
|
+
Assign a nested property safely, e.g. `connection.set('remote.host', 'mx.example.com')`. Setting `remote.ip`
|
|
143
|
+
automatically recomputes `remote.is_private` / `remote.is_local`.
|
|
144
|
+
|
|
145
|
+
### connection.get(path)
|
|
146
|
+
|
|
147
|
+
Read a nested property, returning `undefined` if any segment is missing.
|
|
148
|
+
|
|
149
|
+
### connection.loginfo / lognotice / logwarn / logerror / logdebug / logcrit / logalert / logemerg / logprotocol / logdata
|
|
150
|
+
|
|
151
|
+
Log at the named level. Each takes either `(msg)` or `(plugin, msg, data)`.
|
|
152
|
+
|
|
153
|
+
See [Logging.md](Logging.md).
|
|
@@ -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
|