Haraka 3.1.0 → 3.1.2
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/.prettierignore +4 -0
- package/CONTRIBUTORS.md +5 -5
- package/Changes.md +69 -50
- package/Plugins.md +3 -1
- package/README.md +1 -1
- package/bin/haraka +475 -478
- package/config/outbound.ini +3 -0
- package/connection.js +1072 -1108
- package/docs/Connection.md +29 -30
- package/docs/CoreConfig.md +38 -39
- package/docs/CustomReturnCodes.md +0 -1
- package/docs/HAProxy.md +2 -2
- package/docs/Header.md +1 -1
- package/docs/Logging.md +29 -5
- package/docs/Outbound.md +93 -78
- package/docs/Plugins.md +103 -108
- package/docs/Transaction.md +49 -51
- package/docs/Tutorial.md +127 -143
- package/docs/deprecated/access.md +0 -1
- package/docs/deprecated/backscatterer.md +2 -3
- package/docs/deprecated/connect.rdns_access.md +18 -27
- package/docs/deprecated/data.headers.md +0 -1
- package/docs/deprecated/data.nomsgid.md +1 -2
- package/docs/deprecated/data.noreceived.md +1 -2
- package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
- package/docs/deprecated/dkim_sign.md +13 -17
- package/docs/deprecated/dkim_verify.md +9 -17
- package/docs/deprecated/dnsbl.md +36 -38
- package/docs/deprecated/dnswl.md +41 -43
- package/docs/deprecated/lookup_rdns.strict.md +21 -34
- package/docs/deprecated/mail_from.access.md +17 -25
- package/docs/deprecated/mail_from.blocklist.md +9 -12
- package/docs/deprecated/mail_from.nobounces.md +1 -2
- package/docs/deprecated/rcpt_to.access.md +20 -27
- package/docs/deprecated/rcpt_to.blocklist.md +10 -13
- package/docs/deprecated/rcpt_to.routes.md +0 -1
- package/docs/deprecated/rdns.regexp.md +13 -15
- package/docs/plugins/aliases.md +89 -89
- package/docs/plugins/auth/auth_bridge.md +5 -7
- package/docs/plugins/auth/auth_ldap.md +11 -14
- package/docs/plugins/auth/auth_proxy.md +10 -12
- package/docs/plugins/auth/auth_vpopmaild.md +5 -6
- package/docs/plugins/auth/flat_file.md +4 -4
- package/docs/plugins/block_me.md +3 -3
- package/docs/plugins/data.signatures.md +1 -2
- package/docs/plugins/delay_deny.md +3 -4
- package/docs/plugins/max_unrecognized_commands.md +4 -4
- package/docs/plugins/prevent_credential_leaks.md +6 -6
- package/docs/plugins/process_title.md +18 -18
- package/docs/plugins/queue/deliver.md +2 -3
- package/docs/plugins/queue/discard.md +4 -4
- package/docs/plugins/queue/lmtp.md +1 -3
- package/docs/plugins/queue/qmail-queue.md +7 -9
- package/docs/plugins/queue/quarantine.md +16 -21
- package/docs/plugins/queue/rabbitmq.md +8 -11
- package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
- package/docs/plugins/queue/smtp_bridge.md +7 -10
- package/docs/plugins/queue/smtp_forward.md +42 -34
- package/docs/plugins/queue/smtp_proxy.md +30 -29
- package/docs/plugins/queue/test.md +1 -3
- package/docs/plugins/rcpt_to.in_host_list.md +6 -6
- package/docs/plugins/rcpt_to.max_count.md +1 -1
- package/docs/plugins/record_envelope_addresses.md +3 -3
- package/docs/plugins/reseed_rng.md +6 -6
- package/docs/plugins/status.md +9 -8
- package/docs/plugins/tarpit.md +7 -11
- package/docs/plugins/tls.md +12 -17
- package/docs/plugins/toobusy.md +4 -4
- package/docs/plugins/xclient.md +3 -3
- package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
- package/docs/tutorials/SettingUpOutbound.md +6 -9
- package/endpoint.js +35 -38
- package/eslint.config.mjs +22 -19
- package/haraka.js +42 -47
- package/host_pool.js +75 -79
- package/http/html/404.html +45 -49
- package/http/html/index.html +39 -28
- package/http/package.json +2 -4
- package/line_socket.js +27 -28
- package/logger.js +182 -201
- package/outbound/client_pool.js +34 -27
- package/outbound/config.js +64 -59
- package/outbound/fsync_writestream.js +24 -25
- package/outbound/hmail.js +888 -835
- package/outbound/index.js +194 -187
- package/outbound/qfile.js +49 -52
- package/outbound/queue.js +197 -190
- package/outbound/timer_queue.js +41 -43
- package/outbound/tls.js +68 -61
- package/outbound/todo.js +11 -11
- package/package.json +38 -33
- package/plugins/.eslintrc.yaml +0 -1
- package/plugins/auth/auth_base.js +123 -127
- package/plugins/auth/auth_bridge.js +7 -7
- package/plugins/auth/auth_proxy.js +121 -126
- package/plugins/auth/auth_vpopmaild.js +84 -85
- package/plugins/auth/flat_file.js +18 -17
- package/plugins/block_me.js +31 -31
- package/plugins/data.signatures.js +13 -13
- package/plugins/delay_deny.js +65 -61
- package/plugins/prevent_credential_leaks.js +23 -23
- package/plugins/process_title.js +125 -128
- package/plugins/profile.js +5 -5
- package/plugins/queue/deliver.js +3 -3
- package/plugins/queue/discard.js +13 -14
- package/plugins/queue/lmtp.js +16 -17
- package/plugins/queue/qmail-queue.js +54 -55
- package/plugins/queue/quarantine.js +68 -70
- package/plugins/queue/rabbitmq.js +80 -87
- package/plugins/queue/rabbitmq_amqplib.js +75 -54
- package/plugins/queue/smtp_bridge.js +16 -16
- package/plugins/queue/smtp_forward.js +175 -179
- package/plugins/queue/smtp_proxy.js +69 -71
- package/plugins/queue/test.js +9 -9
- package/plugins/rcpt_to.host_list_base.js +30 -34
- package/plugins/rcpt_to.in_host_list.js +19 -19
- package/plugins/record_envelope_addresses.js +4 -4
- package/plugins/reseed_rng.js +4 -4
- package/plugins/status.js +90 -97
- package/plugins/tarpit.js +25 -14
- package/plugins/tls.js +68 -68
- package/plugins/toobusy.js +21 -23
- package/plugins/xclient.js +51 -53
- package/plugins.js +276 -293
- package/rfc1869.js +30 -35
- package/server.js +308 -299
- package/smtp_client.js +244 -228
- package/test/.eslintrc.yaml +0 -1
- package/test/connection.js +127 -134
- package/test/endpoint.js +53 -47
- package/test/fixtures/line_socket.js +12 -12
- package/test/fixtures/util_hmailitem.js +89 -85
- package/test/host_pool.js +90 -92
- package/test/installation/plugins/base_plugin.js +2 -2
- package/test/installation/plugins/folder_plugin/index.js +2 -3
- package/test/installation/plugins/inherits.js +3 -3
- package/test/installation/plugins/load_first.js +2 -3
- package/test/installation/plugins/plugin.js +1 -3
- package/test/installation/plugins/tls.js +2 -4
- package/test/logger.js +135 -116
- package/test/outbound/hmail.js +49 -35
- package/test/outbound/index.js +118 -101
- package/test/outbound/qfile.js +51 -53
- package/test/outbound_bounce_net_errors.js +84 -69
- package/test/outbound_bounce_rfc3464.js +235 -165
- package/test/plugins/auth/auth_base.js +420 -279
- package/test/plugins/auth/auth_vpopmaild.js +38 -39
- package/test/plugins/queue/smtp_forward.js +126 -104
- package/test/plugins/rcpt_to.host_list_base.js +85 -67
- package/test/plugins/rcpt_to.in_host_list.js +159 -112
- package/test/plugins/status.js +71 -64
- package/test/plugins/tls.js +37 -34
- package/test/plugins.js +97 -92
- package/test/rfc1869.js +19 -26
- package/test/server.js +293 -272
- package/test/smtp_client.js +180 -176
- package/test/tls_socket.js +62 -66
- package/test/transaction.js +159 -160
- package/tls_socket.js +331 -333
- package/transaction.js +129 -137
package/docs/Plugins.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Most aspects of receiving an email in Haraka are controlled by plugins. Mail cannot even be received unless at least a 'rcpt' and 'queue' plugin are
|
|
4
4
|
enabled.
|
|
5
5
|
|
|
6
|
-
Recipient (
|
|
6
|
+
Recipient (_rcpt_) plugins determine if a particular recipient is allowed to be relayed or received for. A _queue_ plugin queues the message somewhere - normally to disk or to an another SMTP server.
|
|
7
7
|
|
|
8
8
|
## Plugin Lists
|
|
9
9
|
|
|
@@ -19,14 +19,13 @@ Display the help text for a plugin by running:
|
|
|
19
19
|
|
|
20
20
|
## Overview
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
## Anatomy of a Plugin
|
|
24
23
|
|
|
25
24
|
Plugins in Haraka are JS files in the `plugins` directory (legacy) and npm
|
|
26
|
-
modules in the
|
|
25
|
+
modules in the node_modules directory. See "Plugins as Modules" below.
|
|
27
26
|
|
|
28
27
|
Plugins can be installed in the Haraka global directory (default:
|
|
29
|
-
/$os/$specific/lib/
|
|
28
|
+
/$os/$specific/lib/node_modules/Haraka) or in the Haraka install directory
|
|
30
29
|
(whatever you chose when you typed `haraka -i`. Example: `haraka -i /etc/haraka`
|
|
31
30
|
|
|
32
31
|
To enable a plugin, add its name to `config/plugins`. For npm packaged plugins, the name does not include the `haraka-plugin` prefix.
|
|
@@ -37,27 +36,27 @@ Register is the only plugin function that is syncronous and receives no argument
|
|
|
37
36
|
|
|
38
37
|
### Register a Hook
|
|
39
38
|
|
|
40
|
-
There are two ways for plugins to register hooks. Both examples register a function on the
|
|
39
|
+
There are two ways for plugins to register hooks. Both examples register a function on the _rcpt_ hook:
|
|
41
40
|
|
|
42
41
|
1. The `register_hook` function in register():
|
|
43
42
|
|
|
44
43
|
```js
|
|
45
44
|
exports.register = function () {
|
|
46
|
-
|
|
47
|
-
}
|
|
45
|
+
this.register_hook('rcpt', 'my_rcpt_validate')
|
|
46
|
+
}
|
|
48
47
|
|
|
49
48
|
exports.my_rcpt_validate = function (next, connection, params) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
49
|
+
// do processing
|
|
50
|
+
next()
|
|
51
|
+
}
|
|
53
52
|
```
|
|
54
53
|
|
|
55
|
-
2. The
|
|
54
|
+
2. The hook\_[$name] syntax:
|
|
56
55
|
|
|
57
56
|
```js
|
|
58
57
|
exports.hook_rcpt = function (next, connection, params) {
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
// do processing
|
|
59
|
+
next()
|
|
61
60
|
}
|
|
62
61
|
```
|
|
63
62
|
|
|
@@ -74,28 +73,28 @@ To register the same hook more than once, call `register_hook()` multiple times
|
|
|
74
73
|
|
|
75
74
|
```js
|
|
76
75
|
exports.register = function () {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
76
|
+
this.register_hook('queue', 'try_queue_my_way')
|
|
77
|
+
this.register_hook('queue', 'try_queue_highway')
|
|
78
|
+
}
|
|
80
79
|
```
|
|
81
80
|
|
|
82
|
-
When `try_queue_my_way()` calls `next()`, the next function registered on hook
|
|
81
|
+
When `try_queue_my_way()` calls `next()`, the next function registered on hook _queue_ will be called, in this case, `try_queue_highway()`.
|
|
83
82
|
|
|
84
83
|
#### Determine hook name
|
|
85
84
|
|
|
86
85
|
When a single function runs on multiple hooks, the function can check the
|
|
87
|
-
|
|
86
|
+
_hook_ property of the _connection_ or _hmail_ argument to determine which hook it is running on:
|
|
88
87
|
|
|
89
88
|
```js
|
|
90
89
|
exports.register = function () {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
90
|
+
this.register_hook('rcpt', 'my_rcpt')
|
|
91
|
+
this.register_hook('rcpt_ok', 'my_rcpt')
|
|
92
|
+
}
|
|
93
|
+
|
|
95
94
|
exports.my_rcpt = function (next, connection, params) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
const hook_name = connection.hook // rcpt or rcpt_ok
|
|
96
|
+
// email address is in params[0]
|
|
97
|
+
// do processing
|
|
99
98
|
}
|
|
100
99
|
```
|
|
101
100
|
|
|
@@ -113,20 +112,20 @@ After registering a hook, functions are called with that hooks arguments (see **
|
|
|
113
112
|
These constants are in your plugin when it is loaded, you do not
|
|
114
113
|
need to define them:
|
|
115
114
|
|
|
116
|
-
|
|
115
|
+
- CONT
|
|
117
116
|
|
|
118
117
|
Continue and let other plugins handle this particular hook. This is the
|
|
119
118
|
default. These are identical: `next()` and `next(CONT)`;
|
|
120
119
|
|
|
121
|
-
|
|
120
|
+
- DENY - Reject with a 5xx error.
|
|
122
121
|
|
|
123
|
-
|
|
122
|
+
- DENYSOFT - Reject with a 4xx error.
|
|
124
123
|
|
|
125
|
-
|
|
124
|
+
- DENYDISCONNECT - Reject with a 5xx error and immediately disconnect.
|
|
126
125
|
|
|
127
|
-
|
|
126
|
+
- DISCONNECT - Immediately disconnect
|
|
128
127
|
|
|
129
|
-
|
|
128
|
+
- OK
|
|
130
129
|
|
|
131
130
|
Required by `rcpt` plugins to accept a recipient and `queue` plugins when the queue was successful.
|
|
132
131
|
|
|
@@ -134,11 +133,11 @@ need to define them:
|
|
|
134
133
|
|
|
135
134
|
Exceptions to next(OK):
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
- connect_init and disconnect hooks are **always called**.
|
|
138
137
|
|
|
139
|
-
|
|
138
|
+
- On the deny hook, `next(OK)` overrides the default CONT.
|
|
140
139
|
|
|
141
|
-
|
|
140
|
+
- HOOK_NEXT
|
|
142
141
|
|
|
143
142
|
HOOK_NEXT is only available on the `unrecognized_command` hook. It instructs Haraka to run a different plugin hook. The `msg` argument must be set to the name of the hook to be run. Ex: `next(HOOK_NEXT, 'rcpt_ok');`
|
|
144
143
|
|
|
@@ -146,49 +145,49 @@ need to define them:
|
|
|
146
145
|
|
|
147
146
|
These are the hook and their parameters (next excluded):
|
|
148
147
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
148
|
+
- init_master - called when the main (master) process is started
|
|
149
|
+
- init_child - in cluster, called when a child process is started
|
|
150
|
+
- init_http - called when Haraka is started.
|
|
151
|
+
- init_wss - called after init_http
|
|
152
|
+
- connect_init - used to init data structures, called for *every* connection
|
|
153
|
+
- lookup_rdns - called to look up the rDNS - return the rDNS via `next(OK, rdns)`
|
|
154
|
+
- connect - called after we got rDNS
|
|
155
|
+
- capabilities - called to get the ESMTP capabilities (such as STARTTLS)
|
|
156
|
+
- unrecognized_command - called when the remote end sends a command we don't recognise
|
|
157
|
+
- disconnect - called upon disconnect
|
|
158
|
+
- helo (hostname)
|
|
159
|
+
- ehlo (hostname)
|
|
160
|
+
- quit
|
|
161
|
+
- vrfy
|
|
162
|
+
- noop
|
|
163
|
+
- rset
|
|
164
|
+
- mail ([from, esmtp\_params])
|
|
165
|
+
- rcpt ([to, esmtp\_params])
|
|
166
|
+
- rcpt_ok (to)
|
|
167
|
+
- data - called at the DATA command
|
|
168
|
+
- data_post - called at the end-of-data marker
|
|
169
|
+
- max_data_exceeded - called when the message exceeds connection.max_bytes
|
|
170
|
+
- queue - called to queue the mail
|
|
171
|
+
- queue_outbound - called to queue the mail when connection.relaying is set
|
|
172
|
+
- queue_ok - called when a mail has been queued successfully
|
|
173
|
+
- reset_transaction - called before the transaction is reset (via RSET, or MAIL)
|
|
174
|
+
- deny - called when a plugin returns DENY, DENYSOFT or DENYDISCONNECT
|
|
175
|
+
- get_mx (hmail, domain) - called by outbound to resolve the MX record
|
|
176
|
+
- deferred (hmail, params) - called when an outbound message is deferred
|
|
177
|
+
- bounce (hmail, err) - called when an outbound message bounces
|
|
178
|
+
- delivered (hmail, [host, ip, response, delay, port, mode, ok_recips, secured, authenticated]) - called when outbound mail is delivered
|
|
179
|
+
- send_email (hmail) - called when outbound is about to be sent
|
|
180
|
+
- pre_send_trans_email (fake_connection) - called just before an email is queued to disk with a faked connection object
|
|
182
181
|
|
|
183
182
|
### rcpt
|
|
184
183
|
|
|
185
|
-
The
|
|
184
|
+
The _rcpt_ hook is slightly special.
|
|
186
185
|
|
|
187
|
-
When **connection.relaying == false** (the default, to avoid being an open relay), a rcpt plugin MUST return `next(OK)` or the sender will receive the error message "I cannot deliver for that user". The default
|
|
186
|
+
When **connection.relaying == false** (the default, to avoid being an open relay), a rcpt plugin MUST return `next(OK)` or the sender will receive the error message "I cannot deliver for that user". The default _rcpt_ plugin is **rcpt_to.in_host_list**, which lists the domains for which to accept email.
|
|
188
187
|
|
|
189
|
-
After a
|
|
188
|
+
After a _rcpt_ plugin calls `next(OK)`, the _rcpt_ok_ hook is run.
|
|
190
189
|
|
|
191
|
-
If a plugin prior to the
|
|
190
|
+
If a plugin prior to the _rcpt_ hook sets **connection.relaying = true**, then it is not necessary for a rcpt plugin to call `next(OK)`.
|
|
192
191
|
|
|
193
192
|
### connect_init
|
|
194
193
|
|
|
@@ -202,11 +201,11 @@ If http listeners are are enabled in http.ini and the express module loaded, the
|
|
|
202
201
|
|
|
203
202
|
If express loaded, an attempt is made to load [ws](https://www.npmjs.com/package/ws), the websocket server. If it succeeds, the wss server will be located at Server.http.wss. Because of how websockets work, only one websocket plugin will work at a time. One plugin using wss is [watch](https://github.com/haraka/Haraka/tree/master/plugins/watch).
|
|
204
203
|
|
|
205
|
-
###
|
|
204
|
+
### pre_send_trans_email (next, fake_connection)
|
|
206
205
|
|
|
207
206
|
The `fake` connection here is a holder for a new transaction object. It only has the log methods and a `transaction` property
|
|
208
207
|
so don't expect it to behave like a a real connection object. This hook is designed so you can add headers and modify mails
|
|
209
|
-
sent via `outbound.send_email()`, see the
|
|
208
|
+
sent via `outbound.send_email()`, see the dkim plugin for an example.
|
|
210
209
|
|
|
211
210
|
## Hook Order
|
|
212
211
|
|
|
@@ -217,18 +216,16 @@ The ordering of hooks is determined by the SMTP protocol. Knowledge of [RFC 5321
|
|
|
217
216
|
- hook_connect_init
|
|
218
217
|
- hook_lookup_rdns
|
|
219
218
|
- hook_connect
|
|
220
|
-
- hook_helo **OR** hook_ehlo
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
-
|
|
224
|
-
|
|
225
|
-
- *hook_unrecognized_command* is run for each ESMTP extension the client requests
|
|
226
|
-
e.g. STARTTLS, AUTH etc.)
|
|
219
|
+
- hook_helo **OR** hook_ehlo
|
|
220
|
+
- hook_helo
|
|
221
|
+
- hook_ehlo (when ESMTP is desired, allows extensions such as STARTTLS, AUTH, SIZE etc.)
|
|
222
|
+
- hook_capabilities
|
|
223
|
+
- *hook_unrecognized_command* is run for each ESMTP extension the client requests (e.g. STARTTLS, AUTH etc.)
|
|
227
224
|
- hook_mail
|
|
228
225
|
- hook_rcpt (once per-recipient)
|
|
229
226
|
- hook_rcpt_ok (for every recipient that hook_rcpt returned `next(OK)` for)
|
|
230
227
|
- hook_data
|
|
231
|
-
-
|
|
228
|
+
- _[attachment hooks]_
|
|
232
229
|
- hook_data_post
|
|
233
230
|
- hook_queue **OR** hook_queue_outbound
|
|
234
231
|
- hook_queue_ok (called if hook_queue or hook_queue_outbound returns `next(OK)`)
|
|
@@ -239,16 +236,16 @@ e.g. STARTTLS, AUTH etc.)
|
|
|
239
236
|
##### Typical Outbound mail
|
|
240
237
|
|
|
241
238
|
By 'outbound' we mean messages using Haraka's built-in queue and delivery
|
|
242
|
-
mechanism. The Outbound queue is used when `connection.relaying = true` is set during the
|
|
239
|
+
mechanism. The Outbound queue is used when `connection.relaying = true` is set during the transaction and `hook_queue_outbound` is called to queue the message.
|
|
243
240
|
|
|
244
241
|
The Outbound hook ordering mirrors the Inbound hook order above until after `hook_queue_outbound`, which is followed by:
|
|
245
242
|
|
|
246
243
|
- hook_send_email
|
|
247
244
|
- hook_get_mx
|
|
248
245
|
- at least one of:
|
|
249
|
-
- hook_delivered
|
|
250
|
-
- hook_deferred
|
|
251
|
-
- hook_bounce
|
|
246
|
+
- hook_delivered (once per delivery domain with at least one successful recipient)
|
|
247
|
+
- hook_deferred (once per delivery domain where at least one recipient or connection was deferred)
|
|
248
|
+
- hook_bounce (once per delivery domain where the recipient(s) or message was rejected by the destination)
|
|
252
249
|
|
|
253
250
|
## Plugin Run Order
|
|
254
251
|
|
|
@@ -256,11 +253,11 @@ Plugins are run on each hook in the order that they are specified in `config/plu
|
|
|
256
253
|
|
|
257
254
|
This is important as some plugins might rely on `results` or `notes` that have been set by plugins that need to run before them. This should be noted in the plugins documentation. Make sure to read it.
|
|
258
255
|
|
|
259
|
-
If you are writing a complex plugin, you may have to split it into multiple plugins to run in a specific order e.g. you want hook_deny to run last after all other plugins and hook_lookup_rdns to run first, then you can explicitly register your hooks and provide a `priority` value which is an integer between -100 (highest priority) to 100 (lowest priority) which defaults to 0 (zero) if not supplied.
|
|
256
|
+
If you are writing a complex plugin, you may have to split it into multiple plugins to run in a specific order e.g. you want hook_deny to run last after all other plugins and hook_lookup_rdns to run first, then you can explicitly register your hooks and provide a `priority` value which is an integer between -100 (highest priority) to 100 (lowest priority) which defaults to 0 (zero) if not supplied. You can apply a priority to your hook in the following way:
|
|
260
257
|
|
|
261
258
|
```js
|
|
262
259
|
exports.register = function () {
|
|
263
|
-
|
|
260
|
+
this.register_hook('connect', 'do_connect_stuff', -100)
|
|
264
261
|
}
|
|
265
262
|
```
|
|
266
263
|
|
|
@@ -274,21 +271,21 @@ Check the order that the plugins will run on each hook by running:
|
|
|
274
271
|
|
|
275
272
|
## Skipping Plugins
|
|
276
273
|
|
|
277
|
-
Plugins can be skipped at runtime by pushing the name of the plugin into the `skip_plugins` array in `transaction.notes`.
|
|
274
|
+
Plugins can be skipped at runtime by pushing the name of the plugin into the `skip_plugins` array in `transaction.notes`. This array is reset for every transaction and once a plugin is added to the list, it will not run any hooks in that plugin for the remainder of the transaction. For example, one could create a whitelist plugin that skipped `spamassassin` if the sender was in a whitelist.
|
|
278
275
|
|
|
279
276
|
## Logging
|
|
280
277
|
|
|
281
278
|
Plugins inherit all the logging methods of `logger.js`, which are:
|
|
282
279
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
280
|
+
- logprotocol
|
|
281
|
+
- logdebug
|
|
282
|
+
- loginfo
|
|
283
|
+
- lognotice
|
|
284
|
+
- logwarn
|
|
285
|
+
- logerror
|
|
286
|
+
- logcrit
|
|
287
|
+
- logalert
|
|
288
|
+
- logemerg
|
|
292
289
|
|
|
293
290
|
If plugins throw an exception when in a hook, the exception will be caught
|
|
294
291
|
and generate a logcrit level error. However, exceptions will not be caught
|
|
@@ -298,16 +295,16 @@ log the error, and run your next() function appropriately.
|
|
|
298
295
|
## Sharing State
|
|
299
296
|
|
|
300
297
|
There are several cases where you might need to share information between
|
|
301
|
-
plugins.
|
|
298
|
+
plugins. This is done using `notes` - there are three types available:
|
|
302
299
|
|
|
303
|
-
|
|
300
|
+
- server.notes
|
|
304
301
|
|
|
305
|
-
Available in all plugins.
|
|
302
|
+
Available in all plugins. This is created at PID start-up and is shared
|
|
306
303
|
amongst all plugins on the same PID and listener.
|
|
307
304
|
Typical uses for notes at this level would be to share database
|
|
308
305
|
connections between multiple plugins or connection pools etc.
|
|
309
306
|
|
|
310
|
-
|
|
307
|
+
- connection.notes
|
|
311
308
|
|
|
312
309
|
Available on any hook that passes 'connection' as a function parameter.
|
|
313
310
|
This is shared amongst all plugins for a single connection and is
|
|
@@ -316,17 +313,17 @@ plugins. This is done using `notes` - there are three types available:
|
|
|
316
313
|
about the connected client e.g. rDNS names, HELO/EHLO, white/black
|
|
317
314
|
list status etc.
|
|
318
315
|
|
|
319
|
-
|
|
316
|
+
- connection.transaction.notes
|
|
320
317
|
|
|
321
318
|
Available on any hook that passes 'connection' as a function parameter
|
|
322
|
-
between
|
|
319
|
+
between hook_mail and hook_data_post.
|
|
323
320
|
This is shared amongst all plugins for this transaction (e.g. MAIL FROM
|
|
324
321
|
through until a message is received or the connection is reset).
|
|
325
322
|
Typical uses for notes at this level would be to store information
|
|
326
323
|
on things like greylisting which uses client, sender and recipient
|
|
327
324
|
information etc.
|
|
328
325
|
|
|
329
|
-
|
|
326
|
+
- hmail.todo.notes
|
|
330
327
|
|
|
331
328
|
Available on any outbound hook that passes `hmail` as a function parameter.
|
|
332
329
|
This is the same object as 'connection.transaction.notes', so anything
|
|
@@ -377,7 +374,7 @@ e.g.
|
|
|
377
374
|
|
|
378
375
|
```js
|
|
379
376
|
exports.shutdown = function () {
|
|
380
|
-
|
|
377
|
+
clearInterval(this._interval)
|
|
381
378
|
}
|
|
382
379
|
```
|
|
383
380
|
|
|
@@ -389,9 +386,7 @@ Note: This only applies when running with a `nodes=...` value in smtp.ini.
|
|
|
389
386
|
|
|
390
387
|
## See also, [Results](Results.md)
|
|
391
388
|
|
|
392
|
-
|
|
393
|
-
Further Reading
|
|
394
|
-
--------------
|
|
389
|
+
## Further Reading
|
|
395
390
|
|
|
396
391
|
Read about the [Connection](Connection.md) object.
|
|
397
392
|
|
package/docs/Transaction.md
CHANGED
|
@@ -4,19 +4,19 @@ An SMTP transaction is valid from MAIL FROM time until RSET or "final-dot".
|
|
|
4
4
|
|
|
5
5
|
## API
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- transaction.uuid
|
|
8
8
|
|
|
9
9
|
A unique UUID for this transaction. Is equal to the connection.uuid + '.N' where N increments for each transaction on this connection.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- transaction.mail_from
|
|
12
12
|
|
|
13
13
|
The value of the MAIL FROM command is an `Address`[1] object.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- transaction.rcpt_to
|
|
16
16
|
|
|
17
17
|
An Array of `Address`[1] objects of recipients from the RCPT TO command.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- transaction.message_stream
|
|
20
20
|
|
|
21
21
|
A node.js Readable Stream object for the message.
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ Where WritableStream is a node.js Writable Stream object such as a net.socket, f
|
|
|
31
31
|
The options argument should be an object that overrides the following properties:
|
|
32
32
|
|
|
33
33
|
* line_endings (default: "\r\n")
|
|
34
|
-
*
|
|
34
|
+
* dot_stuffed (default: true)
|
|
35
35
|
* ending_dot (default: false)
|
|
36
36
|
* end (default: true)
|
|
37
37
|
* buffer_size (default: 65535)
|
|
@@ -40,46 +40,46 @@ The options argument should be an object that overrides the following properties
|
|
|
40
40
|
e.g.
|
|
41
41
|
|
|
42
42
|
```js
|
|
43
|
-
transaction.message_stream.pipe(socket, {
|
|
43
|
+
transaction.message_stream.pipe(socket, { ending_dot: true })
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
- transaction.data_bytes
|
|
47
47
|
|
|
48
48
|
The number of bytes in the email after DATA.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
- transaction.add_data(line)
|
|
51
51
|
|
|
52
52
|
Adds a line of data to the email. Note this is RAW email - it isn't useful for adding banners to the email.
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
- transaction.notes
|
|
55
55
|
|
|
56
56
|
A safe place to store transaction specific values. See also [haraka-results](https://github.com/haraka/haraka-results) and [haraka-notes](https://github.com/haraka/haraka-notes).
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
- transaction.add_leading_header(key, value)
|
|
59
59
|
|
|
60
|
-
Adds a header to the top of the header list.
|
|
60
|
+
Adds a header to the top of the header list. This should only be used in very specific cases. Most cases will use `add_header()` instead.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
- transaction.add_header(key, value)
|
|
63
63
|
|
|
64
64
|
Adds a header to the email.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
- transaction.remove_header(key)
|
|
67
67
|
|
|
68
68
|
Deletes a header from the email.
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
- transaction.header
|
|
71
71
|
|
|
72
72
|
The header of the email. See `Header Object`.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
- transaction.parse_body = true|false [default: false]
|
|
75
75
|
|
|
76
|
-
Set to `true` to enable parsing of the mail body. Make sure you set this in
|
|
76
|
+
Set to `true` to enable parsing of the mail body. Make sure you set this in hook_data or before. Storing a transaction hook (with transaction.attachment_hooks) will set this to true.
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
- transaction.body
|
|
79
79
|
|
|
80
80
|
The body of the email if you set `parse_body` above. See `Body Object`.
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
- transaction.attachment_hooks(start)
|
|
83
83
|
|
|
84
84
|
Sets a callback for when we see an attachment.
|
|
85
85
|
|
|
@@ -91,51 +91,49 @@ If you set stream.connection then the stream will apply backpressure to the conn
|
|
|
91
91
|
|
|
92
92
|
```js
|
|
93
93
|
exports.hook_data = function (next, connection) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
);
|
|
100
|
-
next();
|
|
94
|
+
// enable mail body parsing
|
|
95
|
+
connection.transaction.attachment_hooks(function (ct, fn, body, stream) {
|
|
96
|
+
start_att(connection, ct, fn, body, stream)
|
|
97
|
+
})
|
|
98
|
+
next()
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
function start_att
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
101
|
+
function start_att(connection, ct, fn, body, stream) {
|
|
102
|
+
connection.loginfo(`Got attachment: ${ct}, ${fn} for user id: ${connection.transaction.notes.hubdoc_user.email}`)
|
|
103
|
+
connection.transaction.notes.attachment_count++
|
|
104
|
+
|
|
105
|
+
stream.connection = connection // Allow backpressure
|
|
106
|
+
stream.pause()
|
|
107
|
+
|
|
108
|
+
require('tmp').file((err, path, fd) => {
|
|
109
|
+
connection.loginfo(`Got tempfile: ${path} (${fd})`)
|
|
110
|
+
const ws = fs.createWriteStream(path)
|
|
111
|
+
stream.pipe(ws)
|
|
112
|
+
stream.resume()
|
|
113
|
+
ws.on('close', () => {
|
|
114
|
+
connection.loginfo('End of stream reached')
|
|
115
|
+
fs.fstat(fd, (err, stats) => {
|
|
116
|
+
connection.loginfo(`Got data of length: ${stats.size}`)
|
|
117
|
+
fs.close(fd, () => {}) // Close the tmp file descriptor
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
})
|
|
123
121
|
}
|
|
124
122
|
```
|
|
125
123
|
|
|
126
|
-
|
|
124
|
+
- transaction.discard_data = true|false [default: false]
|
|
127
125
|
|
|
128
|
-
Set this flag to true to discard all data as it arrives and not store in memory or on disk (in the
|
|
126
|
+
Set this flag to true to discard all data as it arrives and not store in memory or on disk (in the message_stream property). You can still access the attachments and body if you set parse_body to true. This is useful for systems which do not need the full email, just the attachments or mail text.
|
|
129
127
|
|
|
130
|
-
|
|
128
|
+
- transaction.set_banner(text, html)
|
|
131
129
|
|
|
132
130
|
Sets a banner to be added to the end of the email. If the html part is not given (optional) then the text part will have each line ending replaced with `<br/>` when being inserted into HTML parts.
|
|
133
131
|
|
|
134
|
-
|
|
132
|
+
- transaction.add_body_filter(ct_match, filter)
|
|
135
133
|
|
|
136
|
-
Adds a filter to be applied to body parts in the email.
|
|
134
|
+
Adds a filter to be applied to body parts in the email. ct_match should be a regular expression to match against the full content-type line, or a string to match at the start, e.g. `/^text\/html/` or `'text/plain'`. filter will be called when each body part matching ct_match is complete. It receives three parameters: the content-type line, the encoding name, and a buffer with the full body part. It should return a buffer with the desired contents of the body in the same encoding.
|
|
137
135
|
|
|
138
|
-
|
|
136
|
+
- transaction.results
|
|
139
137
|
|
|
140
138
|
Store [results](https://github.com/haraka/haraka-results) of processing in a structured format.
|
|
141
139
|
|