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.
Files changed (267) hide show
  1. package/.eslintrc.yaml +5 -9
  2. package/.prettierrc.yml +1 -0
  3. package/CONTRIBUTORS.md +11 -0
  4. package/Changes.md +1393 -1211
  5. package/Dockerfile +3 -3
  6. package/Plugins.md +119 -106
  7. package/README.md +7 -16
  8. package/TODO +1 -24
  9. package/bin/haraka +197 -298
  10. package/config/auth_flat_file.ini +2 -0
  11. package/config/auth_vpopmaild.ini +4 -2
  12. package/config/dhparams.pem +8 -0
  13. package/config/mail_from.is_resolvable.ini +4 -2
  14. package/config/me +1 -0
  15. package/config/outbound.ini +0 -2
  16. package/config/plugins +36 -35
  17. package/config/rabbitmq_amqplib.ini +8 -1
  18. package/config/smtp.ini +0 -1
  19. package/config/smtp.json +17 -0
  20. package/config/tls_cert.pem +23 -0
  21. package/config/tls_key.pem +28 -0
  22. package/connection.js +46 -73
  23. package/contrib/bsd-rc.d/haraka +3 -1
  24. package/contrib/plugin2npm.sh +6 -36
  25. package/docs/Connection.md +1 -1
  26. package/docs/CoreConfig.md +2 -2
  27. package/docs/Logging.md +7 -21
  28. package/docs/Outbound.md +104 -210
  29. package/docs/Plugins.md +47 -40
  30. package/docs/Transaction.md +59 -82
  31. package/docs/{plugins → deprecated}/connect.rdns_access.md +1 -1
  32. package/docs/{plugins → deprecated}/mail_from.access.md +1 -1
  33. package/docs/{plugins → deprecated}/rcpt_to.access.md +1 -1
  34. package/docs/plugins/auth/auth_vpopmaild.md +15 -19
  35. package/docs/plugins/auth/flat_file.md +23 -30
  36. package/docs/plugins/queue/rabbitmq_amqplib.md +7 -0
  37. package/docs/plugins/queue/smtp_forward.md +1 -1
  38. package/docs/plugins/queue/smtp_proxy.md +5 -10
  39. package/docs/plugins/relay.md +2 -2
  40. package/docs/plugins/tls.md +29 -9
  41. package/endpoint.js +16 -13
  42. package/haraka.js +10 -14
  43. package/host_pool.js +5 -5
  44. package/line_socket.js +3 -4
  45. package/logger.js +44 -28
  46. package/outbound/client_pool.js +27 -23
  47. package/outbound/config.js +4 -6
  48. package/outbound/fsync_writestream.js +1 -1
  49. package/outbound/hmail.js +180 -220
  50. package/outbound/index.js +86 -99
  51. package/outbound/qfile.js +1 -1
  52. package/outbound/queue.js +55 -43
  53. package/outbound/timer_queue.js +3 -2
  54. package/outbound/tls.js +19 -7
  55. package/package.json +66 -55
  56. package/plugins/.eslintrc.yaml +0 -6
  57. package/plugins/auth/auth_base.js +30 -12
  58. package/plugins/auth/auth_proxy.js +14 -12
  59. package/plugins/auth/auth_vpopmaild.js +30 -20
  60. package/plugins/auth/flat_file.js +17 -12
  61. package/plugins/block_me.js +1 -1
  62. package/plugins/data.signatures.js +2 -4
  63. package/plugins/early_talker.js +2 -1
  64. package/plugins/mail_from.is_resolvable.js +65 -135
  65. package/plugins/queue/deliver.js +4 -5
  66. package/plugins/queue/lmtp.js +11 -14
  67. package/plugins/queue/qmail-queue.js +2 -2
  68. package/plugins/queue/quarantine.js +2 -2
  69. package/plugins/queue/rabbitmq.js +16 -17
  70. package/plugins/queue/rabbitmq_amqplib.js +1 -1
  71. package/plugins/queue/smtp_forward.js +6 -6
  72. package/plugins/queue/smtp_proxy.js +10 -1
  73. package/plugins/queue/test.js +2 -2
  74. package/plugins/rcpt_to.host_list_base.js +5 -5
  75. package/plugins/rcpt_to.in_host_list.js +2 -2
  76. package/plugins/relay.js +6 -7
  77. package/plugins/reseed_rng.js +1 -1
  78. package/plugins/status.js +37 -33
  79. package/plugins/tls.js +2 -2
  80. package/plugins/xclient.js +3 -2
  81. package/plugins.js +51 -54
  82. package/run_tests +3 -30
  83. package/server.js +190 -190
  84. package/smtp_client.js +30 -23
  85. package/{tests → test}/config/plugins +0 -2
  86. package/{tests → test}/config/smtp.ini +1 -1
  87. package/test/config/tls/example.com/_.example.com.key +28 -0
  88. package/test/config/tls/example.com/example.com.crt +25 -0
  89. package/test/connection.js +302 -0
  90. package/test/endpoint.js +94 -0
  91. package/{tests → test}/fixtures/line_socket.js +1 -1
  92. package/{tests → test}/fixtures/util_hmailitem.js +19 -25
  93. package/{tests → test}/host_pool.js +42 -57
  94. package/test/logger.js +258 -0
  95. package/test/outbound/hmail.js +141 -0
  96. package/test/outbound/index.js +220 -0
  97. package/test/outbound/qfile.js +126 -0
  98. package/test/outbound_bounce_net_errors.js +142 -0
  99. package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
  100. package/test/plugins/auth/auth_base.js +484 -0
  101. package/test/plugins/auth/auth_vpopmaild.js +83 -0
  102. package/test/plugins/early_talker.js +104 -0
  103. package/test/plugins/mail_from.is_resolvable.js +35 -0
  104. package/test/plugins/queue/smtp_forward.js +206 -0
  105. package/test/plugins/rcpt_to.host_list_base.js +122 -0
  106. package/test/plugins/rcpt_to.in_host_list.js +193 -0
  107. package/test/plugins/relay.js +303 -0
  108. package/test/plugins/status.js +130 -0
  109. package/test/plugins/tls.js +70 -0
  110. package/test/plugins.js +228 -0
  111. package/{tests → test}/queue/multibyte +0 -0
  112. package/{tests → test}/queue/plain +0 -0
  113. package/test/rfc1869.js +73 -0
  114. package/test/server.js +491 -0
  115. package/test/smtp_client.js +299 -0
  116. package/test/tls_socket.js +273 -0
  117. package/test/transaction.js +270 -0
  118. package/tls_socket.js +202 -252
  119. package/transaction.js +9 -24
  120. package/CONTRIBUTING.md +0 -1
  121. package/bin/dkimverify +0 -40
  122. package/config/access.domains +0 -13
  123. package/config/attachment.ctype.regex +0 -2
  124. package/config/attachment.filename.regex +0 -1
  125. package/config/avg.ini +0 -5
  126. package/config/bounce.ini +0 -15
  127. package/config/data.headers.ini +0 -61
  128. package/config/dkim/dkim_key_gen.sh +0 -78
  129. package/config/dkim_sign.ini +0 -4
  130. package/config/dkim_verify.ini +0 -7
  131. package/config/dnsbl.ini +0 -23
  132. package/config/greylist.ini +0 -43
  133. package/config/helo.checks.ini +0 -52
  134. package/config/lookup_rdns.strict.ini +0 -12
  135. package/config/lookup_rdns.strict.timeout +0 -1
  136. package/config/lookup_rdns.strict.whitelist +0 -1
  137. package/config/lookup_rdns.strict.whitelist_regex +0 -5
  138. package/config/messagesniffer.ini +0 -18
  139. package/config/rcpt_to.blocklist +0 -1
  140. package/config/rdns.allow_regexps +0 -0
  141. package/config/rdns.deny_regexps +0 -0
  142. package/config/spamassassin.ini +0 -56
  143. package/config.js +0 -6
  144. package/dkim.js +0 -614
  145. package/docs/plugins/avg.md +0 -35
  146. package/docs/plugins/bounce.md +0 -69
  147. package/docs/plugins/clamd.md +0 -147
  148. package/docs/plugins/esets.md +0 -8
  149. package/docs/plugins/greylist.md +0 -90
  150. package/docs/plugins/helo.checks.md +0 -135
  151. package/docs/plugins/messagesniffer.md +0 -163
  152. package/docs/plugins/relay_acl.md +0 -29
  153. package/docs/plugins/relay_all.md +0 -15
  154. package/docs/plugins/relay_force_routing.md +0 -33
  155. package/docs/plugins/spamassassin.md +0 -180
  156. package/outbound/mx_lookup.js +0 -70
  157. package/plugins/auth/auth_ldap.js +0 -3
  158. package/plugins/avg.js +0 -162
  159. package/plugins/backscatterer.js +0 -25
  160. package/plugins/bounce.js +0 -381
  161. package/plugins/clamd.js +0 -381
  162. package/plugins/data.headers.js +0 -4
  163. package/plugins/data.uribl.js +0 -4
  164. package/plugins/dkim_sign.js +0 -395
  165. package/plugins/dkim_verify.js +0 -62
  166. package/plugins/dns_list_base.js +0 -221
  167. package/plugins/dnsbl.js +0 -146
  168. package/plugins/dnswl.js +0 -58
  169. package/plugins/esets.js +0 -71
  170. package/plugins/graph.js +0 -5
  171. package/plugins/greylist.js +0 -645
  172. package/plugins/helo.checks.js +0 -533
  173. package/plugins/messagesniffer.js +0 -381
  174. package/plugins/rcpt_to.ldap.js +0 -3
  175. package/plugins/rcpt_to.max_count.js +0 -24
  176. package/plugins/relay_all.js +0 -13
  177. package/plugins/spamassassin.js +0 -384
  178. package/tests/config/dkim/example.com/dns +0 -29
  179. package/tests/config/dkim/example.com/private +0 -6
  180. package/tests/config/dkim/example.com/public +0 -4
  181. package/tests/config/dkim/example.com/selector +0 -1
  182. package/tests/config/dkim.private.key +0 -6
  183. package/tests/config/dkim_sign.ini +0 -4
  184. package/tests/config/helo.checks.ini +0 -52
  185. package/tests/connection.js +0 -327
  186. package/tests/endpoint.js +0 -128
  187. package/tests/fixtures/vm_harness.js +0 -59
  188. package/tests/logger.js +0 -327
  189. package/tests/outbound/hmail.js +0 -112
  190. package/tests/outbound/index.js +0 -324
  191. package/tests/outbound/qfile.js +0 -67
  192. package/tests/outbound_bounce_net_errors.js +0 -173
  193. package/tests/plugins/auth/auth_base.js +0 -463
  194. package/tests/plugins/auth/auth_vpopmaild.js +0 -91
  195. package/tests/plugins/bounce.js +0 -307
  196. package/tests/plugins/clamd.js +0 -224
  197. package/tests/plugins/deprecated/relay_acl.js +0 -140
  198. package/tests/plugins/deprecated/relay_all.js +0 -59
  199. package/tests/plugins/dkim_sign.js +0 -315
  200. package/tests/plugins/dkim_signer.js +0 -108
  201. package/tests/plugins/dns_list_base.js +0 -259
  202. package/tests/plugins/dnsbl.js +0 -101
  203. package/tests/plugins/early_talker.js +0 -115
  204. package/tests/plugins/greylist.js +0 -58
  205. package/tests/plugins/helo.checks.js +0 -525
  206. package/tests/plugins/mail_from.is_resolvable.js +0 -116
  207. package/tests/plugins/queue/smtp_forward.js +0 -221
  208. package/tests/plugins/rcpt_to.host_list_base.js +0 -132
  209. package/tests/plugins/rcpt_to.in_host_list.js +0 -218
  210. package/tests/plugins/relay.js +0 -339
  211. package/tests/plugins/spamassassin.js +0 -171
  212. package/tests/plugins/status.js +0 -138
  213. package/tests/plugins/tls.js +0 -84
  214. package/tests/plugins.js +0 -247
  215. package/tests/rfc1869.js +0 -61
  216. package/tests/server.js +0 -510
  217. package/tests/smtp_client/auth.js +0 -105
  218. package/tests/smtp_client/basic.js +0 -101
  219. package/tests/smtp_client.js +0 -80
  220. package/tests/tls_socket.js +0 -333
  221. package/tests/transaction.js +0 -284
  222. /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
  223. /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
  224. /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
  225. /package/docs/{plugins → deprecated}/dnswl.md +0 -0
  226. /package/docs/{plugins → deprecated}/rcpt_to.routes.md +0 -0
  227. /package/{tests → test}/.eslintrc.yaml +0 -0
  228. /package/{tests → test}/config/auth_flat_file.ini +0 -0
  229. /package/{tests → test}/config/dhparams.pem +0 -0
  230. /package/{tests → test}/config/host_list +0 -0
  231. /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
  232. /package/{tests → test}/config/outbound_tls_key.pem +0 -0
  233. /package/{tests → test}/config/smtp_forward.ini +0 -0
  234. /package/{tests → test}/config/tls/ec.pem +0 -0
  235. /package/{tests → test}/config/tls/haraka.local.pem +0 -0
  236. /package/{tests → test}/config/tls/mismatched.pem +0 -0
  237. /package/{tests → test}/config/tls.ini +0 -0
  238. /package/{tests → test}/config/tls_cert.pem +0 -0
  239. /package/{tests → test}/config/tls_key.pem +0 -0
  240. /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
  241. /package/{tests → test}/installation/config/test-plugin-flat +0 -0
  242. /package/{tests → test}/installation/config/test-plugin.ini +0 -0
  243. /package/{tests → test}/installation/config/tls.ini +0 -0
  244. /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
  245. /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
  246. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
  247. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
  248. /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
  249. /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
  250. /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
  251. /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
  252. /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
  253. /package/{tests → test}/installation/plugins/inherits.js +0 -0
  254. /package/{tests → test}/installation/plugins/load_first.js +0 -0
  255. /package/{tests → test}/installation/plugins/plugin.js +0 -0
  256. /package/{tests → test}/installation/plugins/tls.js +0 -0
  257. /package/{tests → test}/loud/config/dhparams.pem +0 -0
  258. /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
  259. /package/{tests → test}/loud/config/tls.ini +0 -0
  260. /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
  261. /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
  262. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  263. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  264. /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  265. /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  266. /package/{tests → test}/queue/zero-length +0 -0
  267. /package/{tests → test}/test-queue/delete-me +0 -0
package/docs/Logging.md CHANGED
@@ -17,20 +17,13 @@ Logging conventions within Haraka
17
17
 
18
18
  This section pertains to the built in logging. For log plugins like ([haraka-plugin-syslog](https://github.com/haraka/haraka-plugin-syslog)), refer to the plugin's docs.
19
19
 
20
- See also
21
- ------------------
22
- [https://github.com/haraka/Haraka/pull/119](https://github.com/haraka/Haraka/pull/119)
23
-
24
20
  The logline by default will be in the form of:
25
21
 
26
22
  [level] [uuid] [origin] message
27
23
 
28
- Where origin is "core" or the name of the plugin which
29
- triggered the message, and "uuid" is the ID of the
30
- connection associated with the message.
24
+ Where origin is "core" or the name of the plugin which triggered the message, and "uuid" is the ID of the connection associated with the message.
31
25
 
32
- When calling a log method on logger, you should provide the
33
- plugin object and the connection object anywhere in the arguments
26
+ When calling a log method on logger, you should provide the plugin object and the connection object anywhere in the arguments
34
27
  to the log method.
35
28
 
36
29
  logger.logdebug("i like turtles", plugin, connection);
@@ -39,8 +32,7 @@ Will yield, for example,
39
32
 
40
33
  [DEBUG] [7F1C820F-DC79-4192-9AA6-5307354B20A6] [dnsbl] i like turtles
41
34
 
42
- If you call the log method on the connection object, you can
43
- forego the connection as argument:
35
+ If you call the log method on the connection object, you can forego the connection as argument:
44
36
 
45
37
  connection.logdebug("turtles all the way down", plugin);
46
38
 
@@ -48,18 +40,13 @@ and similarly for the log methods on the plugin object:
48
40
 
49
41
  plugin.logdebug("he just really likes turtles", connection);
50
42
 
51
- failing to provide a connection and/or plugin object will leave
52
- the default values in the log (currently "core").
43
+ failing to provide a connection and/or plugin object will leavethe default values in the log (currently "core").
53
44
 
54
- This is implemented by testing for argument type in
55
- the logger.js log\* method. objects-as-arguments are then sniffed
56
- to try to determine if they're a connection or plugin instance.
45
+ This is implemented by testing for argument type in the logger.js log\* method. objects-as-arguments are then sniffed to try to determine if they're a connection or plugin instance.
57
46
 
58
47
  ### Log formats
59
48
 
60
- Apart from the default log format described above, Haraka also supports logging
61
- as [`logfmt`](https://brandur.org/logfmt) and JSON. These can be used by
62
- changing the `format` attribute in `log.ini` to the desired format, e.g.:
49
+ Apart from the default log format described above, Haraka also supports logging as [`logfmt`](https://brandur.org/logfmt) and JSON. These can be used by changing the `format` attribute in `log.ini` to the desired format, e.g.:
63
50
 
64
51
  ```ini
65
52
  ; format=default
@@ -77,8 +64,7 @@ And the same line formatted as JSON:
77
64
  {"level":"PROTOCOL","uuid":"9FF7F70E-5D57-435A-AAD9-EA069B6159D9.1","source":"core","message":"S: 354 go ahead, make my day"}
78
65
  ```
79
66
 
80
- Any objects passed to the log methods will also have their properties included
81
- in the log line. For example, using `logfmt`:
67
+ Any objects passed to the log methods will also have their properties included in the log line. For example, using `logfmt`:
82
68
 
83
69
  level=NOTICE uuid=9FF7F70E-5D57-435A-AAD9-EA069B6159D9.1 source=core message=disconnect ip=127.0.0.1 rdns=Unknown helo=3h2dnz8a0if relay=N early=N esmtp=N tls=N pipe=N errors=0 txns=1 rcpts=1/0/0 msgs=1/0/0 bytes=222 lr="" time=0.052
84
70
 
package/docs/Outbound.md CHANGED
@@ -1,71 +1,45 @@
1
- Outbound Mail with Haraka
2
- =========================
1
+ # Outbound Mail with Haraka
3
2
 
4
- A default installation of Haraka will queue outbound mail for delivery in the
5
- queue directory. Those mails will be delivered to the appropriate MX record
6
- for that domain. Mails are queued onto your disk, and will deal appropriately
7
- with temporary failures to retry delivery later.
3
+ A default installation of Haraka will queue outbound mail for delivery in the queue directory. Those mails will be delivered to the appropriate MX record for that domain. Mails are queued onto your disk, and will deal appropriately with temporary failures to retry delivery later.
8
4
 
9
- Outbound mails are defined as those that have set the `connection.relaying`
10
- flag to `true` via a plugin. The simplest way of doing that is to use SMTP
11
- AUTH, and have the client authenticate. For example using the `auth/flat_file`
12
- plugin. However it is very simple to write a custom plugin to do this.
5
+ Outbound mails are defined as those that have set the `connection.relaying` flag to `true` via a plugin. The simplest way of doing that is to use SMTP AUTH, and have the client authenticate. For example using the `auth/flat_file` plugin. The `relay` plugin provides common ways to set it and it is simple to write a custom plugin to do this.
13
6
 
14
- For statistics on outbound mail use the `process_title` plugin. See the
15
- documentation for that plugin for details.
7
+ For statistics on outbound mail use the `process_title` plugin. See the documentation for that plugin for details.
16
8
 
17
- To flush the outbound queue (for temporary failed mails) hit the Haraka master
18
- process with the SIGHUP signal (via the `kill` command line tool).
9
+ To flush the outbound queue (for temporary failed mails) hit the Haraka master process with the SIGHUP signal (via the `kill` command line tool).
19
10
 
20
- Outbound Configuration Files
21
- ----------------------------
11
+ ## Outbound Configuration Files
22
12
 
23
13
  ### outbound.ini
24
14
 
25
15
  * `disabled`
26
16
 
27
- Default: false. Allows one to temporarily disable outbound delivery, while
28
- still receiving and queuing emails. This can be changed while Haraka is
29
- running.
17
+ Default: false. Allows one to temporarily disable outbound delivery, while still receiving and queuing emails. This can be changed while Haraka is running.
30
18
 
31
19
  * `concurrency_max`
32
20
 
33
- Default: 100. Specifies the maximum concurrent connections to make. Note that
34
- if using cluster (multiple CPUs) then this will be multiplied by the number
35
- of CPUs that you have.
21
+ Default: 100. Specifies the maximum concurrent connections to make. Note that if using cluster (multiple CPUs) this will be multiplied by the number of CPUs that you have.
36
22
 
37
23
  * `enable_tls`
38
24
 
39
25
  Default: true. Switch to false to disable TLS for outbound mail.
40
26
 
41
- This uses the same `tls_key.pem` and `tls_cert.pem` files that the `tls`
42
- plugin uses, along with other values in `tls.ini`. See the [tls plugin
43
- docs](http://haraka.github.io/manual/plugins/tls.html) for information on generating those files.
27
+ This uses the same `tls_key.pem` and `tls_cert.pem` files that the `TLS` plugin uses, along with other values in `tls.ini`. See the [TLS plugin docs][url-tls] for more information.
44
28
 
45
29
  Within `tls.ini` you can specify global options for the values `ciphers`, `minVersion`, `requestCert` and `rejectUnauthorized`, alternatively you can provide separate values by putting them under a key: `[outbound]`, such as:
46
30
 
47
- ```
31
+ ```ini
48
32
  [outbound]
49
33
  ciphers=!DES
50
34
  ```
51
35
 
52
- * `ipv6_enabled`
53
-
54
- When this has a "true" value inside (usually a `1`), it defaults to an 'AAAA'
55
- lookup first for each MX record, and uses those hosts to send email via.
56
-
57
36
  * `always_split`
58
37
 
59
- Default: false. By default, Haraka groups message recipients by domain so that
60
- messages with multiple recipients at the same domain get sent in a single SMTP
61
- session. When `always_split` is enabled, each recipient gets a queue entry and
62
- delivery in its own SMTP session. This carries a performance penalty but
63
- enables more flexibility in mail delivery and bounce handling.
38
+ Default: false. By default, Haraka groups message recipients by domain so that messages with multiple recipients at the same domain get sent in a single SMTP session. When `always_split` is enabled, each recipient gets a queue entry and delivery in its own SMTP session. This carries a performance penalty but enables more flexibility in mail delivery and bounce handling.
64
39
 
65
40
  * `received_header`
66
41
 
67
- Default: "Haraka outbound". If this text is any string except *disabled*, the
68
- string is attached as a `Received` header to all outbound mail just before it is queued.
42
+ Default: "Haraka outbound". If this text is any string except *disabled*, the string is attached as a `Received` header to all outbound mail just before it is queued.
69
43
 
70
44
  * `connect_timeout`
71
45
 
@@ -73,69 +47,50 @@ Timeout for connecting to remote servers. Default: 30s
73
47
 
74
48
  * `local_mx_ok`
75
49
 
76
- Default: false. By default, outbound to a local IP is disabled, to avoid creating
77
- outbound loops. Set this to true if you want to allow outbound to local IPs.
78
- This could be useful if you want to deliver mail to localhost on another port.
50
+ Default: false. By default, outbound to a local IP is disabled, to avoid creating mail loops. Set this to true if you want to allow outbound to local IPs. This could be useful if you want to deliver mail to private IPs or localhost on another port.
79
51
 
80
52
  * `temp_fail_intervals`
81
53
 
82
- Set this to specify the delay intervals to use between trying to re-send an email
83
- that has a temporary failure condition. The setting is a comma separated list of
84
- time spans and multipliers. The time span is a number followed by `s`, `m`, `h`, or `d` to represent seconds, minutes, hours, and days, respectively. The multiplier is an asterisk followed by an integer representing the number of times to repeat the interval.
85
- For example, the entry `1m, 5m*2, 1h*3` results in an array of delay times of
54
+ Set this to specify the delay intervals to use between trying to re-send an email that has a temporary failure condition. The setting is a comma separated list of time spans and multipliers. The time span is a number followed by `s`, `m`, `h`, or `d` to represent seconds, minutes, hours, and days, respectively. The multiplier is an asterisk followed by an integer representing the number of times to repeat the interval. For example, the entry `1m, 5m*2, 1h*3` results in an array of delay times of
86
55
  `[60,300,300,3600,3600,3600]` in seconds. The email will be bounced when the array runs out of intervals (the 7th failure in this case). Set this to `none` to bounce the email on the first temporary failure.
87
56
 
88
57
  ### outbound.bounce\_message
89
58
 
90
59
  See "Bounce Messages" below for details.
91
60
 
92
- The HMail Object
93
- ----------------
61
+ ## The HMail Object
94
62
 
95
63
  Many hooks (see below) pass in a `hmail` object.
96
64
 
97
- You likely won't ever need to call methods on this object, so they are left
98
- undocumented here.
65
+ You likely won't ever need to call methods on this object, so they are left undocumented here.
99
66
 
100
67
  The attributes of an `hmail` object that may be of use are:
101
68
 
102
69
  * path - the full path to the queue file
103
70
  * filename - the filename within the queue dir
104
71
  * num_failures - the number of times this mail has been temp failed
105
- * notes - notes you can store on a hmail object (similar to `transaction.notes`)
106
- to allow you to pass information between outbound hooks
72
+ * notes - notes you can store on a hmail object (similar to `transaction.notes`) to allow you to pass information between outbound hooks
107
73
  * todo - see below
108
74
 
109
- The ToDo Object
110
- ---------------
75
+ ## The ToDo Object
111
76
 
112
- The `todo` object contains information about how to deliver this mail. Keys
113
- you may be interested in are:
77
+ The `todo` object contains information about how to deliver this mail. Keys you may be interested in are:
114
78
 
115
- * rcpt_to - an Array of `Address`[1] objects - the rfc.2821 recipients of this mail
116
- * mail_from - an `Address`[1] object - the rfc.2821 sender of this mail
79
+ * rcpt_to - an Array of `Address`<sup>[1](#fn1)</sup> objects - the rfc.2821 recipients of this mail
80
+ * mail_from - an Address<sup>[1](#fn1)</sup> object - the rfc.2821 sender of this mail
117
81
  * domain - the domain this mail is going to (see `always_split` above)
118
- * notes - the original transaction.notes for this mail, also contains the
119
- following useful keys:
120
- ** outbound_ip - the IP address to bind to (note do not set this manually,
121
- use the `get_mx` hook)
122
- ** outbound_helo - the EHLO domain to use (again, do not set manually)
82
+ * notes - the original transaction.notes for this mail, also contains the following useful keys:
83
+ * outbound_ip - the IP address to bind to (do not set manually, use the `get_mx` hook)
84
+ * outbound_helo - the EHLO domain to use (again, do not set manually)
123
85
  * queue_time - the epoch milliseconds time when this mail was queued
124
86
  * uuid - the original transaction.uuid
125
87
  * force_tls - if true, this mail will be sent over TLS or defer
126
88
 
127
-
128
- Outbound Mail Hooks
129
- -------------------
89
+ ## Outbound Mail Hooks
130
90
 
131
91
  ### The queue\_outbound hook
132
92
 
133
- The first hook that is called prior to queueing an outbound mail is the
134
- `queue_outbound` hook. Only if all these hooks return `CONT` (or if there are
135
- no hooks) will the mail be queued for outbound delivery. A return of `OK` will
136
- indicate that the mail has been queued in some custom manner for outbound
137
- delivery. Any of the `DENY` return codes will cause the message to be
138
- appropriately rejected.
93
+ The first hook that is called prior to queueing an outbound mail is the `queue_outbound` hook. Only if all these hooks return `CONT` (or if there are no hooks) will the mail be queued for outbound delivery. A return of `OK` will indicate that the mail has been queued in some custom manner for outbound delivery. Any of the `DENY` return codes will cause the message to be appropriately rejected.
139
94
 
140
95
  ### The send\_email hook
141
96
 
@@ -149,63 +104,31 @@ Respond with `next(DELAY, delay_seconds)` to defer sending the email at this tim
149
104
 
150
105
  Parameters: `next, hmail, domain`
151
106
 
152
- Upon starting delivery the `get_mx` hook is called, with the parameter set to
153
- the domain in question (for example a mail to `user@example.com` will call the
154
- `get_mx` hook with `(next, hmail, domain)` as parameters). This is to allow
155
- you to implement a custom handler to find MX records. For most installations
156
- there is no reason to implement this hook - Haraka will find the correct MX
157
- records for you.
158
-
159
- The MX record is sent via next(OK, mx) and can be one of:
160
-
161
- * A string of one of the following formats:
162
- * hostname
163
- * hostname:port
164
- * ipaddress
165
- * ipaddress:port
166
- * An MX object of the form: `{priority: 0, exchange: hostname}` with the
167
- following optional properies:
168
- * `port` to specify an alternate port
169
- * `bind` to specify an outbound IP address to bind to
170
- * `bind_helo` to specify an outbound helo for IP address to bind to
171
- * `using_lmtp` boolean to specify that delivery should be attempted using
172
- LMTP instead of SMTP.
173
- * `auth_user` to specify an AUTH username (required if AUTH is desired)
174
- * `auth_pass` to specify an AUTH password (required if AUTH is desired)
175
- * `auth_type` to specify an AUTH type that should be used with the MX.
176
- If this is not specified then Haraka will pick an appropriate method.
177
- * A list of MX objects in an array, each in the same format as above.
107
+ Upon starting delivery the `get_mx` hook is called, with the parameter set to the domain in question (for example a mail to `user@example.com` will call the `get_mx` hook with `(next, hmail, domain)` as parameters). This is to allow you to implement a custom handler to find MX records. For most installations there is no reason to implement this hook - Haraka will find the MX records via DNS.
108
+
109
+ The MX is sent via next(OK, mx). `mx` is a [HarakaMx][url-harakamx] object, an array of HarakaMx objects, or any suitable HarakaMx input.
178
110
 
179
111
  ### The deferred hook
180
112
 
181
113
  Parameters: `next, hmail, {delay: ..., err: ...}`
182
114
 
183
- If the mail is temporarily deferred, the `deferred` hook is called. The hook
184
- parameter is an object with keys: `delay` and `err`, which explain the delay
185
- (in seconds) and error message.
115
+ If the mail is temporarily deferred, the `deferred` hook is called. The hook parameter is an object with keys: `delay` and `err`, which explain the delay (in seconds) and error message.
186
116
 
187
- If you want to stop at this point, and drop the mail completely, then you
188
- can call `next(OK)`.
117
+ If you want to stop at this point, and drop the mail completely, then you can call `next(OK)`.
189
118
 
190
- If you want to change the delay, then call `next(DENYSOFT, delay_in_seconds)`.
191
- Using this you can define a custom delay algorithm indexed by
192
- `hmail.num_failures`.
119
+ If you want to change the delay, then call `next(DENYSOFT, delay_in_seconds)`. Using this you can define a custom delay algorithm indexed by `hmail.num_failures`.
193
120
 
194
121
  ### The bounce hook
195
122
 
196
123
  Parameters: `next, hmail, error`
197
124
 
198
- If the mail completely bounces then the `bounce` hook is called. This is *not*
199
- called if the mail is issued a temporary failure (a 4xx error code). The hook
200
- parameter is the error message received from the remote end as an `Error` object.
201
- The object may also have the following properties:
125
+ If the mail completely bounces then the `bounce` hook is called. This is *not* called if the mail is issued a temporary failure (a 4xx error code). The hook parameter is the error message received from the remote end as an `Error` object. The object may also have the following properties:
202
126
 
203
127
  * mx - the MX object that caused the bounce
204
128
  * deferred_rcpt - the deferred recipients that eventually bounced
205
129
  * bounced_rcpt - the bounced recipients
206
130
 
207
- If you do not wish to have a bounce message sent to the originating sender of the
208
- email then you can return `OK` from this hook to stop it from sending a bounce message.
131
+ If you do not wish to have a bounce message sent to the originating sender of the email then you can return `OK` from this hook to stop it from sending a bounce message.
209
132
 
210
133
  ### The delivered hook
211
134
 
@@ -213,67 +136,34 @@ Parameters: `next, hmail, params`
213
136
 
214
137
  Params is a list of: `[host, ip, response, delay, port, mode, ok_recips, secured]`
215
138
 
216
- When mails are successfully delivered to the remote end then the `delivered`
217
- hook is called. The return codes from this hook have no effect, so it is only
218
- useful for logging the fact that a successful delivery occurred.
139
+ When mails are successfully delivered to the remote end then the `delivered` hook is called. The return codes from this hook have no effect, so it is only useful for logging the fact that a successful delivery occurred.
219
140
 
220
141
  * `host` - Hostname of the MX that the message was delivered to,
221
142
  * `ip` - IP address of the host that the message was delivered to,
222
- * `response` - Variable contains the SMTP response text returned by the host
223
- that received the message and will typically contain the remote queue ID and
224
- * `delay` - Time taken between the queue file being created and the
225
- message being delivered.
143
+ * `response` - Variable contains the SMTP response text returned by the host that received the message and will typically contain the remote queue ID and
144
+ * `delay` - Time taken between the queue file being created and the message being delivered.
226
145
  * `port` - Port number that the message was delivered to.
227
146
  * `mode` - Shows whether SMTP or LMTP was used to deliver the mail.
228
- * `ok_recips` - an `Address`[1] array containing all of the recipients that were
229
- successfully delivered to.
147
+ * `ok_recips` - an `Address`<sup>[1](#fn1)</sup> array containing all of the recipients that were successfully delivered to.
230
148
  * `secured` - A boolean denoting if the connection used TLS or not.
231
149
 
232
- Outbound IP address
233
- -------------------
150
+ ## Outbound IP address
234
151
 
235
- Normally the OS will decide which IP address will be used for outbound
236
- connections using the IP routing table.
152
+ Normally the OS will decide which IP address will be used for outbound connections using the IP routing table.
237
153
 
238
- There are instances where you may want to separate outbound traffic on
239
- different IP addresses based on sender, domain or some other identifier.
240
- To do this, the IP address that you want to use *must* be bound to an
241
- interface (or alias) on the local system.
154
+ There are instances where you may want to separate outbound traffic on different IP addresses based on sender, domain or some other identifier. To do this, the IP address that you want to use *must* be bound to an interface (or alias) on the local system.
242
155
 
243
- As described above the outbound IP can be set using the `bind` parameter
244
- and also the outbound helo for the IP can be set using the `bind_ehlo`
245
- parameter returned by the `get_mx` hook or during the reception of the message
246
- you can set a transaction note in a plugin to tell Haraka which outbound IP
247
- address you would like it to use when it tries to deliver the message:
156
+ As described above, the outbound IP can be set using the `bind` parameter and also the outbound helo for the IP can be set using the `bind_ehlo` parameter returned by the `get_mx` hook.
248
157
 
249
- `````
250
- connection.transaction.notes.outbound_ip = '1.2.3.4';
251
- connection.transaction.notes.outbound_helo = 'mail-2.example.com';
252
- `````
158
+ ## AUTH
253
159
 
254
- Note: if the `get_mx` hook returns a `bind` and `bind_helo` parameter, then
255
- this will be used in preference to the transaction note.
160
+ If you wish to use AUTH for a particular domain or domains, or you wish to force all mail to an outbound service or smart host that requires authentication then you can use the `get_mx` hook documented above to do this by supplying both `auth_user` and `auth_pass` properties in an MX object.
256
161
 
257
- AUTH
258
- ----
162
+ If AUTH properties are supplied and the remote end does not offer AUTH or there are no compatible AUTH methods, then the message will be sent without AUTH and a warning will be logged.
259
163
 
260
- If you wish to use AUTH for a particular domain or domains, or you wish to
261
- force all mail to an outbound service or smart host that requires authentication
262
- then you can use the `get_mx` hook documented above to do this by supplying
263
- both `auth_user` and `auth_pass` properties in an MX object.
164
+ ## Bounce Messages
264
165
 
265
- If AUTH properties are supplied and the remote end does not offer AUTH or there
266
- are no compatible AUTH methods, then the message will be sent without AUTH and
267
- a warning will be logged.
268
-
269
-
270
- Bounce Messages
271
- ---------------
272
-
273
- The contents of the bounce message are configured by a file called
274
- `config/outbound.bounce_message`. If you look at this file you will see it
275
- contains several template entries wrapped in curly brackets. These will be
276
- populated as follows:
166
+ The contents of the bounce message are configured by a file called `config/outbound.bounce_message`. If you look at this file you will see it contains several template entries wrapped in curly brackets. These will be populated as follows:
277
167
 
278
168
  Optional: Possibility to add HTML code (with optional image) to the bounce message is possible by adding the files `config/outbound.bounce_message_html`. An image can be attached to the mail by using `config/outbound.bounce_message_image`.
279
169
 
@@ -286,72 +176,76 @@ Optional: Possibility to add HTML code (with optional image) to the bounce messa
286
176
  multiple people
287
177
  * reason - the text from the remote server indicating why it bounced
288
178
 
289
- Following the bounce message itself will be a copy of the entire original
290
- message.
179
+ Following the bounce message itself will be a copy of the entire original message.
291
180
 
292
- Creating a mail internally for outbound delivery
293
- ------------------------------------------------
181
+ ## Creating a mail internally for outbound delivery
294
182
 
295
183
  Sometimes it is necessary to generate a new mail from within a plugin.
296
184
 
297
185
  To do that, you can use the `outbound` module directly:
298
186
 
299
- var outbound = require('./outbound');
300
-
301
- var plugin = this;
302
-
303
- var to = 'user@example.com';
304
- var from = 'sender@example.com';
305
-
306
- var contents = [
307
- "From: " + from,
308
- "To: " + to,
309
- "MIME-Version: 1.0",
310
- "Content-type: text/plain; charset=us-ascii",
311
- "Subject: Some subject here",
312
- "",
313
- "Some email body here",
314
- ""].join("\n");
315
-
316
- var outnext = function (code, msg) {
317
- switch (code) {
318
- case DENY: plugin.logerror("Sending mail failed: " + msg);
319
- break;
320
- case OK: plugin.loginfo("mail sent");
321
- next();
322
- break;
323
- default: plugin.logerror("Unrecognized return code from sending email: " + msg);
324
- next();
325
- }
326
- };
327
-
328
- outbound.send_email(from, to, contents, outnext);
329
-
330
- The callback on `send_email()` is passed `OK` if the mail is successfully
331
- queued to disk, not when it is successfully delivered. To check delivery
332
- status you still need to hook `delivered` and `bounce` to know if it was
333
- successfully delivered.
334
-
335
- The callback parameter may be omitted if you don't need to handle errors
336
- should queueing to disk fail e.g:
337
-
338
- outbound.send_email(from, to, contents);
339
-
340
- You can pass various options to `outbound.send_email` like so:
341
-
342
- outbound.send_email(from, to, contents, outnext, options);
187
+ ```js
188
+ const outbound = require('./outbound');
189
+
190
+ const to = 'user@example.com';
191
+ const from = 'sender@example.com';
192
+
193
+ const contents = [
194
+ "From: " + from,
195
+ "To: " + to,
196
+ "MIME-Version: 1.0",
197
+ "Content-type: text/plain; charset=us-ascii",
198
+ "Subject: Some subject here",
199
+ "",
200
+ "Some email body here",
201
+ ""].join("\n");
202
+
203
+ const outnext = (code, msg) => {
204
+ switch (code) {
205
+ case DENY: this.logerror("Sending mail failed: " + msg);
206
+ break;
207
+ case OK: this.loginfo("mail sent");
208
+ next();
209
+ break;
210
+ default: this.logerror("Unrecognized return code from sending email: " + msg);
211
+ next();
212
+ }
213
+ }
214
+
215
+ outbound.send_email(from, to, contents, outnext)
216
+ ```
217
+
218
+ The callback on `send_email()` is passed `OK` if the mail is successfully queued, not when it is successfully delivered. To check delivery status, you need to hook `delivered` and `bounce`.
219
+
220
+ The callback parameter may be omitted if you don't need to handle errors should queueing to disk fail e.g:
221
+
222
+ ```js
223
+ outbound.send_email(from, to, contents);
224
+ ```
225
+
226
+ Various options can be passed to `outbound.send_email` like so:
227
+
228
+ ```js
229
+ outbound.send_email(from, to, contents, outnext, options);
230
+ ```
343
231
 
344
232
  Where `options` is a Object that may contain the following keys:
345
233
 
346
- | Key/Value | Description |
347
- |------------------------|--------------------------------------------------------------------------------------------
348
- | `dot_stuffed: true` | Use this if you are passing your content dot-stuffed (a dot at the start of a line is doubled, like it is in SMTP conversation, see [RFC 2821](https://tools.ietf.org/html/rfc2821#section-4.5.2).|
234
+ | Key/Value | Description |
235
+ |------------------------|-------------|
236
+ | `dot_stuffed: true` | Use this if you are passing your content dot-stuffed (a dot at the start of a line is doubled, like it is in SMTP conversation, see [RFC 2821][url-rfc2821].|
349
237
  | `notes: { key: value}` | In case you need notes in the new transaction that `send_email()` creates. |
350
238
  | `remove_msgid: true` | Remove any Message-Id header found in the message. If you are reading a message in from the filesystem and you want to ensure that a generated Message-Id header is used in preference over the original. This is useful if you are releasing mail from a quarantine. |
351
239
  | `remove_date: true` | Remove any Date header found in the message. If you are reading a message in from the filesystem and you want to ensure that a generated Date header is used in preference over the original. This is useful if you are releasing mail from a quarantine. |
352
240
  | `origin: Object` | Adds object as argument to logger.log calls inside outbound.send_email. Useful for tracking which Plugin/Connection/HMailItem object generated email. |
353
241
 
354
242
 
355
- outbound.send_email(from, to, contents, outnext, { notes: transaction.notes });
243
+ ```js
244
+ outbound.send_email(from, to, contents, outnext, { notes: transaction.notes });
245
+ ```
246
+
247
+ <a name="fn1">1</a>: `Address` objects are [address-rfc2821](https://github.com/haraka/node-address-rfc2821) objects.
356
248
 
357
- [1]: `Address` objects are [address-rfc2821 objects](https://github.com/haraka/node-address-rfc2821).
249
+ [url-tls]: https://haraka.github.io/plugins/tls
250
+ [url-harakamx]: https://github.com/haraka/haraka-net-utils?tab=readme-ov-file#harakamx
251
+ [url-rfc2821]: https://tools.ietf.org/html/rfc2821#section-4.5.2
package/docs/Plugins.md CHANGED
@@ -20,7 +20,6 @@ Display the help text for a plugin by running:
20
20
  ## Overview
21
21
 
22
22
 
23
-
24
23
  ## Anatomy of a Plugin
25
24
 
26
25
  Plugins in Haraka are JS files in the `plugins` directory (legacy) and npm
@@ -42,37 +41,43 @@ There are two ways for plugins to register hooks. Both examples register a funct
42
41
 
43
42
  1. The `register_hook` function in register():
44
43
 
45
- exports.register = function() {
46
- this.register_hook('rcpt', 'my_rcpt_validate');
47
- };
44
+ ```js
45
+ exports.register = function () {
46
+ this.register_hook('rcpt', 'my_rcpt_validate')
47
+ };
48
48
 
49
- exports.my_rcpt_validate = function (next, connection, params) {
50
- // do processing
51
- next();
52
- };
49
+ exports.my_rcpt_validate = function (next, connection, params) {
50
+ // do processing
51
+ next()
52
+ };
53
+ ```
53
54
 
54
55
  2. The hook_[$name] syntax:
55
56
 
56
- exports.hook_rcpt = function (next, connection, params) {
57
- // do processing
58
- next();
59
- };
57
+ ```js
58
+ exports.hook_rcpt = function (next, connection, params) {
59
+ // do processing
60
+ next()
61
+ }
62
+ ```
60
63
 
61
64
  The register_hook function within `register()` offers a few advantages:
62
65
 
63
- 1. register a hook multiple times (see below)
64
- 2. a unique function name in stack traces
65
- 3. [a better function name](https://google.com/search?q=programming%20good%20function%20names)
66
- 4. hooks can be registered conditionally (ie, based on a config setting)
66
+ 1. register a hook multiple times (see below)
67
+ 2. a unique function name in stack traces
68
+ 3. [a better function name](https://google.com/search?q=programming%20good%20function%20names)
69
+ 4. hooks can be registered conditionally (ie, based on a config setting)
67
70
 
68
71
  ### Register a Hook Multiple Times
69
72
 
70
73
  To register the same hook more than once, call `register_hook()` multiple times with the same hook name:
71
74
 
72
- exports.register = function() {
73
- this.register_hook('queue', 'try_queue_my_way');
74
- this.register_hook('queue', 'try_queue_highway');
75
- };
75
+ ```js
76
+ exports.register = function () {
77
+ this.register_hook('queue', 'try_queue_my_way')
78
+ this.register_hook('queue', 'try_queue_highway')
79
+ };
80
+ ```
76
81
 
77
82
  When `try_queue_my_way()` calls `next()`, the next function registered on hook *queue* will be called, in this case, `try_queue_highway()`.
78
83
 
@@ -81,17 +86,18 @@ When `try_queue_my_way()` calls `next()`, the next function registered on hook *
81
86
  When a single function runs on multiple hooks, the function can check the
82
87
  *hook* property of the *connection* or *hmail* argument to determine which hook it is running on:
83
88
 
84
- exports.register = function() {
85
- this.register_hook('rcpt', 'my_rcpt');
86
- this.register_hook('rcpt_ok', 'my_rcpt');
87
- };
88
-
89
- exports.my_rcpt = function (next, connection, params) {
90
- var hook_name = connection.hook; // rcpt or rcpt_ok
91
- // email address is in params[0]
92
- // do processing
93
- }
94
-
89
+ ```js
90
+ exports.register = function () {
91
+ this.register_hook('rcpt', 'my_rcpt')
92
+ this.register_hook('rcpt_ok', 'my_rcpt')
93
+ };
94
+
95
+ exports.my_rcpt = function (next, connection, params) {
96
+ const hook_name = connection.hook; // rcpt or rcpt_ok
97
+ // email address is in params[0]
98
+ // do processing
99
+ }
100
+ ```
95
101
 
96
102
  ### Next()
97
103
 
@@ -252,14 +258,13 @@ This is important as some plugins might rely on `results` or `notes` that have b
252
258
 
253
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. You can apply a priority to your hook in the following way:
254
260
 
255
- ````
256
- exports.register = function() {
257
- var plugin = this;
258
- plugin.register_hook('connect', 'hook_connect', -100);
261
+ ```js
262
+ exports.register = function () {
263
+ this.register_hook('connect', 'do_connect_stuff', -100);
259
264
  }
260
- ````
265
+ ```
261
266
 
262
- This would ensure that your hook_connect function will run before any other
267
+ This would ensure that your `do_connect_stuff` function will run before any other
263
268
  plugins registered on the `connect` hook, regardless of the order it was
264
269
  specified in `config/plugins`.
265
270
 
@@ -370,9 +375,11 @@ to remote servers. See [Issue 2024](https://github.com/haraka/Haraka/issues/2024
370
375
 
371
376
  e.g.
372
377
 
373
- exports.shutdown = function () {
374
- clearInterval(this._interval);
375
- }
378
+ ```js
379
+ exports.shutdown = function () {
380
+ clearInterval(this._interval);
381
+ }
382
+ ```
376
383
 
377
384
  If you don't implement this in your plugin and have a connection open or a
378
385
  timer running then Haraka will take 30 seconds to shut down and have to