Haraka 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/.prettierignore +4 -0
  2. package/CONTRIBUTORS.md +5 -5
  3. package/Changes.md +69 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -478
  7. package/config/outbound.ini +3 -0
  8. package/connection.js +1072 -1108
  9. package/docs/Connection.md +29 -30
  10. package/docs/CoreConfig.md +38 -39
  11. package/docs/CustomReturnCodes.md +0 -1
  12. package/docs/HAProxy.md +2 -2
  13. package/docs/Header.md +1 -1
  14. package/docs/Logging.md +29 -5
  15. package/docs/Outbound.md +93 -78
  16. package/docs/Plugins.md +103 -108
  17. package/docs/Transaction.md +49 -51
  18. package/docs/Tutorial.md +127 -143
  19. package/docs/deprecated/access.md +0 -1
  20. package/docs/deprecated/backscatterer.md +2 -3
  21. package/docs/deprecated/connect.rdns_access.md +18 -27
  22. package/docs/deprecated/data.headers.md +0 -1
  23. package/docs/deprecated/data.nomsgid.md +1 -2
  24. package/docs/deprecated/data.noreceived.md +1 -2
  25. package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
  26. package/docs/deprecated/dkim_sign.md +13 -17
  27. package/docs/deprecated/dkim_verify.md +9 -17
  28. package/docs/deprecated/dnsbl.md +36 -38
  29. package/docs/deprecated/dnswl.md +41 -43
  30. package/docs/deprecated/lookup_rdns.strict.md +21 -34
  31. package/docs/deprecated/mail_from.access.md +17 -25
  32. package/docs/deprecated/mail_from.blocklist.md +9 -12
  33. package/docs/deprecated/mail_from.nobounces.md +1 -2
  34. package/docs/deprecated/rcpt_to.access.md +20 -27
  35. package/docs/deprecated/rcpt_to.blocklist.md +10 -13
  36. package/docs/deprecated/rcpt_to.routes.md +0 -1
  37. package/docs/deprecated/rdns.regexp.md +13 -15
  38. package/docs/plugins/aliases.md +89 -89
  39. package/docs/plugins/auth/auth_bridge.md +5 -7
  40. package/docs/plugins/auth/auth_ldap.md +11 -14
  41. package/docs/plugins/auth/auth_proxy.md +10 -12
  42. package/docs/plugins/auth/auth_vpopmaild.md +5 -6
  43. package/docs/plugins/auth/flat_file.md +4 -4
  44. package/docs/plugins/block_me.md +3 -3
  45. package/docs/plugins/data.signatures.md +1 -2
  46. package/docs/plugins/delay_deny.md +3 -4
  47. package/docs/plugins/max_unrecognized_commands.md +4 -4
  48. package/docs/plugins/prevent_credential_leaks.md +6 -6
  49. package/docs/plugins/process_title.md +18 -18
  50. package/docs/plugins/queue/deliver.md +2 -3
  51. package/docs/plugins/queue/discard.md +4 -4
  52. package/docs/plugins/queue/lmtp.md +1 -3
  53. package/docs/plugins/queue/qmail-queue.md +7 -9
  54. package/docs/plugins/queue/quarantine.md +16 -21
  55. package/docs/plugins/queue/rabbitmq.md +8 -11
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
  57. package/docs/plugins/queue/smtp_bridge.md +7 -10
  58. package/docs/plugins/queue/smtp_forward.md +42 -34
  59. package/docs/plugins/queue/smtp_proxy.md +30 -29
  60. package/docs/plugins/queue/test.md +1 -3
  61. package/docs/plugins/rcpt_to.in_host_list.md +6 -6
  62. package/docs/plugins/rcpt_to.max_count.md +1 -1
  63. package/docs/plugins/record_envelope_addresses.md +3 -3
  64. package/docs/plugins/reseed_rng.md +6 -6
  65. package/docs/plugins/status.md +9 -8
  66. package/docs/plugins/tarpit.md +7 -11
  67. package/docs/plugins/tls.md +12 -17
  68. package/docs/plugins/toobusy.md +4 -4
  69. package/docs/plugins/xclient.md +3 -3
  70. package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
  71. package/docs/tutorials/SettingUpOutbound.md +6 -9
  72. package/endpoint.js +35 -38
  73. package/eslint.config.mjs +22 -19
  74. package/haraka.js +42 -47
  75. package/host_pool.js +75 -79
  76. package/http/html/404.html +45 -49
  77. package/http/html/index.html +39 -28
  78. package/http/package.json +2 -4
  79. package/line_socket.js +27 -28
  80. package/logger.js +182 -201
  81. package/outbound/client_pool.js +34 -27
  82. package/outbound/config.js +64 -59
  83. package/outbound/fsync_writestream.js +24 -25
  84. package/outbound/hmail.js +888 -835
  85. package/outbound/index.js +194 -187
  86. package/outbound/qfile.js +49 -52
  87. package/outbound/queue.js +197 -190
  88. package/outbound/timer_queue.js +41 -43
  89. package/outbound/tls.js +68 -61
  90. package/outbound/todo.js +11 -11
  91. package/package.json +38 -33
  92. package/plugins/.eslintrc.yaml +0 -1
  93. package/plugins/auth/auth_base.js +123 -127
  94. package/plugins/auth/auth_bridge.js +7 -7
  95. package/plugins/auth/auth_proxy.js +121 -126
  96. package/plugins/auth/auth_vpopmaild.js +84 -85
  97. package/plugins/auth/flat_file.js +18 -17
  98. package/plugins/block_me.js +31 -31
  99. package/plugins/data.signatures.js +13 -13
  100. package/plugins/delay_deny.js +65 -61
  101. package/plugins/prevent_credential_leaks.js +23 -23
  102. package/plugins/process_title.js +125 -128
  103. package/plugins/profile.js +5 -5
  104. package/plugins/queue/deliver.js +3 -3
  105. package/plugins/queue/discard.js +13 -14
  106. package/plugins/queue/lmtp.js +16 -17
  107. package/plugins/queue/qmail-queue.js +54 -55
  108. package/plugins/queue/quarantine.js +68 -70
  109. package/plugins/queue/rabbitmq.js +80 -87
  110. package/plugins/queue/rabbitmq_amqplib.js +75 -54
  111. package/plugins/queue/smtp_bridge.js +16 -16
  112. package/plugins/queue/smtp_forward.js +175 -179
  113. package/plugins/queue/smtp_proxy.js +69 -71
  114. package/plugins/queue/test.js +9 -9
  115. package/plugins/rcpt_to.host_list_base.js +30 -34
  116. package/plugins/rcpt_to.in_host_list.js +19 -19
  117. package/plugins/record_envelope_addresses.js +4 -4
  118. package/plugins/reseed_rng.js +4 -4
  119. package/plugins/status.js +90 -97
  120. package/plugins/tarpit.js +25 -14
  121. package/plugins/tls.js +68 -68
  122. package/plugins/toobusy.js +21 -23
  123. package/plugins/xclient.js +51 -53
  124. package/plugins.js +276 -293
  125. package/rfc1869.js +30 -35
  126. package/server.js +308 -299
  127. package/smtp_client.js +244 -228
  128. package/test/.eslintrc.yaml +0 -1
  129. package/test/connection.js +127 -134
  130. package/test/endpoint.js +53 -47
  131. package/test/fixtures/line_socket.js +12 -12
  132. package/test/fixtures/util_hmailitem.js +89 -85
  133. package/test/host_pool.js +90 -92
  134. package/test/installation/plugins/base_plugin.js +2 -2
  135. package/test/installation/plugins/folder_plugin/index.js +2 -3
  136. package/test/installation/plugins/inherits.js +3 -3
  137. package/test/installation/plugins/load_first.js +2 -3
  138. package/test/installation/plugins/plugin.js +1 -3
  139. package/test/installation/plugins/tls.js +2 -4
  140. package/test/logger.js +135 -116
  141. package/test/outbound/hmail.js +49 -35
  142. package/test/outbound/index.js +118 -101
  143. package/test/outbound/qfile.js +51 -53
  144. package/test/outbound_bounce_net_errors.js +84 -69
  145. package/test/outbound_bounce_rfc3464.js +235 -165
  146. package/test/plugins/auth/auth_base.js +420 -279
  147. package/test/plugins/auth/auth_vpopmaild.js +38 -39
  148. package/test/plugins/queue/smtp_forward.js +126 -104
  149. package/test/plugins/rcpt_to.host_list_base.js +85 -67
  150. package/test/plugins/rcpt_to.in_host_list.js +159 -112
  151. package/test/plugins/status.js +71 -64
  152. package/test/plugins/tls.js +37 -34
  153. package/test/plugins.js +97 -92
  154. package/test/rfc1869.js +19 -26
  155. package/test/server.js +293 -272
  156. package/test/smtp_client.js +180 -176
  157. package/test/tls_socket.js +62 -66
  158. package/test/transaction.js +159 -160
  159. package/tls_socket.js +331 -333
  160. package/transaction.js +129 -137
@@ -1,355 +1,351 @@
1
- 'use strict';
1
+ 'use strict'
2
2
  // Forward to an SMTP server
3
3
  // Opens the connection to the ongoing SMTP server at queue time
4
4
  // and passes back any errors seen on the ongoing server to the
5
5
  // originating server.
6
6
 
7
- const url = require('node:url');
7
+ const url = require('node:url')
8
8
 
9
- const smtp_client_mod = require('./smtp_client');
9
+ const smtp_client_mod = require('./smtp_client')
10
10
 
11
11
  exports.register = function () {
12
- this.load_errs = [];
12
+ this.load_errs = []
13
13
 
14
- this.load_smtp_forward_ini();
14
+ this.load_smtp_forward_ini()
15
15
 
16
- if (this.load_errs.length > 0) return;
16
+ if (this.load_errs.length > 0) return
17
17
 
18
18
  if (this.cfg.main.check_sender) {
19
- this.register_hook('mail', 'check_sender');
19
+ this.register_hook('mail', 'check_sender')
20
20
  }
21
21
 
22
22
  if (this.cfg.main.check_recipient) {
23
- this.register_hook('rcpt', 'check_recipient');
23
+ this.register_hook('rcpt', 'check_recipient')
24
24
  }
25
25
 
26
- this.register_hook('queue', 'queue_forward');
26
+ this.register_hook('queue', 'queue_forward')
27
27
 
28
28
  if (this.cfg.main.enable_outbound) {
29
29
  // deliver local message via smtp forward when relaying=true
30
- this.register_hook('queue_outbound', 'queue_forward');
30
+ this.register_hook('queue_outbound', 'queue_forward')
31
31
  }
32
32
 
33
33
  // may specify more specific [per-domain] outbound routes
34
- this.register_hook('get_mx', 'get_mx');
34
+ this.register_hook('get_mx', 'get_mx')
35
35
  }
36
36
 
37
37
  exports.load_smtp_forward_ini = function () {
38
-
39
- this.cfg = this.config.get('smtp_forward.ini', {
40
- booleans: [
41
- '-main.enable_tls',
42
- '-main.enable_outbound',
43
- 'main.one_message_per_rcpt',
44
- '-main.check_sender',
45
- '-main.check_recipient',
46
- '*.enable_tls',
47
- '*.enable_outbound'
48
- ],
49
- },
50
- () => {
51
- this.load_smtp_forward_ini();
52
- });
38
+ this.cfg = this.config.get(
39
+ 'smtp_forward.ini',
40
+ {
41
+ booleans: [
42
+ '-main.enable_tls',
43
+ '-main.enable_outbound',
44
+ 'main.one_message_per_rcpt',
45
+ '-main.check_sender',
46
+ '-main.check_recipient',
47
+ '*.enable_tls',
48
+ '*.enable_outbound',
49
+ ],
50
+ },
51
+ () => {
52
+ this.load_smtp_forward_ini()
53
+ },
54
+ )
53
55
  }
54
56
 
55
57
  exports.get_config = function (conn) {
58
+ if (!conn.transaction) return this.cfg.main
56
59
 
57
- if (!conn.transaction) return this.cfg.main;
58
-
59
- let dom;
60
+ let dom, address
60
61
  if (this.cfg.main.domain_selector === 'mail_from') {
61
- if (!conn.transaction.mail_from) return this.cfg.main;
62
- dom = conn.transaction.mail_from.host;
63
- }
64
- else {
65
- if (!conn.transaction.rcpt_to[0]) return this.cfg.main;
66
- dom = conn.transaction.rcpt_to[0].host;
62
+ if (!conn.transaction.mail_from) return this.cfg.main
63
+ dom = conn.transaction.mail_from.host
64
+ address = conn.transaction.mail_from.address()
65
+ } else {
66
+ if (!conn.transaction.rcpt_to[0]) return this.cfg.main
67
+ dom = conn.transaction.rcpt_to[0].host
67
68
  }
68
69
 
69
- if (!dom) return this.cfg.main;
70
- if (!this.cfg[dom]) return this.cfg.main; // no specific route
70
+ if (address && this.cfg[address]) return this.cfg[address]
71
+ if (!dom) return this.cfg.main
72
+ if (!this.cfg[dom]) return this.cfg.main // no specific route
71
73
 
72
- return this.cfg[dom];
74
+ return this.cfg[dom]
73
75
  }
74
76
 
75
77
  exports.is_outbound_enabled = function (dom_cfg) {
78
+ if ('enable_outbound' in dom_cfg) return dom_cfg.enable_outbound // per-domain flag
76
79
 
77
- if ('enable_outbound' in dom_cfg) return dom_cfg.enable_outbound; // per-domain flag
78
-
79
- return this.cfg.main.enable_outbound; // follow the global configuration
80
+ return this.cfg.main.enable_outbound // follow the global configuration
80
81
  }
81
82
 
82
83
  exports.check_sender = function (next, connection, params) {
83
- const txn = connection?.transaction;
84
- if (!txn) return;
84
+ const txn = connection?.transaction
85
+ if (!txn) return
85
86
 
86
- const email = params[0].address();
87
+ const email = params[0].address()
87
88
  if (!email) {
88
- txn.results.add(this, {skip: 'mail_from.null', emit: true});
89
- return next();
89
+ txn.results.add(this, { skip: 'mail_from.null', emit: true })
90
+ return next()
90
91
  }
91
92
 
92
- const domain = params[0].host.toLowerCase();
93
- if (!this.cfg[domain]) return next();
93
+ const domain = params[0].host.toLowerCase()
94
+ if (!this.cfg[domain]) return next()
94
95
 
95
96
  // domain is defined in smtp_forward.ini
96
- txn.notes.local_sender = true;
97
+ txn.notes.local_sender = true
97
98
 
98
99
  if (!connection.relaying) {
99
- txn.results.add(this, {fail: 'mail_from!spoof'});
100
- return next(DENY, "Spoofed MAIL FROM");
100
+ txn.results.add(this, { fail: 'mail_from!spoof' })
101
+ return next(DENY, 'Spoofed MAIL FROM')
101
102
  }
102
103
 
103
- txn.results.add(this, {pass: 'mail_from'});
104
- next();
104
+ txn.results.add(this, { pass: 'mail_from' })
105
+ next()
105
106
  }
106
107
 
107
108
  exports.set_queue = function (connection, queue_wanted, domain) {
109
+ let dom_cfg = this.cfg[domain]
110
+ if (dom_cfg === undefined) dom_cfg = {}
108
111
 
109
- let dom_cfg = this.cfg[domain];
110
- if (dom_cfg === undefined) dom_cfg = {};
111
-
112
- if (!queue_wanted) queue_wanted = dom_cfg.queue || this.cfg.main.queue;
113
- if (!queue_wanted) return true;
112
+ if (!queue_wanted) queue_wanted = dom_cfg.queue || this.cfg.main.queue
113
+ if (!queue_wanted) return true
114
114
 
115
- let dst_host = dom_cfg.host || this.cfg.main.host;
116
- if (dst_host) dst_host = `smtp://${dst_host}`;
115
+ let dst_host = dom_cfg.host || this.cfg.main.host
116
+ if (dst_host) dst_host = `smtp://${dst_host}`
117
117
 
118
- const notes = connection?.transaction?.notes;
119
- if (!notes) return false;
118
+ const notes = connection?.transaction?.notes
119
+ if (!notes) return false
120
120
  if (!notes.get('queue.wants')) {
121
- notes.set('queue.wants', queue_wanted);
122
- if (dst_host) notes.set('queue.next_hop', dst_host);
123
- return true;
121
+ notes.set('queue.wants', queue_wanted)
122
+ if (dst_host) notes.set('queue.next_hop', dst_host)
123
+ return true
124
124
  }
125
125
 
126
126
  // multiple recipients with same destination
127
127
  if (notes.get('queue.wants') === queue_wanted) {
128
- if (!dst_host) return true;
128
+ if (!dst_host) return true
129
129
 
130
- const next_hop = notes.get('queue.next_hop');
131
- if (!next_hop) return true;
132
- if (next_hop === dst_host) return true;
130
+ const next_hop = notes.get('queue.next_hop')
131
+ if (!next_hop) return true
132
+ if (next_hop === dst_host) return true
133
133
  }
134
134
 
135
135
  // multiple recipients with different forward host, soft deny
136
- return false;
136
+ return false
137
137
  }
138
138
 
139
139
  exports.check_recipient = function (next, connection, params) {
140
- const txn = connection?.transaction;
141
- if (!txn) return;
140
+ const txn = connection?.transaction
141
+ if (!txn) return
142
142
 
143
- const rcpt = params[0];
143
+ const rcpt = params[0]
144
144
  if (!rcpt.host) {
145
- txn.results.add(this, {skip: 'rcpt!domain'});
146
- return next();
145
+ txn.results.add(this, { skip: 'rcpt!domain' })
146
+ return next()
147
147
  }
148
148
 
149
149
  if (connection.relaying && txn.notes.local_sender) {
150
- this.set_queue(connection, 'outbound');
151
- txn.results.add(this, {pass: 'relaying local_sender'});
152
- return next(OK);
150
+ this.set_queue(connection, 'outbound')
151
+ txn.results.add(this, { pass: 'relaying local_sender' })
152
+ return next(OK)
153
153
  }
154
154
 
155
- const domain = rcpt.host.toLowerCase();
155
+ const domain = rcpt.host.toLowerCase()
156
156
  if (this.cfg[domain] !== undefined) {
157
157
  if (this.set_queue(connection, 'smtp_forward', domain)) {
158
- txn.results.add(this, {pass: 'rcpt_to'});
159
- return next(OK);
158
+ txn.results.add(this, { pass: 'rcpt_to' })
159
+ return next(OK)
160
160
  }
161
- txn.results.add(this, {pass: 'rcpt_to.split'});
162
- return next(DENYSOFT, "Split transaction, retry soon");
161
+ txn.results.add(this, { pass: 'rcpt_to.split' })
162
+ return next(DENYSOFT, 'Split transaction, retry soon')
163
163
  }
164
164
 
165
165
  // the MAIL FROM domain is not local and neither is the RCPT TO
166
166
  // Another RCPT plugin may vouch for this recipient.
167
- txn.results.add(this, {msg: 'rcpt!local'});
168
- next();
167
+ txn.results.add(this, { msg: 'rcpt!local' })
168
+ next()
169
169
  }
170
170
 
171
171
  exports.auth = function (cfg, connection, smtp_client) {
172
-
173
- connection.loginfo(this, `Configuring authentication for SMTP server ${cfg.host}:${cfg.port}`);
172
+ connection.loginfo(this, `Configuring authentication for SMTP server ${cfg.host}:${cfg.port}`)
174
173
  smtp_client.on('capabilities', () => {
175
- connection.loginfo(this, 'capabilities received');
174
+ connection.loginfo(this, 'capabilities received')
176
175
 
177
176
  if ('secured' in smtp_client) {
178
- connection.loginfo(this, 'secured is pending');
177
+ connection.loginfo(this, 'secured is pending')
179
178
  if (smtp_client.secured === false) {
180
- connection.loginfo(this, "Waiting for STARTTLS to complete. AUTH postponed");
181
- return;
179
+ connection.loginfo(this, 'Waiting for STARTTLS to complete. AUTH postponed')
180
+ return
182
181
  }
183
182
  }
184
183
 
185
- function base64 (str) {
186
- const buffer = Buffer.from(str, 'UTF-8');
187
- return buffer.toString('base64');
184
+ function base64(str) {
185
+ const buffer = Buffer.from(str, 'UTF-8')
186
+ return buffer.toString('base64')
188
187
  }
189
188
 
190
189
  if (cfg.auth_type === 'plain') {
191
- connection.loginfo(this, `Authenticating with AUTH PLAIN ${cfg.auth_user}`);
192
- smtp_client.send_command('AUTH', `PLAIN ${base64(`\0${cfg.auth_user}\0${cfg.auth_pass}`)}`);
190
+ connection.loginfo(this, `Authenticating with AUTH PLAIN ${cfg.auth_user}`)
191
+ smtp_client.send_command('AUTH', `PLAIN ${base64(`\0${cfg.auth_user}\0${cfg.auth_pass}`)}`)
193
192
  return
194
193
  }
195
194
 
196
195
  if (cfg.auth_type === 'login') {
197
- smtp_client.authenticating = true;
198
- smtp_client.authenticated = false;
196
+ smtp_client.authenticating = true
197
+ smtp_client.authenticated = false
199
198
 
200
- connection.loginfo(this, `Authenticating with AUTH LOGIN ${cfg.auth_user}`);
201
- smtp_client.send_command('AUTH', 'LOGIN');
199
+ connection.loginfo(this, `Authenticating with AUTH LOGIN ${cfg.auth_user}`)
200
+ smtp_client.send_command('AUTH', 'LOGIN')
202
201
  smtp_client.on('auth', () => {
203
202
  // do nothing
204
- });
203
+ })
205
204
  smtp_client.on('auth_username', () => {
206
- smtp_client.send_command(base64(cfg.auth_user));
207
- });
205
+ smtp_client.send_command(base64(cfg.auth_user))
206
+ })
208
207
  smtp_client.on('auth_password', () => {
209
- smtp_client.send_command(base64(cfg.auth_pass));
210
- });
208
+ smtp_client.send_command(base64(cfg.auth_pass))
209
+ })
211
210
  }
212
- });
211
+ })
213
212
  }
214
213
 
215
214
  exports.forward_enabled = function (conn, dom_cfg) {
216
-
217
- const q_wants = conn.transaction.notes.get('queue.wants');
215
+ const q_wants = conn.transaction.notes.get('queue.wants')
218
216
  if (q_wants && q_wants !== 'smtp_forward') {
219
- conn.logdebug(this, `skipping, unwanted (${q_wants})`);
220
- return false;
217
+ conn.logdebug(this, `skipping, unwanted (${q_wants})`)
218
+ return false
221
219
  }
222
220
 
223
221
  if (conn.relaying && !this.is_outbound_enabled(dom_cfg)) {
224
- conn.logdebug(this, 'skipping, outbound disabled');
225
- return false;
222
+ conn.logdebug(this, 'skipping, outbound disabled')
223
+ return false
226
224
  }
227
225
 
228
- return true;
226
+ return true
229
227
  }
230
228
 
231
229
  exports.queue_forward = function (next, connection) {
232
- const plugin = this;
230
+ const plugin = this
233
231
  if (connection.remote.closed) return
234
- const txn = connection?.transaction;
232
+ const txn = connection?.transaction
235
233
 
236
- const cfg = plugin.get_config(connection);
237
- if (!plugin.forward_enabled(connection, cfg)) return next();
234
+ const cfg = plugin.get_config(connection)
235
+ if (!plugin.forward_enabled(connection, cfg)) return next()
238
236
 
239
237
  smtp_client_mod.get_client_plugin(plugin, connection, cfg, (err, smtp_client) => {
240
- smtp_client.next = next;
238
+ smtp_client.next = next
241
239
 
242
- let rcpt = 0;
240
+ let rcpt = 0
243
241
 
244
- if (cfg.auth_user) plugin.auth(cfg, connection, smtp_client);
242
+ if (cfg.auth_user) plugin.auth(cfg, connection, smtp_client)
245
243
 
246
- connection.loginfo(plugin, `forwarding to ${
247
- cfg.forwarding_host_pool ? 'host_pool' : `${cfg.host}:${cfg.port}`}`
248
- );
244
+ connection.loginfo(
245
+ plugin,
246
+ `forwarding to ${cfg.forwarding_host_pool ? 'host_pool' : `${cfg.host}:${cfg.port}`}`,
247
+ )
249
248
 
250
- function get_rs () {
249
+ function get_rs() {
251
250
  return connection?.transaction?.results ? connection.transaction.results : connection.results
252
251
  }
253
252
 
254
- function dead_sender () {
253
+ function dead_sender() {
255
254
  if (smtp_client.is_dead_sender(plugin, connection)) {
256
- get_rs().add(plugin, { err: 'dead sender' });
257
- return true;
255
+ get_rs().add(plugin, { err: 'dead sender' })
256
+ return true
258
257
  }
259
- return false;
258
+ return false
260
259
  }
261
260
 
262
- function send_rcpt () {
263
- if (dead_sender() || !txn) return;
261
+ function send_rcpt() {
262
+ if (dead_sender() || !txn) return
264
263
  if (rcpt === txn.rcpt_to.length) {
265
- smtp_client.send_command('DATA');
266
- return;
264
+ smtp_client.send_command('DATA')
265
+ return
267
266
  }
268
- smtp_client.send_command('RCPT', `TO:${txn.rcpt_to[rcpt].format(!smtp_client.smtp_utf8)}`);
269
- rcpt++;
267
+ smtp_client.send_command('RCPT', `TO:${txn.rcpt_to[rcpt].format(!smtp_client.smtp_utf8)}`)
268
+ rcpt++
270
269
  }
271
270
 
272
- smtp_client.on('mail', send_rcpt);
271
+ smtp_client.on('mail', send_rcpt)
273
272
 
274
273
  if (cfg.one_message_per_rcpt) {
275
274
  smtp_client.on('rcpt', () => {
276
- smtp_client.send_command('DATA');
277
- });
278
- }
279
- else {
280
- smtp_client.on('rcpt', send_rcpt);
275
+ smtp_client.send_command('DATA')
276
+ })
277
+ } else {
278
+ smtp_client.on('rcpt', send_rcpt)
281
279
  }
282
280
 
283
281
  smtp_client.on('data', () => {
284
- if (dead_sender()) return;
285
- smtp_client.start_data(txn.message_stream);
286
- });
282
+ if (dead_sender()) return
283
+ smtp_client.start_data(txn.message_stream)
284
+ })
287
285
 
288
286
  smtp_client.on('dot', () => {
289
- if (dead_sender() || !txn) return;
287
+ if (dead_sender() || !txn) return
290
288
 
291
- get_rs().add(plugin, { pass: smtp_client.response });
289
+ get_rs().add(plugin, { pass: smtp_client.response })
292
290
  if (rcpt < txn.rcpt_to.length) {
293
- smtp_client.send_command('RSET');
294
- return;
291
+ smtp_client.send_command('RSET')
292
+ return
295
293
  }
296
- smtp_client.call_next(OK, smtp_client.response);
297
- smtp_client.release();
298
- });
294
+ smtp_client.call_next(OK, smtp_client.response)
295
+ smtp_client.release()
296
+ })
299
297
 
300
298
  smtp_client.on('rset', () => {
301
- if (dead_sender() || !txn) return;
302
- smtp_client.send_command('MAIL', `FROM:${txn.mail_from}`);
303
- });
299
+ if (dead_sender() || !txn) return
300
+ smtp_client.send_command('MAIL', `FROM:${txn.mail_from}`)
301
+ })
304
302
 
305
303
  smtp_client.on('bad_code', (code, msg) => {
306
- if (dead_sender() || !txn) return;
307
- smtp_client.call_next(((code && code[0] === '5') ? DENY : DENYSOFT), msg);
308
- smtp_client.release();
309
- });
310
- });
304
+ if (dead_sender() || !txn) return
305
+ smtp_client.call_next(code && code[0] === '5' ? DENY : DENYSOFT, msg)
306
+ smtp_client.release()
307
+ })
308
+ })
311
309
  }
312
310
 
313
- exports.get_mx_next_hop = next_hop => {
311
+ exports.get_mx_next_hop = (next_hop) => {
314
312
  // queue.wants && queue.next_hop are mechanisms for fine-grained MX routing.
315
313
  // Plugins can specify a queue to perform the delivery as well as a route. A
316
314
  // plugin that uses this is qmail-deliverable, which can direct email delivery
317
315
  // via smtp_forward, outbound (SMTP), and outbound (LMTP).
318
- const dest = new url.URL(next_hop);
316
+ const dest = new url.URL(next_hop)
319
317
  const mx = {
320
318
  priority: 0,
321
319
  port: dest.port || (dest.protocol === 'lmtp:' ? 24 : 25),
322
320
  exchange: dest.hostname,
323
321
  }
324
- if (dest.protocol === 'lmtp:') mx.using_lmtp = true;
322
+ if (dest.protocol === 'lmtp:') mx.using_lmtp = true
325
323
  if (dest.auth) {
326
- mx.auth_type = 'plain';
327
- mx.auth_user = dest.auth.split(':')[0];
328
- mx.auth_pass = dest.auth.split(':')[1];
324
+ mx.auth_type = 'plain'
325
+ mx.auth_user = dest.auth.split(':')[0]
326
+ mx.auth_pass = dest.auth.split(':')[1]
329
327
  }
330
- return mx;
328
+ return mx
331
329
  }
332
330
 
333
331
  exports.get_mx = function (next, hmail, domain) {
334
-
335
332
  const qw = hmail.todo.notes.get('queue.wants')
336
- if (qw && qw !== 'smtp_forward') return next()
333
+ if (qw && !['smtp_forward', 'outbound'].includes(qw)) return next()
337
334
 
338
335
  if (qw === 'smtp_forward' && hmail.todo.notes.get('queue.next_hop')) {
339
- return next(OK, this.get_mx_next_hop(hmail.todo.notes.get('queue.next_hop')));
336
+ return next(OK, this.get_mx_next_hop(hmail.todo.notes.get('queue.next_hop')))
340
337
  }
341
338
 
342
- const dom = this.cfg.main.domain_selector === 'mail_from' ? hmail.todo.mail_from.host.toLowerCase() : domain.toLowerCase();
343
- const cfg = this.cfg[dom];
339
+ const dom =
340
+ this.cfg.main.domain_selector === 'mail_from' ? hmail.todo.mail_from.host.toLowerCase() : domain.toLowerCase()
341
+ const cfg = this.cfg[dom]
344
342
 
345
343
  if (cfg === undefined) {
346
- this.logdebug(`using DNS MX for: ${domain}`);
347
- return next();
344
+ this.logdebug(`using DNS MX for: ${domain}`)
345
+ return next()
348
346
  }
349
347
 
350
- const mx_opts = [
351
- 'auth_type', 'auth_user', 'auth_pass', 'bind', 'bind_helo', 'using_lmtp'
352
- ]
348
+ const mx_opts = ['auth_type', 'auth_user', 'auth_pass', 'bind', 'bind_helo', 'using_lmtp']
353
349
 
354
350
  const mx = {
355
351
  priority: 0,
@@ -358,10 +354,10 @@ exports.get_mx = function (next, hmail, domain) {
358
354
  }
359
355
 
360
356
  // apply auth/mx options
361
- mx_opts.forEach(o => {
362
- if (cfg[o] === undefined) return;
363
- mx[o] = this.cfg[dom][o];
357
+ mx_opts.forEach((o) => {
358
+ if (cfg[o] === undefined) return
359
+ mx[o] = this.cfg[dom][o]
364
360
  })
365
361
 
366
- next(OK, mx);
362
+ next(OK, mx)
367
363
  }