Haraka 3.1.5 → 3.1.7
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 +1 -1
- package/{Changes.md → CHANGELOG.md} +54 -3
- package/CONTRIBUTORS.md +26 -26
- package/Plugins.md +99 -99
- package/README.md +68 -93
- package/SECURITY.md +178 -0
- package/bin/haraka +7 -14
- package/config/plugins +0 -3
- package/config/smtp_forward.ini +10 -0
- package/config/smtp_proxy.ini +10 -0
- package/connection.js +25 -8
- package/docs/Connection.md +126 -39
- package/docs/CoreConfig.md +92 -74
- package/docs/HAProxy.md +41 -25
- package/docs/Logging.md +68 -38
- package/docs/Outbound.md +124 -179
- package/docs/Plugins.md +38 -59
- package/docs/Transaction.md +78 -83
- package/docs/Tutorial.md +122 -209
- package/docs/plugins/aliases.md +1 -141
- package/docs/plugins/auth/auth_ldap.md +2 -39
- package/docs/plugins/max_unrecognized_commands.md +4 -18
- package/docs/plugins/process_title.md +3 -3
- package/docs/plugins/queue/smtp_forward.md +19 -3
- package/docs/plugins/queue/smtp_proxy.md +10 -2
- package/docs/plugins/reseed_rng.md +11 -13
- package/docs/plugins/tls.md +7 -7
- package/docs/plugins/toobusy.md +10 -4
- package/docs/tutorials/SettingUpOutbound.md +40 -48
- package/endpoint.js +32 -2
- package/haraka.js +1 -1
- package/outbound/hmail.js +42 -41
- package/outbound/index.js +7 -4
- package/outbound/tls.js +2 -43
- package/package.json +51 -61
- package/plugins/auth/auth_base.js +9 -3
- package/plugins/auth/auth_proxy.js +14 -11
- package/plugins/block_me.js +4 -2
- package/plugins/prevent_credential_leaks.js +3 -1
- package/plugins/process_title.js +6 -6
- package/plugins/queue/qmail-queue.js +15 -19
- package/plugins/queue/smtp_forward.js +12 -4
- package/plugins/queue/smtp_proxy.js +14 -3
- package/plugins/tls.js +13 -5
- package/plugins/xclient.js +3 -1
- package/server.js +22 -10
- package/smtp_client.js +20 -11
- package/test/config/block_me.recipient +1 -0
- package/test/config/block_me.senders +1 -0
- package/test/connection.js +258 -0
- package/test/endpoint.js +27 -0
- package/test/outbound/bounce_net_errors.js +3 -2
- package/test/outbound/hmail.js +19 -0
- package/test/outbound/index.js +189 -0
- package/test/outbound/queue.js +92 -0
- package/test/plugins/auth/auth_bridge.js +80 -0
- package/test/plugins/auth/flat_file.js +128 -0
- package/test/plugins/block_me.js +157 -0
- package/test/plugins/data.signatures.js +114 -0
- package/test/plugins/delay_deny.js +263 -0
- package/test/plugins/prevent_credential_leaks.js +178 -0
- package/test/plugins/process_title.js +135 -0
- package/test/plugins/queue/deliver.js +99 -0
- package/test/plugins/queue/discard.js +79 -0
- package/test/plugins/queue/lmtp.js +138 -0
- package/test/plugins/queue/qmail-queue.js +99 -0
- package/test/plugins/queue/quarantine.js +81 -0
- package/test/plugins/queue/smtp_bridge.js +154 -0
- package/test/plugins/queue/smtp_forward.js +42 -6
- package/test/plugins/queue/smtp_proxy.js +139 -0
- package/test/plugins/reseed_rng.js +34 -0
- package/test/plugins/tarpit.js +91 -0
- package/test/plugins/tls.js +25 -0
- package/test/plugins/toobusy.js +21 -0
- package/test/plugins/xclient.js +14 -0
- package/test/server.js +231 -0
- package/test/smtp_client.js +45 -12
- package/test/tls_socket.js +220 -0
- package/tls_socket.js +52 -2
package/docs/Plugins.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Plugins
|
|
2
2
|
|
|
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
|
-
enabled.
|
|
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 enabled.
|
|
5
4
|
|
|
6
5
|
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
6
|
|
|
@@ -9,7 +8,7 @@ Recipient (_rcpt_) plugins determine if a particular recipient is allowed to be
|
|
|
9
8
|
|
|
10
9
|
Get a list of installed plugins by running `haraka -l`. To include locally installed plugins, add the `-c /path/to/config` option.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
The [top-level Plugins.md](../Plugins.md) is the registry of known plugins — both core and community.
|
|
13
12
|
|
|
14
13
|
Display the help text for a plugin by running:
|
|
15
14
|
|
|
@@ -21,12 +20,9 @@ Display the help text for a plugin by running:
|
|
|
21
20
|
|
|
22
21
|
## Anatomy of a Plugin
|
|
23
22
|
|
|
24
|
-
Plugins in Haraka are JS files in the `plugins` directory (legacy) and npm
|
|
25
|
-
modules in the node_modules directory. See "Plugins as Modules" below.
|
|
23
|
+
Plugins in Haraka are JS files in the `plugins` directory (legacy) and npm modules in the node_modules directory. See "Plugins as Modules" below.
|
|
26
24
|
|
|
27
|
-
Plugins can be installed in the Haraka global directory (default:
|
|
28
|
-
/$os/$specific/lib/node_modules/Haraka) or in the Haraka install directory
|
|
29
|
-
(whatever you chose when you typed `haraka -i`. Example: `haraka -i /etc/haraka`
|
|
25
|
+
Plugins can be installed in the Haraka global directory (default: /$os/$specific/lib/node_modules/Haraka) or in the Haraka install directory (whatever you chose when you typed `haraka -i`. Example: `haraka -i /etc/haraka`
|
|
30
26
|
|
|
31
27
|
To enable a plugin, add its name to `config/plugins`. For npm packaged plugins, the name does not include the `haraka-plugin` prefix.
|
|
32
28
|
|
|
@@ -123,6 +119,8 @@ need to define them:
|
|
|
123
119
|
|
|
124
120
|
- DENYDISCONNECT - Reject with a 5xx error and immediately disconnect.
|
|
125
121
|
|
|
122
|
+
- DENYSOFTDISCONNECT - Reject with a 4xx error and immediately disconnect.
|
|
123
|
+
|
|
126
124
|
- DISCONNECT - Immediately disconnect
|
|
127
125
|
|
|
128
126
|
- OK
|
|
@@ -178,6 +176,7 @@ These are the hook and their parameters (next excluded):
|
|
|
178
176
|
- delivered (hmail, [host, ip, response, delay, port, mode, ok_recips, secured, authenticated]) - called when outbound mail is delivered
|
|
179
177
|
- send_email (hmail) - called when outbound is about to be sent
|
|
180
178
|
- pre_send_trans_email (fake_connection) - called just before an email is queued to disk with a faked connection object
|
|
179
|
+
- log (logger, log_item) - called for every log message; log plugins (e.g. haraka-plugin-syslog) use this hook to ship logs elsewhere
|
|
181
180
|
|
|
182
181
|
### rcpt
|
|
183
182
|
|
|
@@ -287,47 +286,28 @@ Plugins inherit all the logging methods of `logger.js`, which are:
|
|
|
287
286
|
- logalert
|
|
288
287
|
- logemerg
|
|
289
288
|
|
|
290
|
-
If plugins throw an exception when in a hook, the exception will be caught
|
|
291
|
-
and generate a logcrit level error. However, exceptions will not be caught
|
|
292
|
-
as gracefully when plugins are running async code. Use error codes for that,
|
|
293
|
-
log the error, and run your next() function appropriately.
|
|
289
|
+
If plugins throw an exception when in a hook, the exception will be caught and generate a logcrit level error. However, exceptions will not be caught as gracefully when plugins are running async code. Use error codes for that, log the error, and run your next() function appropriately.
|
|
294
290
|
|
|
295
291
|
## Sharing State
|
|
296
292
|
|
|
297
|
-
There are several cases where you might need to share information between
|
|
298
|
-
plugins. This is done using `notes` - there are three types available:
|
|
293
|
+
There are several cases where you might need to share information between plugins. This is done using `notes` - there are three types available:
|
|
299
294
|
|
|
300
295
|
- server.notes
|
|
301
296
|
|
|
302
|
-
Available in all plugins. This is created at PID start-up and is shared
|
|
303
|
-
amongst all plugins on the same PID and listener.
|
|
304
|
-
Typical uses for notes at this level would be to share database
|
|
305
|
-
connections between multiple plugins or connection pools etc.
|
|
297
|
+
Available in all plugins. This is created at PID start-up and is shared amongst all plugins on the same PID and listener. Typical uses for notes at this level would be to share database connections between multiple plugins or connection pools etc.
|
|
306
298
|
|
|
307
299
|
- connection.notes
|
|
308
300
|
|
|
309
|
-
Available on any hook that passes 'connection' as a function parameter.
|
|
310
|
-
This is shared amongst all plugins for a single connection and is
|
|
311
|
-
destroyed after the client disconnects.
|
|
312
|
-
Typical uses for notes at this level would be to store information
|
|
313
|
-
about the connected client e.g. rDNS names, HELO/EHLO, white/black
|
|
314
|
-
list status etc.
|
|
301
|
+
Available on any hook that passes 'connection' as a function parameter. This is shared amongst all plugins for a single connection and is destroyed after the client disconnects. Typical uses for notes at this level would be to store information about the connected client e.g. rDNS names, HELO/EHLO, white/black list status etc.
|
|
315
302
|
|
|
316
303
|
- connection.transaction.notes
|
|
317
304
|
|
|
318
|
-
Available on any hook that passes 'connection' as a function parameter
|
|
319
|
-
|
|
320
|
-
This is shared amongst all plugins for this transaction (e.g. MAIL FROM
|
|
321
|
-
through until a message is received or the connection is reset).
|
|
322
|
-
Typical uses for notes at this level would be to store information
|
|
323
|
-
on things like greylisting which uses client, sender and recipient
|
|
324
|
-
information etc.
|
|
305
|
+
Available on any hook that passes 'connection' as a function parameter between hook_mail and hook_data_post.
|
|
306
|
+
This is shared amongst all plugins for this transaction (e.g. MAIL FROM through until a message is received or the connection is reset). Typical uses for notes at this level would be to store information on things like greylisting which uses client, sender and recipient information etc.
|
|
325
307
|
|
|
326
308
|
- hmail.todo.notes
|
|
327
309
|
|
|
328
|
-
Available on any outbound hook that passes `hmail` as a function parameter.
|
|
329
|
-
This is the same object as 'connection.transaction.notes', so anything
|
|
330
|
-
you store in the transaction notes is automatically available in the
|
|
310
|
+
Available on any outbound hook that passes `hmail` as a function parameter. This is the same object as 'connection.transaction.notes', so anything you store in the transaction notes is automatically available in the
|
|
331
311
|
outbound functions here.
|
|
332
312
|
|
|
333
313
|
All of these notes are JS objects - use them as simple key/value store e.g.
|
|
@@ -336,39 +316,40 @@ All of these notes are JS objects - use them as simple key/value store e.g.
|
|
|
336
316
|
|
|
337
317
|
## Plugins as Modules
|
|
338
318
|
|
|
339
|
-
Plugins as NPM modules are named with the `haraka-plugin` prefix. Therefore, a
|
|
340
|
-
plugin that frobnobricates might be called `haraka-plugin-frobnobricate` and
|
|
341
|
-
published to NPM with that name. The prefix is not required in the
|
|
319
|
+
Plugins as NPM modules are named with the `haraka-plugin` prefix. Therefore, a plugin that frobnobricates might be called `haraka-plugin-frobnobricate` and published to NPM with that name. The prefix is not required in the
|
|
342
320
|
`config/plugins` file.
|
|
343
321
|
|
|
344
|
-
Plugins loaded as NPM modules behave slightly different than plugins loaded
|
|
345
|
-
|
|
322
|
+
Plugins loaded as NPM modules behave slightly different than plugins loaded as plain JS files.
|
|
323
|
+
|
|
324
|
+
Plain JS plugins have a custom `require()` which allows loading core Haraka modules via specifying `require('./name')` (note the `./` prefix). Although the core modules aren't in the same folder, the custom `require` intercepts
|
|
325
|
+
this and look for core modules. Note that if there is a module in your plugins folder of the same name that will not take preference, so avoid using names similar to core modules.
|
|
326
|
+
|
|
327
|
+
Plugins loaded as modules do not have the special `require()`. To load a core Haraka module you must use `this.haraka_require('name')`. This should also be preferred for plain JS plugins, as the `./` hack is likely to be removed in the future.
|
|
328
|
+
|
|
329
|
+
Plugins loaded as modules are not compiled in the Haraka plugin sandbox, which blocks access to certain globals and provides a global `server` object. To access the `server` object, use `connection.server` instead.
|
|
330
|
+
|
|
331
|
+
Module plugins support default config in their local `config` directory. See the "Default Config and Overrides" section in [haraka-config](https://github.com/haraka/haraka-config#default-config-and-overrides).
|
|
346
332
|
|
|
347
|
-
|
|
348
|
-
modules via specifying `require('./name')` (note the `./` prefix). Although
|
|
349
|
-
the core modules aren't in the same folder, the custom `require` intercepts
|
|
350
|
-
this and look for core modules. Note that if there is a module in your plugins
|
|
351
|
-
folder of the same name that will not take preference, so avoid using names
|
|
352
|
-
similar to core modules.
|
|
333
|
+
### Inheriting from another plugin
|
|
353
334
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
335
|
+
A plugin can inherit methods from another plugin by calling `plugin.inherits(name)` from its `register()`. The parent's exported methods become available on `this` (without overwriting any methods the child has already defined), and the parent's `register()` runs in the child's context. `rcpt_to.host_list_base` is a typical parent used by multiple `rcpt_to.*` plugins.
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
exports.register = function () {
|
|
339
|
+
this.inherits('rcpt_to.host_list_base')
|
|
340
|
+
this.register_hook('rcpt', 'my_rcpt')
|
|
341
|
+
}
|
|
342
|
+
```
|
|
358
343
|
|
|
359
|
-
|
|
360
|
-
which blocks access to certain globals and provides a global `server` object.
|
|
361
|
-
To access the `server` object, use `connection.server` instead.
|
|
344
|
+
### Deprecated plugin names
|
|
362
345
|
|
|
363
|
-
|
|
364
|
-
"Default Config and Overrides" section in [Config](Config.md).
|
|
346
|
+
Some plugin names have been folded into newer packages — for example `connect.fcrdns` is now `fcrdns`, `dnsbl` is now `dns-list`, and `rate_limit` / `max_unrecognized_commands` are now `limit`. Haraka logs a notice and loads the replacement automatically; the full mapping lives in `plugins.js → plugins.deprecated`.
|
|
365
347
|
|
|
366
348
|
## Shutdown
|
|
367
349
|
|
|
368
350
|
On graceful reload, Haraka will call a plugin's `shutdown` method.
|
|
369
351
|
|
|
370
|
-
This is so you can clear any timers or intervals, or shut down any connections
|
|
371
|
-
to remote servers. See [Issue 2024](https://github.com/haraka/Haraka/issues/2024).
|
|
352
|
+
This is so you can clear any timers or intervals, or shut down any connections to remote servers. See [Issue 2024](https://github.com/haraka/Haraka/issues/2024).
|
|
372
353
|
|
|
373
354
|
e.g.
|
|
374
355
|
|
|
@@ -378,9 +359,7 @@ exports.shutdown = function () {
|
|
|
378
359
|
}
|
|
379
360
|
```
|
|
380
361
|
|
|
381
|
-
If you don't implement this in your plugin and have a connection open or a
|
|
382
|
-
timer running then Haraka will take 30 seconds to shut down and have to
|
|
383
|
-
forcibly kill your process.
|
|
362
|
+
If you don't implement this in your plugin and have a connection open or a timer running then Haraka will take 30 seconds to shut down and have to forcibly kill your process.
|
|
384
363
|
|
|
385
364
|
Note: This only applies when running with a `nodes=...` value in smtp.ini.
|
|
386
365
|
|
package/docs/Transaction.md
CHANGED
|
@@ -1,140 +1,135 @@
|
|
|
1
1
|
# Transaction Object
|
|
2
2
|
|
|
3
|
-
An SMTP transaction
|
|
3
|
+
An SMTP transaction begins at `MAIL FROM` and ends at `RSET` or end-of-data (the "final dot"). A connection can carry multiple transactions; the current one is available as `connection.transaction`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Properties
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### transaction.uuid
|
|
8
8
|
|
|
9
|
-
A unique UUID for this transaction
|
|
9
|
+
A unique UUID for this transaction, of the form `<connection.uuid>.N`, where `N` increments per transaction on the connection.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
### transaction.mail_from
|
|
12
12
|
|
|
13
|
-
The
|
|
13
|
+
The `MAIL FROM` argument as an [`Address`][address] object.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### transaction.rcpt_to
|
|
16
16
|
|
|
17
|
-
An
|
|
17
|
+
An array of [`Address`][address] objects, one per accepted `RCPT TO`.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
### transaction.header
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
The parsed message header. See [haraka-email-message → Header](https://github.com/haraka/email-message#header).
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
### transaction.body
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
transaction.message_stream.pipe(WritableStream, options)
|
|
27
|
-
```
|
|
25
|
+
The parsed message body, available only when `parse_body` is `true`. See [haraka-email-message → Body](https://github.com/haraka/email-message#body).
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
### transaction.message_stream
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
A Node.js `Readable` stream for the message (headers + body). Pipe it into any `Writable` — a socket, file, stdout, or your own stream:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
transaction.message_stream.pipe(writable, options)
|
|
33
|
+
```
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
* dot_stuffed (default: true)
|
|
35
|
-
* ending_dot (default: false)
|
|
36
|
-
* end (default: true)
|
|
37
|
-
* buffer_size (default: 65535)
|
|
38
|
-
* clamd_style (default: false)
|
|
35
|
+
`options` may override:
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
| Option | Default | Description |
|
|
38
|
+
| -------------- | -------- | --- |
|
|
39
|
+
| `line_endings` | `"\r\n"` | newline sequence |
|
|
40
|
+
| `dot_stuffed` | `true` | emit SMTP dot-stuffed output |
|
|
41
|
+
| `ending_dot` | `false` | terminate with `.\r\n` (SMTP end-of-data) |
|
|
42
|
+
| `end` | `true` | call `.end()` on the writable when finished |
|
|
43
|
+
| `buffer_size` | `65535` | internal buffer size |
|
|
44
|
+
| `clamd_style` | `false` | ClamAV CLAMSCAN-INSTREAM framing |
|
|
41
45
|
|
|
42
46
|
```js
|
|
43
47
|
transaction.message_stream.pipe(socket, { ending_dot: true })
|
|
44
48
|
```
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
### transaction.data_bytes
|
|
51
|
+
|
|
52
|
+
Number of bytes received during `DATA`.
|
|
53
|
+
|
|
54
|
+
### transaction.parse_body
|
|
55
|
+
|
|
56
|
+
`false` by default. Set to `true` (in `hook_data` or earlier) to enable MIME body parsing, after which `transaction.body` becomes available. `attachment_hooks()`, `set_banner()`, and `add_body_filter()` set this automatically.
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
### transaction.discard_data
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
Set to `true` to drop the raw message as it arrives instead of buffering it in `message_stream`. The parsed body and attachments are still available when `parse_body` is `true`. Useful for plugins that only need attachments or text without retaining the whole message.
|
|
51
61
|
|
|
52
|
-
|
|
62
|
+
### transaction.notes
|
|
53
63
|
|
|
54
|
-
- transaction.notes
|
|
64
|
+
A `haraka-notes` instance scoped to this transaction. Use it to pass state between hooks; for structured per-test output prefer `transaction.results`. See [haraka-notes](https://github.com/haraka/haraka-notes).
|
|
55
65
|
|
|
56
|
-
|
|
66
|
+
`transaction.notes.skip_plugins` is honoured by the plugin runner — push plugin names into it to bypass them for the remainder of the transaction.
|
|
57
67
|
|
|
58
|
-
|
|
68
|
+
### transaction.results
|
|
59
69
|
|
|
60
|
-
|
|
70
|
+
Structured store for plugin results. See [haraka-results](https://github.com/haraka/haraka-results).
|
|
61
71
|
|
|
62
|
-
|
|
72
|
+
### transaction.rcpt_count
|
|
63
73
|
|
|
64
|
-
|
|
74
|
+
Per-disposition counters (`accept`, `tempfail`, `reject`) tracking recipients in this transaction.
|
|
65
75
|
|
|
66
|
-
|
|
76
|
+
### transaction.mime_part_count
|
|
67
77
|
|
|
68
|
-
|
|
78
|
+
Number of MIME parts seen so far (when `parse_body` is enabled).
|
|
69
79
|
|
|
70
|
-
|
|
80
|
+
### transaction.encoding
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
Character encoding used to convert incoming bytes to strings. Defaults to `'utf8'`.
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
## Methods
|
|
75
85
|
|
|
76
|
-
|
|
86
|
+
### transaction.add_header(key, value)
|
|
77
87
|
|
|
78
|
-
|
|
88
|
+
Append a header to the message.
|
|
79
89
|
|
|
80
|
-
|
|
90
|
+
### transaction.add_leading_header(key, value)
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
Prepend a header to the message. Most plugins want `add_header()`; use this only when ordering matters (e.g. `Received:` chains).
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
### transaction.remove_header(key)
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
Remove all headers with `key`.
|
|
87
97
|
|
|
88
|
-
|
|
98
|
+
### transaction.add_data(line)
|
|
89
99
|
|
|
90
|
-
|
|
100
|
+
Append a raw line to the message. The input must already be in SMTP wire format (CRLF newlines, dot-stuffed). Not the right tool for adding banners or transforming body parts — see `set_banner()` and `add_body_filter()`.
|
|
101
|
+
|
|
102
|
+
### transaction.attachment_hooks(start)
|
|
103
|
+
|
|
104
|
+
Register a callback fired for each attachment. `start` is called with `(content_type, filename, body, stream)`; `stream` is a Node.js `Readable`. Setting `stream.connection = connection` applies backpressure to the SMTP connection so attachments can be processed before the message ends.
|
|
91
105
|
|
|
92
106
|
```js
|
|
93
|
-
exports.hook_data =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
next()
|
|
107
|
+
exports.hook_data = (next, connection) => {
|
|
108
|
+
connection.transaction.attachment_hooks((ct, fn, body, stream) => {
|
|
109
|
+
start_att(connection, ct, fn, body, stream)
|
|
110
|
+
})
|
|
111
|
+
next()
|
|
99
112
|
}
|
|
100
113
|
|
|
101
114
|
function start_att(connection, ct, fn, body, stream) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
})
|
|
115
|
+
connection.loginfo(`attachment: ${ct} ${fn}`)
|
|
116
|
+
stream.connection = connection // enable backpressure
|
|
117
|
+
stream.pause()
|
|
118
|
+
|
|
119
|
+
require('node:tmp').file((err, path, fd) => {
|
|
120
|
+
const ws = require('node:fs').createWriteStream(path)
|
|
121
|
+
stream.pipe(ws)
|
|
122
|
+
stream.resume()
|
|
119
123
|
})
|
|
120
|
-
})
|
|
121
124
|
}
|
|
122
125
|
```
|
|
123
126
|
|
|
124
|
-
|
|
125
|
-
|
|
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.
|
|
127
|
-
|
|
128
|
-
- transaction.set_banner(text, html)
|
|
129
|
-
|
|
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.
|
|
131
|
-
|
|
132
|
-
- transaction.add_body_filter(ct_match, filter)
|
|
127
|
+
### transaction.set_banner(text, html)
|
|
133
128
|
|
|
134
|
-
|
|
129
|
+
Append a banner to the end of the message. If `html` is omitted, each newline in `text` is replaced with `<br/>\n` when inserted into HTML parts.
|
|
135
130
|
|
|
136
|
-
|
|
131
|
+
### transaction.add_body_filter(ct_match, filter)
|
|
137
132
|
|
|
138
|
-
|
|
133
|
+
Register a filter applied to body parts. `ct_match` is either a regex matched against the content-type line, or a string matched as a prefix (e.g. `/^text\/html/` or `'text/plain'`). `filter` receives `(content_type, encoding, buffer)` and must return a `Buffer` with the replacement body (in the same encoding).
|
|
139
134
|
|
|
140
|
-
[
|
|
135
|
+
[address]: https://github.com/haraka/node-address-rfc2821
|