Haraka 3.0.2 → 3.0.4
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/.eslintrc.yaml +5 -9
- package/.prettierrc.yml +1 -0
- package/CONTRIBUTORS.md +11 -0
- package/Changes.md +1393 -1211
- package/Dockerfile +3 -3
- package/Plugins.md +119 -106
- package/README.md +7 -16
- package/TODO +1 -24
- package/bin/haraka +197 -298
- package/config/auth_flat_file.ini +2 -0
- package/config/auth_vpopmaild.ini +4 -2
- package/config/dhparams.pem +8 -0
- package/config/mail_from.is_resolvable.ini +4 -2
- package/config/me +1 -0
- package/config/outbound.ini +0 -2
- package/config/plugins +36 -35
- package/config/rabbitmq_amqplib.ini +8 -1
- package/config/smtp.ini +0 -1
- package/config/smtp.json +17 -0
- package/config/tls_cert.pem +23 -0
- package/config/tls_key.pem +28 -0
- package/connection.js +46 -73
- package/contrib/bsd-rc.d/haraka +3 -1
- package/contrib/plugin2npm.sh +6 -36
- package/docs/Connection.md +1 -1
- package/docs/CoreConfig.md +2 -2
- package/docs/Logging.md +7 -21
- package/docs/Outbound.md +104 -210
- package/docs/Plugins.md +47 -40
- package/docs/Transaction.md +59 -82
- package/docs/{plugins → deprecated}/connect.rdns_access.md +1 -1
- package/docs/{plugins → deprecated}/mail_from.access.md +1 -1
- package/docs/{plugins → deprecated}/rcpt_to.access.md +1 -1
- package/docs/plugins/auth/auth_vpopmaild.md +15 -19
- package/docs/plugins/auth/flat_file.md +23 -30
- package/docs/plugins/queue/rabbitmq_amqplib.md +7 -0
- package/docs/plugins/queue/smtp_forward.md +1 -1
- package/docs/plugins/queue/smtp_proxy.md +5 -10
- package/docs/plugins/relay.md +2 -2
- package/docs/plugins/tls.md +29 -9
- package/endpoint.js +16 -13
- package/haraka.js +10 -14
- package/host_pool.js +5 -5
- package/line_socket.js +3 -4
- package/logger.js +44 -28
- package/outbound/client_pool.js +27 -23
- package/outbound/config.js +4 -6
- package/outbound/fsync_writestream.js +1 -1
- package/outbound/hmail.js +180 -220
- package/outbound/index.js +86 -99
- package/outbound/qfile.js +1 -1
- package/outbound/queue.js +55 -43
- package/outbound/timer_queue.js +3 -2
- package/outbound/tls.js +19 -7
- package/package.json +66 -55
- package/plugins/.eslintrc.yaml +0 -6
- package/plugins/auth/auth_base.js +30 -12
- package/plugins/auth/auth_proxy.js +14 -12
- package/plugins/auth/auth_vpopmaild.js +30 -20
- package/plugins/auth/flat_file.js +17 -12
- package/plugins/block_me.js +1 -1
- package/plugins/data.signatures.js +2 -4
- package/plugins/early_talker.js +2 -1
- package/plugins/mail_from.is_resolvable.js +65 -135
- package/plugins/queue/deliver.js +4 -5
- package/plugins/queue/lmtp.js +11 -14
- package/plugins/queue/qmail-queue.js +2 -2
- package/plugins/queue/quarantine.js +2 -2
- package/plugins/queue/rabbitmq.js +16 -17
- package/plugins/queue/rabbitmq_amqplib.js +1 -1
- package/plugins/queue/smtp_forward.js +6 -6
- package/plugins/queue/smtp_proxy.js +10 -1
- package/plugins/queue/test.js +2 -2
- package/plugins/rcpt_to.host_list_base.js +5 -5
- package/plugins/rcpt_to.in_host_list.js +2 -2
- package/plugins/relay.js +6 -7
- package/plugins/reseed_rng.js +1 -1
- package/plugins/status.js +37 -33
- package/plugins/tls.js +2 -2
- package/plugins/xclient.js +3 -2
- package/plugins.js +51 -54
- package/run_tests +3 -30
- package/server.js +190 -190
- package/smtp_client.js +30 -23
- package/{tests → test}/config/plugins +0 -2
- package/{tests → test}/config/smtp.ini +1 -1
- package/test/config/tls/example.com/_.example.com.key +28 -0
- package/test/config/tls/example.com/example.com.crt +25 -0
- package/test/connection.js +302 -0
- package/test/endpoint.js +94 -0
- package/{tests → test}/fixtures/line_socket.js +1 -1
- package/{tests → test}/fixtures/util_hmailitem.js +19 -25
- package/{tests → test}/host_pool.js +42 -57
- package/test/logger.js +258 -0
- package/test/outbound/hmail.js +141 -0
- package/test/outbound/index.js +220 -0
- package/test/outbound/qfile.js +126 -0
- package/test/outbound_bounce_net_errors.js +142 -0
- package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
- package/test/plugins/auth/auth_base.js +484 -0
- package/test/plugins/auth/auth_vpopmaild.js +83 -0
- package/test/plugins/early_talker.js +104 -0
- package/test/plugins/mail_from.is_resolvable.js +35 -0
- package/test/plugins/queue/smtp_forward.js +206 -0
- package/test/plugins/rcpt_to.host_list_base.js +122 -0
- package/test/plugins/rcpt_to.in_host_list.js +193 -0
- package/test/plugins/relay.js +303 -0
- package/test/plugins/status.js +130 -0
- package/test/plugins/tls.js +70 -0
- package/test/plugins.js +228 -0
- package/{tests → test}/queue/multibyte +0 -0
- package/{tests → test}/queue/plain +0 -0
- package/test/rfc1869.js +73 -0
- package/test/server.js +491 -0
- package/test/smtp_client.js +299 -0
- package/test/tls_socket.js +273 -0
- package/test/transaction.js +270 -0
- package/tls_socket.js +202 -252
- package/transaction.js +9 -24
- package/CONTRIBUTING.md +0 -1
- package/bin/dkimverify +0 -40
- package/config/access.domains +0 -13
- package/config/attachment.ctype.regex +0 -2
- package/config/attachment.filename.regex +0 -1
- package/config/avg.ini +0 -5
- package/config/bounce.ini +0 -15
- package/config/data.headers.ini +0 -61
- package/config/dkim/dkim_key_gen.sh +0 -78
- package/config/dkim_sign.ini +0 -4
- package/config/dkim_verify.ini +0 -7
- package/config/dnsbl.ini +0 -23
- package/config/greylist.ini +0 -43
- package/config/helo.checks.ini +0 -52
- package/config/lookup_rdns.strict.ini +0 -12
- package/config/lookup_rdns.strict.timeout +0 -1
- package/config/lookup_rdns.strict.whitelist +0 -1
- package/config/lookup_rdns.strict.whitelist_regex +0 -5
- package/config/messagesniffer.ini +0 -18
- package/config/rcpt_to.blocklist +0 -1
- package/config/rdns.allow_regexps +0 -0
- package/config/rdns.deny_regexps +0 -0
- package/config/spamassassin.ini +0 -56
- package/config.js +0 -6
- package/dkim.js +0 -614
- package/docs/plugins/avg.md +0 -35
- package/docs/plugins/bounce.md +0 -69
- package/docs/plugins/clamd.md +0 -147
- package/docs/plugins/esets.md +0 -8
- package/docs/plugins/greylist.md +0 -90
- package/docs/plugins/helo.checks.md +0 -135
- package/docs/plugins/messagesniffer.md +0 -163
- package/docs/plugins/relay_acl.md +0 -29
- package/docs/plugins/relay_all.md +0 -15
- package/docs/plugins/relay_force_routing.md +0 -33
- package/docs/plugins/spamassassin.md +0 -180
- package/outbound/mx_lookup.js +0 -70
- package/plugins/auth/auth_ldap.js +0 -3
- package/plugins/avg.js +0 -162
- package/plugins/backscatterer.js +0 -25
- package/plugins/bounce.js +0 -381
- package/plugins/clamd.js +0 -381
- package/plugins/data.headers.js +0 -4
- package/plugins/data.uribl.js +0 -4
- package/plugins/dkim_sign.js +0 -395
- package/plugins/dkim_verify.js +0 -62
- package/plugins/dns_list_base.js +0 -221
- package/plugins/dnsbl.js +0 -146
- package/plugins/dnswl.js +0 -58
- package/plugins/esets.js +0 -71
- package/plugins/graph.js +0 -5
- package/plugins/greylist.js +0 -645
- package/plugins/helo.checks.js +0 -533
- package/plugins/messagesniffer.js +0 -381
- package/plugins/rcpt_to.ldap.js +0 -3
- package/plugins/rcpt_to.max_count.js +0 -24
- package/plugins/relay_all.js +0 -13
- package/plugins/spamassassin.js +0 -384
- package/tests/config/dkim/example.com/dns +0 -29
- package/tests/config/dkim/example.com/private +0 -6
- package/tests/config/dkim/example.com/public +0 -4
- package/tests/config/dkim/example.com/selector +0 -1
- package/tests/config/dkim.private.key +0 -6
- package/tests/config/dkim_sign.ini +0 -4
- package/tests/config/helo.checks.ini +0 -52
- package/tests/connection.js +0 -327
- package/tests/endpoint.js +0 -128
- package/tests/fixtures/vm_harness.js +0 -59
- package/tests/logger.js +0 -327
- package/tests/outbound/hmail.js +0 -112
- package/tests/outbound/index.js +0 -324
- package/tests/outbound/qfile.js +0 -67
- package/tests/outbound_bounce_net_errors.js +0 -173
- package/tests/plugins/auth/auth_base.js +0 -463
- package/tests/plugins/auth/auth_vpopmaild.js +0 -91
- package/tests/plugins/bounce.js +0 -307
- package/tests/plugins/clamd.js +0 -224
- package/tests/plugins/deprecated/relay_acl.js +0 -140
- package/tests/plugins/deprecated/relay_all.js +0 -59
- package/tests/plugins/dkim_sign.js +0 -315
- package/tests/plugins/dkim_signer.js +0 -108
- package/tests/plugins/dns_list_base.js +0 -259
- package/tests/plugins/dnsbl.js +0 -101
- package/tests/plugins/early_talker.js +0 -115
- package/tests/plugins/greylist.js +0 -58
- package/tests/plugins/helo.checks.js +0 -525
- package/tests/plugins/mail_from.is_resolvable.js +0 -116
- package/tests/plugins/queue/smtp_forward.js +0 -221
- package/tests/plugins/rcpt_to.host_list_base.js +0 -132
- package/tests/plugins/rcpt_to.in_host_list.js +0 -218
- package/tests/plugins/relay.js +0 -339
- package/tests/plugins/spamassassin.js +0 -171
- package/tests/plugins/status.js +0 -138
- package/tests/plugins/tls.js +0 -84
- package/tests/plugins.js +0 -247
- package/tests/rfc1869.js +0 -61
- package/tests/server.js +0 -510
- package/tests/smtp_client/auth.js +0 -105
- package/tests/smtp_client/basic.js +0 -101
- package/tests/smtp_client.js +0 -80
- package/tests/tls_socket.js +0 -333
- package/tests/transaction.js +0 -284
- /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
- /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
- /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
- /package/docs/{plugins → deprecated}/dnswl.md +0 -0
- /package/docs/{plugins → deprecated}/rcpt_to.routes.md +0 -0
- /package/{tests → test}/.eslintrc.yaml +0 -0
- /package/{tests → test}/config/auth_flat_file.ini +0 -0
- /package/{tests → test}/config/dhparams.pem +0 -0
- /package/{tests → test}/config/host_list +0 -0
- /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
- /package/{tests → test}/config/outbound_tls_key.pem +0 -0
- /package/{tests → test}/config/smtp_forward.ini +0 -0
- /package/{tests → test}/config/tls/ec.pem +0 -0
- /package/{tests → test}/config/tls/haraka.local.pem +0 -0
- /package/{tests → test}/config/tls/mismatched.pem +0 -0
- /package/{tests → test}/config/tls.ini +0 -0
- /package/{tests → test}/config/tls_cert.pem +0 -0
- /package/{tests → test}/config/tls_key.pem +0 -0
- /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
- /package/{tests → test}/installation/config/test-plugin-flat +0 -0
- /package/{tests → test}/installation/config/test-plugin.ini +0 -0
- /package/{tests → test}/installation/config/tls.ini +0 -0
- /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
- /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
- /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
- /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
- /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
- /package/{tests → test}/installation/plugins/inherits.js +0 -0
- /package/{tests → test}/installation/plugins/load_first.js +0 -0
- /package/{tests → test}/installation/plugins/plugin.js +0 -0
- /package/{tests → test}/installation/plugins/tls.js +0 -0
- /package/{tests → test}/loud/config/dhparams.pem +0 -0
- /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
- /package/{tests → test}/loud/config/tls.ini +0 -0
- /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
- /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
- /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
- /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
- /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
- /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
- /package/{tests → test}/queue/zero-length +0 -0
- /package/{tests → test}/test-queue/delete-me +0 -0
package/docs/Transaction.md
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
Transaction Object
|
|
2
|
-
==================
|
|
1
|
+
# Transaction Object
|
|
3
2
|
|
|
4
3
|
An SMTP transaction is valid from MAIL FROM time until RSET or "final-dot".
|
|
5
4
|
|
|
6
|
-
API
|
|
7
|
-
---
|
|
5
|
+
## API
|
|
8
6
|
|
|
9
7
|
* transaction.uuid
|
|
10
8
|
|
|
11
|
-
A unique UUID for this transaction. Is equal to the connection.uuid + '.N'
|
|
12
|
-
where N increments for each transaction on this connection.
|
|
9
|
+
A unique UUID for this transaction. Is equal to the connection.uuid + '.N' where N increments for each transaction on this connection.
|
|
13
10
|
|
|
14
11
|
* transaction.mail\_from
|
|
15
12
|
|
|
16
|
-
The value of the MAIL FROM command
|
|
13
|
+
The value of the MAIL FROM command is an `Address`[1] object.
|
|
17
14
|
|
|
18
15
|
* transaction.rcpt\_to
|
|
19
16
|
|
|
@@ -25,13 +22,13 @@ A node.js Readable Stream object for the message.
|
|
|
25
22
|
|
|
26
23
|
You use it like this:
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
```js
|
|
26
|
+
transaction.message_stream.pipe(WritableStream, options)
|
|
27
|
+
```
|
|
29
28
|
|
|
30
|
-
Where WritableStream is a node.js Writable Stream object such as a
|
|
31
|
-
net.socket, fs.writableStream, process.stdout/stderr or custom stream.
|
|
29
|
+
Where WritableStream is a node.js Writable Stream object such as a net.socket, fs.writableStream, process.stdout/stderr or custom stream.
|
|
32
30
|
|
|
33
|
-
The options argument should be an object that overrides the following
|
|
34
|
-
properties:
|
|
31
|
+
The options argument should be an object that overrides the following properties:
|
|
35
32
|
|
|
36
33
|
* line_endings (default: "\r\n")
|
|
37
34
|
* dot_stuffing (default: false)
|
|
@@ -42,7 +39,9 @@ properties:
|
|
|
42
39
|
|
|
43
40
|
e.g.
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
```js
|
|
43
|
+
transaction.message_stream.pipe(socket, { dot_stuffing: true, ending_dot: true });
|
|
44
|
+
```
|
|
46
45
|
|
|
47
46
|
* transaction.data\_bytes
|
|
48
47
|
|
|
@@ -50,8 +49,7 @@ The number of bytes in the email after DATA.
|
|
|
50
49
|
|
|
51
50
|
* transaction.add\_data(line)
|
|
52
51
|
|
|
53
|
-
Adds a line of data to the email. Note this is RAW email - it isn't useful
|
|
54
|
-
for adding banners to the email.
|
|
52
|
+
Adds a line of data to the email. Note this is RAW email - it isn't useful for adding banners to the email.
|
|
55
53
|
|
|
56
54
|
* transaction.notes
|
|
57
55
|
|
|
@@ -59,8 +57,7 @@ A safe place to store transaction specific values. See also [haraka-results](htt
|
|
|
59
57
|
|
|
60
58
|
* transaction.add\_leading\_header(key, value)
|
|
61
59
|
|
|
62
|
-
Adds a header to the top of the header list. This should only be used in
|
|
63
|
-
very specific cases. Most people will want to use `add_header()` instead.
|
|
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.
|
|
64
61
|
|
|
65
62
|
* transaction.add\_header(key, value)
|
|
66
63
|
|
|
@@ -76,8 +73,7 @@ The header of the email. See `Header Object`.
|
|
|
76
73
|
|
|
77
74
|
* transaction.parse\_body = true|false [default: false]
|
|
78
75
|
|
|
79
|
-
Set to `true` to enable parsing of the mail body. Make sure you set this in
|
|
80
|
-
hook\_data or before.
|
|
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.
|
|
81
77
|
|
|
82
78
|
* transaction.body
|
|
83
79
|
|
|
@@ -85,81 +81,62 @@ The body of the email if you set `parse_body` above. See `Body Object`.
|
|
|
85
81
|
|
|
86
82
|
* transaction.attachment\_hooks(start)
|
|
87
83
|
|
|
88
|
-
Sets a callback for when we see an attachment
|
|
89
|
-
|
|
90
|
-
The `start` event will receive `(content_type, filename, body, stream)` as
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
stream.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
stream.pipe(ws);
|
|
125
|
-
stream.resume();
|
|
126
|
-
ws.on('close', function () {
|
|
127
|
-
connection.loginfo("End of stream reached");
|
|
128
|
-
fs.fstat(fd, function (err, stats) {
|
|
129
|
-
connection.loginfo("Got data of length: " + stats.size);
|
|
130
|
-
// Close the tmp file descriptor
|
|
131
|
-
fs.close(fd, function(){});
|
|
132
|
-
});
|
|
84
|
+
Sets a callback for when we see an attachment.
|
|
85
|
+
|
|
86
|
+
The `start` event will receive `(content_type, filename, body, stream)` as parameters.
|
|
87
|
+
|
|
88
|
+
The stream is a [ReadableStream](http://nodejs.org/api/stream.html)
|
|
89
|
+
|
|
90
|
+
If you set stream.connection then the stream will apply backpressure to the connection, allowing you to process attachments before the connection has ended. Here is an example which stores attachments in temporary files using the `tmp` library from npm and tells us the size of the file:
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
exports.hook_data = function (next, connection) {
|
|
94
|
+
// enable mail body parsing
|
|
95
|
+
connection.transaction.attachment_hooks(
|
|
96
|
+
function (ct, fn, body, stream) {
|
|
97
|
+
start_att(connection, ct, fn, body, stream)
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
next();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function start_att (connection, ct, fn, body, stream) {
|
|
104
|
+
connection.loginfo(`Got attachment: ${ct}, ${fn} for user id: ${connection.transaction.notes.hubdoc_user.email}`)
|
|
105
|
+
connection.transaction.notes.attachment_count++
|
|
106
|
+
|
|
107
|
+
stream.connection = connection; // Allow backpressure
|
|
108
|
+
stream.pause();
|
|
109
|
+
|
|
110
|
+
require('tmp').file((err, path, fd) => {
|
|
111
|
+
connection.loginfo(`Got tempfile: ${path} (${fd})`)
|
|
112
|
+
const ws = fs.createWriteStream(path)
|
|
113
|
+
stream.pipe(ws);
|
|
114
|
+
stream.resume();
|
|
115
|
+
ws.on('close', () => {
|
|
116
|
+
connection.loginfo("End of stream reached");
|
|
117
|
+
fs.fstat(fd, (err, stats) => {
|
|
118
|
+
connection.loginfo(`Got data of length: ${stats.size}`);
|
|
119
|
+
fs.close(fd, () => {}); // Close the tmp file descriptor
|
|
133
120
|
});
|
|
134
121
|
});
|
|
135
|
-
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
```
|
|
136
125
|
|
|
137
126
|
* transaction.discard\_data = true|false [default: false]
|
|
138
127
|
|
|
139
|
-
Set this flag to true to discard all data as it arrives and not store in
|
|
140
|
-
memory or on disk (in the message\_stream property). You can still access
|
|
141
|
-
the attachments and body if you set parse\_body to true. This is useful
|
|
142
|
-
for systems which do not need the full email, just the attachments or
|
|
143
|
-
mail text.
|
|
128
|
+
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.
|
|
144
129
|
|
|
145
130
|
* transaction.set\_banner(text, html)
|
|
146
131
|
|
|
147
|
-
Sets a banner to be added to the end of the email. If the html part is not
|
|
148
|
-
given (optional) then the text part will have each line ending replaced with
|
|
149
|
-
`<br/>` when being inserted into HTML parts.
|
|
132
|
+
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.
|
|
150
133
|
|
|
151
134
|
* transaction.add\_body\_filter(ct_match, filter)
|
|
152
135
|
|
|
153
|
-
Adds a filter to be applied to body parts in the email.
|
|
154
|
-
regular expression to match against the full content-type line, or a string to
|
|
155
|
-
match at the start, e.g. `/^text\/html/` or `'text/plain'`. filter will be
|
|
156
|
-
called when each body part matching ct_match is complete. It receives three
|
|
157
|
-
parameters, the content-type line, the encoding name, and a buffer with the
|
|
158
|
-
full body part. It should return a buffer with the desired contents of the
|
|
159
|
-
body in the same encoding.
|
|
136
|
+
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.
|
|
160
137
|
|
|
161
138
|
* transaction.results
|
|
162
139
|
|
|
163
|
-
Store results of processing in a structured format.
|
|
140
|
+
Store [results](https://github.com/haraka/haraka-results) of processing in a structured format.
|
|
164
141
|
|
|
165
|
-
[1]: `Address` objects are address-rfc2821
|
|
142
|
+
[1]: `Address` objects are [address-rfc2821](https://github.com/haraka/node-address-rfc2821) objects.
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
auth/auth\_vpopmaild
|
|
2
|
-
===============
|
|
1
|
+
# auth/auth\_vpopmaild
|
|
3
2
|
|
|
4
|
-
The `auth/vpopmaild` plugin allows
|
|
5
|
-
daemon.
|
|
3
|
+
The `auth/vpopmaild` plugin allows SMTP users to authenticate against a vpopmaild daemon.
|
|
6
4
|
|
|
7
5
|
## Configuration
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
style formatting.
|
|
7
|
+
The configuration file is stored in `config/auth_vpopmaild.ini`.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
### settings
|
|
13
10
|
|
|
14
11
|
* host: The host/IP that vpopmaild is listening on (default: localhost).
|
|
15
12
|
|
|
16
13
|
* port: The TCP port that vpopmaild is listening on (default: 89).
|
|
17
14
|
|
|
18
|
-
* sysadmin: A colon separated username:password of a vpopmail user with
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
password. On new installs, it's best not to use CRAM-MD5, as it requires
|
|
22
|
-
storing clear text passwords. Legacy clients with MUAs configured
|
|
23
|
-
to authenticate with CRAM-MD5 will need this enabled.
|
|
15
|
+
* sysadmin: A colon separated username:password of a vpopmail user with SYSADMIN privileges (see vpopmail/bin/vmoduser -S). This is **only** necessary to support CRAM-MD5 which requires access to the clear text password. On new installs, it's best not to use CRAM-MD5, as it requires storing clear text passwords. Legacy clients with MUAs configured to authenticate with CRAM-MD5 will need this enabled.
|
|
16
|
+
|
|
17
|
+
* constrain_sender: (default: true). For outbound messages (due to successful AUTH), constrain the envelope sender (MAIL FROM) to the same domain as the authenticated user. This setting, combined with `rate_rcpt_sender` in the [limit](https://github.com/haraka/haraka-plugin-limit) plugin can dramatically reduce the amount of backscatter and spam sent when an email account is compromised.
|
|
24
18
|
|
|
25
19
|
|
|
26
20
|
### Per-domain Configuration
|
|
@@ -29,10 +23,12 @@ Additionally, domains can each have their own configuration for connecting
|
|
|
29
23
|
to vpopmaild. The defaults are the same, so only the differences needs to
|
|
30
24
|
be declared. Example:
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
```ini
|
|
27
|
+
[example.com]
|
|
28
|
+
host=192.168.0.1
|
|
29
|
+
port=999
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
[example2.com]
|
|
32
|
+
host=192.168.0.2
|
|
33
|
+
sysadmin=postmaster@example2.com:sekret
|
|
34
|
+
```
|
|
@@ -1,47 +1,40 @@
|
|
|
1
|
-
auth/flat\_file
|
|
2
|
-
==============
|
|
1
|
+
# auth/flat\_file
|
|
3
2
|
|
|
4
|
-
The `auth/flat_file` plugin allows you to create a file containing username
|
|
5
|
-
and password combinations, and have relaying users authenticate from that
|
|
6
|
-
file.
|
|
3
|
+
The `auth/flat_file` plugin allows you to create a file containing username and password combinations, and have relaying users authenticate from that file.
|
|
7
4
|
|
|
8
|
-
Note that passwords are stored in clear-text, so this may not be a great idea
|
|
9
|
-
for large scale systems. However the plugin would be a good start for someone
|
|
10
|
-
looking to implement authentication using some other form of auth.
|
|
5
|
+
Note that passwords are stored in clear-text, so this may not be a great idea for large scale systems. However the plugin would be a good start for someone looking to implement authentication using some other form of auth.
|
|
11
6
|
|
|
12
|
-
**Security** - it is recommended to switch to [auth-encfile][url-authencflat]
|
|
13
|
-
to protect your user credentials.
|
|
7
|
+
**Security** - it is recommended to switch to [auth-encfile][url-authencflat] to protect your user credentials.
|
|
14
8
|
|
|
15
|
-
**IMPORANT NOTE** - this plugin requires that STARTTLS be used via the tls plugin
|
|
16
|
-
|
|
17
|
-
improve security out-of-the-box. Localhost and any IP in RFC1918 ranges
|
|
18
|
-
are automatically exempt from this rule.
|
|
9
|
+
**IMPORANT NOTE** - this plugin requires that STARTTLS be used via the tls plugin before it will advertise AUTH capabilities by the EHLO command. Localhost and IPs in RFC1918 ranges
|
|
10
|
+
are exempt from this rule.
|
|
19
11
|
|
|
20
|
-
Configuration
|
|
21
|
-
-------------
|
|
12
|
+
## Configuration
|
|
22
13
|
|
|
23
|
-
Configuration is stored in `config/auth_flat_file.ini
|
|
24
|
-
style formatting.
|
|
14
|
+
Configuration is stored in `config/auth_flat_file.ini`.
|
|
25
15
|
|
|
26
|
-
|
|
27
|
-
parameter. Lists of authentification methods are comma separated. Currently
|
|
28
|
-
supported methods are: `CRAM-MD5`, `PLAIN` and `LOGIN`. The `PLAIN`
|
|
29
|
-
and `LOGIN` methods are not secure. That is why TLS is required before AUTH is
|
|
30
|
-
offered.
|
|
16
|
+
* [core]methods
|
|
31
17
|
|
|
32
|
-
|
|
18
|
+
Authentication methods are listed in the `[core]methods` parameter. Authentification methods are comma separated. Currently supported methods are: `CRAM-MD5`, `PLAIN` and `LOGIN`. The `PLAIN` and `LOGIN` methods are insecure and require TLS to be enabled.
|
|
19
|
+
|
|
20
|
+
* [core]constrain_sender: (default: true). For outbound messages (due to successful AUTH), constrain the envelope sender (MAIL FROM) to the same domain as the authenticated user. This setting, combined with `rate_rcpt_sender` in the [limit](https://github.com/haraka/haraka-plugin-limit) plugin can dramatically reduce the amount of backscatter and spam sent when an email account is compromised.
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
methods=PLAIN,LOGIN,CRAM-MD5
|
|
22
|
+
Example:
|
|
36
23
|
|
|
24
|
+
```ini
|
|
25
|
+
[core]
|
|
26
|
+
methods=PLAIN,LOGIN,CRAM-MD5
|
|
27
|
+
constrain_sender=true
|
|
28
|
+
```
|
|
37
29
|
|
|
38
30
|
Users are stored in the `[users]` section.
|
|
39
31
|
|
|
40
32
|
Example:
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
```ini
|
|
35
|
+
[users]
|
|
36
|
+
user1=password1
|
|
37
|
+
user@domain.com=password2
|
|
38
|
+
```
|
|
46
39
|
|
|
47
40
|
[url-authencflat]: https://github.com/AuspeXeu/haraka-plugin-auth-enc-file
|
|
@@ -36,5 +36,12 @@ Configuration
|
|
|
36
36
|
durable = true
|
|
37
37
|
autoDelete = false
|
|
38
38
|
|
|
39
|
+
; Optional queue arguments
|
|
40
|
+
; More information about x-arguments can be found at https://www.rabbitmq.com/queues.html#optional-arguments
|
|
41
|
+
[queue_args]
|
|
42
|
+
x-dead-letter-exchange =
|
|
43
|
+
x-dead-letter-routing-key = emails_dlq
|
|
44
|
+
x-overflow = reject-publish
|
|
45
|
+
x-queue-type = quorum
|
|
39
46
|
|
|
40
47
|
More information about RabbitMQ can be found at https://www.rabbitmq.com/
|
|
@@ -100,4 +100,4 @@ enable\_outbound can be set or unset on a per-domain level to enable or disable
|
|
|
100
100
|
|
|
101
101
|
# Split host forward routing
|
|
102
102
|
|
|
103
|
-
When an incoming email transaction has multiple recipients with different forward routes,
|
|
103
|
+
When an incoming email transaction has multiple recipients with different forward routes, recipients to subsequent forward routes are deferred. Example: an incoming email transaction has recipients user@example1.com, user@example2.com, and user@example3.com. The first two recipients will be accepted (they share the same forward destination) and the latter will be deferred. It will arrive in a future delivery attempt by the remote.
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
# queue/smtp\_proxy
|
|
2
2
|
================
|
|
3
3
|
|
|
4
|
-
This plugin delivers to another mail server. This is a common setup when you
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
MAIL FROM time to the ongoing SMTP server. This can be a benefit in that
|
|
10
|
-
you get any SMTP-time filtering that the ongoing server provides, in
|
|
11
|
-
particular one important facility to some setups is recipient filtering.
|
|
12
|
-
However be aware that other than connect and HELO-time filtering, you will
|
|
13
|
-
have as many connections to your ongoing SMTP server as you have to Haraka.
|
|
4
|
+
This plugin delivers to another mail server. This is a common setup when you want to have a mail server with a solid pedigree of outbound delivery to other hosts, and inbound delivery to users.
|
|
5
|
+
|
|
6
|
+
In comparison to `queue/smtp_forward`, this plugin makes a connection at MAIL FROM time to the ongoing SMTP server. This can be a benefit in that you get any SMTP-time filtering that the ongoing server provides, in particular one important facility to some setups is recipient filtering.
|
|
7
|
+
|
|
8
|
+
Be aware that other than connect and HELO-time filtering, you will have as many connections to your ongoing SMTP server as you have to Haraka.
|
|
14
9
|
|
|
15
10
|
## Configuration
|
|
16
11
|
-------------
|
package/docs/plugins/relay.md
CHANGED
|
@@ -8,7 +8,7 @@ This **relay** plugin provides Haraka with options for managing relay permission
|
|
|
8
8
|
|
|
9
9
|
## Authentication
|
|
10
10
|
|
|
11
|
-
One way to enable relaying is [
|
|
11
|
+
One way to enable relaying is authentication via the [auth plugins](http://haraka.github.io/plugins). Successful authentication enables relaying during _that_ SMTP connection. To securely offer SMTP AUTH, the [tls](http://haraka.github.io/plugins/tls) plugin and at least one auth plugin must be enabled and properly configured. When that requirement is met, the AUTH SMTP extension will be advertised to SMTP clients.
|
|
12
12
|
|
|
13
13
|
% nc mail.example.com 587
|
|
14
14
|
220 mail.example.com ESMTP Haraka 2.4.0 ready
|
|
@@ -118,7 +118,7 @@ Example:
|
|
|
118
118
|
[domains]
|
|
119
119
|
test.com = { "action": "accept" }
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
Think of *accept* as the equivalent of qmail's *rcpthosts*, or a misplaced Haraka `rcpt_to.*` plugin. The *accept* mechanism is another way to tell Haraka that a particular domain is one we accept mail for. The difference between this and the [rcpt_to.in_host_list](http://haraka.github.io/plugins/rcpt_to.in_host_list) plugin is that this one also enables relaying.
|
|
122
122
|
|
|
123
123
|
* continue (mails are subject to further checks)
|
|
124
124
|
|
package/docs/plugins/tls.md
CHANGED
|
@@ -4,9 +4,11 @@ This plugin enables the use of TLS (via `STARTTLS`) in Haraka.
|
|
|
4
4
|
|
|
5
5
|
For this plugin to work you must have SSL certificates installed correctly.
|
|
6
6
|
|
|
7
|
+
Haraka has [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) support. When the remote MUA/MTA presents a servername during the TLS handshake and a TLS certificate with that Common Name matches, that certificate will be presented. If no match is found, the default certificate (see Certificate Files) is presented.
|
|
8
|
+
|
|
7
9
|
## Certificate Files
|
|
8
10
|
|
|
9
|
-
Defaults are shown and can be overridden in `config/tls.ini`.
|
|
11
|
+
Defaults settings are shown and can be overridden in `config/tls.ini`.
|
|
10
12
|
|
|
11
13
|
```ini
|
|
12
14
|
key=tls_key.pem
|
|
@@ -16,20 +18,39 @@ dhparam=dhparams.pem
|
|
|
16
18
|
|
|
17
19
|
## Certificate Directory
|
|
18
20
|
|
|
19
|
-
If the directory `config/tls` exists,
|
|
21
|
+
If the directory `config/tls` exists, files within the directory are PEM encoded TLS files in one of two formats: bundles or Wild Wild West.
|
|
22
|
+
|
|
23
|
+
### Certificate bundles
|
|
24
|
+
|
|
25
|
+
Generate PEM bundles in The Usual Way[TM] by concatenating the key, certificate, and CA/chain certs in that order. Example:
|
|
20
26
|
|
|
21
27
|
```sh
|
|
22
|
-
cat example.com.key example.com.crt ca.crt > config/tls/example.com.pem
|
|
28
|
+
cat example.com.key example.com.crt ca-int.crt > haraka/config/tls/example.com.pem
|
|
23
29
|
```
|
|
24
30
|
|
|
25
|
-
An example [acme.sh](https://acme.sh) deployment [script](https://github.com/msimerson/Mail-Toaster-6/blob/master/provision/letsencrypt.sh)
|
|
31
|
+
An example [acme.sh](https://acme.sh) deployment [script](https://github.com/msimerson/Mail-Toaster-6/blob/master/provision/letsencrypt.sh) installs [Let's Encrypt](https://letsencrypt.org) certificate bundles to the Haraka `config/tls`directory.
|
|
32
|
+
|
|
33
|
+
### Wild Wild West
|
|
34
|
+
|
|
35
|
+
PEM encoded TLS certificates and keys can be stored in files in `config/tls`. The certificate loader is recursive, so TLS files can be in subdirs like `config/tls/mx1.example.com`. The certificate names are parsed from the 1st cert in each file and indexed by the certs Common Name(s). Subject Alternate Names are supported. The file name containing the certificates does *not* matter. Additional certificates within each file are presumed to be CA chain (intermediate) certificates.
|
|
36
|
+
|
|
37
|
+
If the TLS key is stored in the same file as the matching certificate, then the name of the file does not matter. If the TLS key is alone in a file, the file MUST be named with the keys Common Name. The file extension does not matter, `.pem` and `.key` are common. If the key is used for multiple CNs, the key must be stored in a file name matching each CN. Examples of working TLS key/cert file pairs for the Common Name mx1.example.com:
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
1. certificate bundle (see above), key & cert in same file
|
|
40
|
+
- config/tls/mx1.example.com.pem (recommended)
|
|
41
|
+
- config/tls/any-unique-name.pem (CN is extracted from 1st cert)
|
|
42
|
+
2. files in TLS dir
|
|
43
|
+
- config/tls/mx1.example.com.crt
|
|
44
|
+
- config/tls/mx1.example.com.key
|
|
45
|
+
3. files in subdir
|
|
46
|
+
- config/tls/example.com/mx1.cert
|
|
47
|
+
- config/tls/example.com/mx1.example.com.key
|
|
48
|
+
4. wildcard bundle on Windows platform (* is not allowed in file names)
|
|
49
|
+
- config/tls/_.example.com.pem
|
|
28
50
|
|
|
29
51
|
## Purchased Certificate
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
files to the certificate in this order:
|
|
53
|
+
For purchased certificate, append any intermediate/chained/ca-cert files to the certificate in this order:
|
|
33
54
|
|
|
34
55
|
1. The CA signed SSL cert
|
|
35
56
|
2. Any intermediate certificates
|
|
@@ -39,8 +60,7 @@ See also [Setting Up TLS](https://github.com/haraka/Haraka/wiki/Setting-up-TLS-w
|
|
|
39
60
|
|
|
40
61
|
## Self Issued (unsigned) Certificate
|
|
41
62
|
|
|
42
|
-
Create a certificate and key file in the config directory with the following
|
|
43
|
-
command:
|
|
63
|
+
Create a certificate and key file in the config directory with the following command:
|
|
44
64
|
|
|
45
65
|
openssl req -x509 -nodes -days 2190 -newkey rsa:2048 \
|
|
46
66
|
-keyout config/tls_key.pem -out config/tls_cert.pem
|
package/endpoint.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// Socket address parser/formatter and server binding helper
|
|
3
3
|
|
|
4
|
-
const fs = require('fs');
|
|
4
|
+
const fs = require('node:fs/promises');
|
|
5
5
|
const sockaddr = require('sockaddr');
|
|
6
6
|
|
|
7
7
|
module.exports = function endpoint (addr, defaultPort) {
|
|
@@ -46,21 +46,24 @@ class Endpoint {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Make server listen on this endpoint, w/optional options
|
|
49
|
-
bind (server, opts) {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
async bind (server, opts) {
|
|
50
|
+
opts = {...opts};
|
|
51
|
+
|
|
52
|
+
const mode = this.mode ? parseInt(this.mode, 8) : false;
|
|
52
53
|
if (this.path) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
done = () => fs.chmodSync(path, mode);
|
|
57
|
-
}
|
|
58
|
-
if (fs.existsSync(path)) fs.unlinkSync(path);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
54
|
+
opts.path = this.path;
|
|
55
|
+
await fs.rm(this.path, { force: true }); // errors are ignored when force is true
|
|
56
|
+
} else {
|
|
61
57
|
opts.host = this.host;
|
|
62
58
|
opts.port = this.port;
|
|
63
59
|
}
|
|
64
|
-
|
|
60
|
+
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
server.listen(opts, async (err) => {
|
|
63
|
+
if(err) return reject(err);
|
|
64
|
+
if (mode) await fs.chmod(opts.path, mode);
|
|
65
|
+
resolve()
|
|
66
|
+
});
|
|
67
|
+
});
|
|
65
68
|
}
|
|
66
69
|
}
|
package/haraka.js
CHANGED
|
@@ -20,20 +20,18 @@ catch (e) {
|
|
|
20
20
|
require('module')._initPaths(); // Horrible hack
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const utils = require('haraka-utils');
|
|
24
24
|
const logger = require('./logger');
|
|
25
25
|
const server = require('./server');
|
|
26
26
|
|
|
27
|
-
exports.version =
|
|
28
|
-
fs.readFileSync(path.join(__dirname, './package.json'), 'utf8')
|
|
29
|
-
).version;
|
|
27
|
+
exports.version = utils.getVersion(__dirname)
|
|
30
28
|
|
|
31
29
|
process.on('uncaughtException', err => {
|
|
32
30
|
if (err.stack) {
|
|
33
|
-
err.stack.split("\n").forEach(line => logger.
|
|
31
|
+
err.stack.split("\n").forEach(line => logger.crit(line));
|
|
34
32
|
}
|
|
35
33
|
else {
|
|
36
|
-
logger.
|
|
34
|
+
logger.crit(`Caught exception: ${JSON.stringify(err)}`);
|
|
37
35
|
}
|
|
38
36
|
logger.dump_and_exit(1);
|
|
39
37
|
});
|
|
@@ -41,18 +39,16 @@ process.on('uncaughtException', err => {
|
|
|
41
39
|
let shutting_down = false;
|
|
42
40
|
const signals = ['SIGINT'];
|
|
43
41
|
|
|
44
|
-
if (process.pid === 1)
|
|
45
|
-
signals.push('SIGTERM')
|
|
46
|
-
}
|
|
42
|
+
if (process.pid === 1) signals.push('SIGTERM')
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
for (const sig of signals) {
|
|
49
45
|
process.on(sig, () => {
|
|
50
46
|
if (shutting_down) return process.exit(1);
|
|
51
47
|
shutting_down = true;
|
|
52
48
|
const [, filename] = process.argv;
|
|
53
49
|
process.title = path.basename(filename, '.js');
|
|
54
50
|
|
|
55
|
-
logger.
|
|
51
|
+
logger.notice(`${sig} received`);
|
|
56
52
|
logger.dump_and_exit(() => {
|
|
57
53
|
if (server.cluster?.isMaster) {
|
|
58
54
|
server.performShutdown();
|
|
@@ -62,10 +58,10 @@ signals.forEach((sig) => {
|
|
|
62
58
|
}
|
|
63
59
|
});
|
|
64
60
|
});
|
|
65
|
-
}
|
|
61
|
+
}
|
|
66
62
|
|
|
67
63
|
process.on('SIGHUP', () => {
|
|
68
|
-
logger.
|
|
64
|
+
logger.notice('Flushing the temp fail queue');
|
|
69
65
|
server.flushQueue();
|
|
70
66
|
});
|
|
71
67
|
|
|
@@ -74,7 +70,7 @@ process.on('exit', code => {
|
|
|
74
70
|
const [, filename] = process.argv;
|
|
75
71
|
process.title = path.basename(filename, '.js');
|
|
76
72
|
|
|
77
|
-
logger.
|
|
73
|
+
logger.notice('Shutting down');
|
|
78
74
|
logger.dump_logs();
|
|
79
75
|
});
|
|
80
76
|
|