Haraka 3.1.3 → 3.1.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 (55) hide show
  1. package/.prettierignore +2 -0
  2. package/CONTRIBUTORS.md +23 -1
  3. package/Changes.md +38 -0
  4. package/Plugins.md +81 -64
  5. package/README.md +1 -1
  6. package/bin/haraka +7 -5
  7. package/connection.js +15 -19
  8. package/docs/Plugins.md +1 -1
  9. package/docs/plugins/aliases.md +0 -2
  10. package/docs/plugins/queue/qmail-queue.md +0 -1
  11. package/logger.js +2 -2
  12. package/outbound/hmail.js +76 -83
  13. package/outbound/index.js +36 -34
  14. package/outbound/queue.js +231 -176
  15. package/package.json +25 -26
  16. package/plugins/prevent_credential_leaks.js +2 -2
  17. package/plugins/process_title.js +1 -1
  18. package/plugins/queue/smtp_forward.js +1 -1
  19. package/plugins/status.js +8 -5
  20. package/plugins/tls.js +1 -1
  21. package/plugins.js +19 -14
  22. package/rfc1869.js +10 -10
  23. package/run_tests +20 -2
  24. package/server.js +15 -10
  25. package/smtp_client.js +2 -9
  26. package/test/config/tls/haraka.local.pem +47 -47
  27. package/test/connection.js +286 -147
  28. package/test/fixtures/line_socket.js +1 -0
  29. package/test/fixtures/util_hmailitem.js +1 -1
  30. package/test/outbound/bounce_net_errors.js +176 -0
  31. package/test/outbound/bounce_rfc3464.js +303 -0
  32. package/test/outbound/hmail.js +140 -104
  33. package/test/outbound/index.js +61 -101
  34. package/test/outbound/qfile.js +25 -25
  35. package/test/outbound/queue.js +233 -0
  36. package/test/plugins/queue/smtp_forward.js +1 -1
  37. package/test/plugins/record_envelope_addresses.js +93 -0
  38. package/test/plugins/tls.js +2 -2
  39. package/test/plugins/xclient.js +137 -0
  40. package/test/rfc1869.js +43 -0
  41. package/test/smtp_client.js +6 -6
  42. package/test/transaction.js +486 -201
  43. package/tls_socket.js +3 -3
  44. package/transaction.js +33 -10
  45. package/config/rabbitmq.ini +0 -10
  46. package/config/rabbitmq_amqplib.ini +0 -19
  47. package/docs/plugins/queue/rabbitmq.md +0 -34
  48. package/docs/plugins/queue/rabbitmq_amqplib.md +0 -51
  49. package/plugins/queue/rabbitmq.js +0 -141
  50. package/plugins/queue/rabbitmq_amqplib.js +0 -96
  51. package/test/config/tls/ec.pem +0 -23
  52. package/test/config/tls/mismatched.pem +0 -49
  53. package/test/outbound_bounce_net_errors.js +0 -157
  54. package/test/outbound_bounce_rfc3464.js +0 -366
  55. package/test/tls_socket.js +0 -273
@@ -1,157 +0,0 @@
1
- 'use strict'
2
-
3
- // Testing bounce email contents related to errors occuring during SMTP dialog
4
-
5
- // About running the tests:
6
- // - Making a folder for queuing files
7
- // - Creating a HMailItem instance using fixtures/util_hmailitem
8
- // - Talk some STMP in the playbook
9
- // - Test the outcome by replacing trigger functions with our testing code (outbound.send_email, HMailItem.temp_fail, ...)
10
-
11
- const assert = require('node:assert')
12
- const dns = require('node:dns')
13
- const fs = require('node:fs')
14
- const path = require('node:path')
15
-
16
- const constants = require('haraka-constants')
17
- const util_hmailitem = require('./fixtures/util_hmailitem')
18
- const TODOItem = require('../outbound/todo')
19
- const HMailItem = require('../outbound/hmail')
20
- const outbound = require('../outbound')
21
-
22
- const outbound_context = {
23
- TODOItem,
24
- exports: outbound,
25
- }
26
-
27
- const queue_dir = path.resolve(__dirname, 'test-queue')
28
-
29
- describe('outbound_bounce_net_errors', () => {
30
- beforeEach((done) => {
31
- fs.exists(queue_dir, (exists) => {
32
- if (exists) {
33
- done()
34
- } else {
35
- fs.mkdir(queue_dir, done)
36
- }
37
- })
38
- })
39
-
40
- afterEach((done) => {
41
- fs.exists(queue_dir, (exists) => {
42
- if (exists) {
43
- for (const file of fs.readdirSync(queue_dir)) {
44
- const curPath = path.resolve(queue_dir, file)
45
- if (fs.lstatSync(curPath).isDirectory()) {
46
- console.error(`did not expect an sub folder here ("${curPath}")! cancel`)
47
- }
48
- fs.unlinkSync(curPath)
49
- }
50
- }
51
- done()
52
- })
53
- })
54
-
55
- it('test get-mx-deny triggers bounce(...)', (done) => {
56
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
57
- const orig_bounce = HMailItem.prototype.bounce
58
- HMailItem.prototype.bounce = function (err, opts) {
59
- assert.ok(true, 'get_mx=DENY: bounce function called')
60
- /* dsn_code: 550,
61
- dsn_status: '5.1.2',
62
- dsn_action: 'failed' */
63
- assert.equal('5.1.2', this.todo.rcpt_to[0].dsn_status, 'get_mx=DENY dsn status = 5.1.2')
64
- done()
65
- }
66
- mock_hmail.domain = mock_hmail.todo.domain
67
- HMailItem.prototype.get_mx_respond.apply(mock_hmail, [constants.deny, {}])
68
- HMailItem.prototype.bounce = orig_bounce
69
- })
70
- })
71
-
72
- it('test get-mx-denysoft triggers temp_fail(...)', (done) => {
73
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
74
- const orig_temp_fail = HMailItem.prototype.temp_fail
75
- HMailItem.prototype.temp_fail = function (err, opts) {
76
- assert.ok(true, 'get_mx-DENYSOFT: temp_fail function called')
77
- /*dsn_code: 450,
78
- dsn_status: '4.1.2',
79
- dsn_action: 'delayed' */
80
- assert.equal('4.1.2', this.todo.rcpt_to[0].dsn_status, 'get_mx=DENYSOFT dsn status = 4.1.2')
81
- done()
82
- }
83
- mock_hmail.domain = mock_hmail.todo.domain
84
- HMailItem.prototype.get_mx_respond.apply(mock_hmail, [constants.denysoft, {}])
85
- HMailItem.prototype.temp_fail = orig_temp_fail
86
- })
87
- })
88
-
89
- it('test found_mx({code:dns.NXDOMAIN}) triggers bounce(...)', (done) => {
90
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
91
- const orig_bounce = HMailItem.prototype.bounce
92
- HMailItem.prototype.bounce = function (err, opts) {
93
- assert.ok(true, 'get_mx_error({code: dns.NXDOMAIN}): bounce function called')
94
- assert.equal(
95
- '5.1.2',
96
- this.todo.rcpt_to[0].dsn_status,
97
- 'get_mx_error({code: dns.NXDOMAIN}: dsn status = 5.1.2',
98
- )
99
- done()
100
- }
101
- HMailItem.prototype.get_mx_error.apply(mock_hmail, [{ code: dns.NXDOMAIN }])
102
- HMailItem.prototype.bounce = orig_bounce
103
- })
104
- })
105
-
106
- it("test get_mx_error({code:'SOME-OTHER-ERR'}) triggers temp_fail(...)", (done) => {
107
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
108
- const orig_temp_fail = HMailItem.prototype.temp_fail
109
- HMailItem.prototype.temp_fail = function (err, opts) {
110
- assert.ok(true, 'get_mx_error({code: "SOME-OTHER-ERR"}): temp_fail function called')
111
- assert.equal(
112
- '4.1.0',
113
- this.todo.rcpt_to[0].dsn_status,
114
- 'get_mx_error({code: "SOME-OTHER-ERR"}: dsn status = 4.1.0',
115
- )
116
- done()
117
- }
118
- HMailItem.prototype.get_mx_error.apply(mock_hmail, [{ code: 'SOME-OTHER-ERR' }, {}])
119
- HMailItem.prototype.temp_fail = orig_temp_fail
120
- })
121
- })
122
-
123
- it("test found_mx(null, [{priority:0,exchange:''}]) triggers bounce(...)", (done) => {
124
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
125
- const orig_bounce = HMailItem.prototype.bounce
126
- HMailItem.prototype.bounce = function (err, opts) {
127
- assert.ok(true, 'found_mx(null, [{priority:0,exchange:""}]): bounce function called')
128
- assert.equal(
129
- '5.1.2',
130
- this.todo.rcpt_to[0].dsn_status,
131
- 'found_mx(null, [{priority:0,exchange:""}]): dsn status = 5.1.2',
132
- )
133
- done()
134
- }
135
- HMailItem.prototype.found_mx.apply(mock_hmail, [[{ priority: 0, exchange: '' }]])
136
- HMailItem.prototype.bounce = orig_bounce
137
- })
138
- })
139
-
140
- it('test try_deliver while hmail.mxlist=[] triggers bounce(...)', (done) => {
141
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
142
- mock_hmail.mxlist = []
143
- const orig_temp_fail = HMailItem.prototype.temp_fail
144
- HMailItem.prototype.temp_fail = function (err, opts) {
145
- assert.ok(true, 'try_deliver while hmail.mxlist=[]: temp_fail function called')
146
- assert.equal(
147
- '5.1.2',
148
- this.todo.rcpt_to[0].dsn_status,
149
- 'try_deliver while hmail.mxlist=[]: dsn status = 5.1.2',
150
- )
151
- done()
152
- }
153
- HMailItem.prototype.try_deliver.apply(mock_hmail, [])
154
- HMailItem.prototype.temp_fail = orig_temp_fail
155
- })
156
- })
157
- })
@@ -1,366 +0,0 @@
1
- 'use strict'
2
-
3
- // Testing bounce email contents related to errors occuring during SMTP dialog
4
-
5
- // About running the tests:
6
- // - Making a folder for queuing files
7
- // - Creating a HMailItem instance using fixtures/util_hmailitem
8
- // - Talk some SMTP in the playbook
9
- // - Test the outcome by replacing trigger functions with our testing code (outbound.send_email, HMailItem.temp_fail, ...)
10
- // At one point, the mocked remote SMTP says "5XX" or "4XX" and we test that
11
- // * outbound.send_email is called with a RFC3464 bounce message
12
- // * or, in case of 4XX: that temp_fail is called and dsn vars are available)
13
-
14
- const assert = require('node:assert')
15
- const fs = require('node:fs')
16
- const path = require('node:path')
17
-
18
- const util_hmailitem = require('./fixtures/util_hmailitem')
19
- const TODOItem = require('../outbound/todo')
20
- const HMailItem = require('../outbound/hmail')
21
- const obc = require('../outbound/config')
22
- const outbound = require('../outbound')
23
- const mock_sock = require('./fixtures/line_socket')
24
-
25
- obc.cfg.pool_concurrency_max = 0
26
-
27
- const outbound_context = {
28
- TODOItem,
29
- exports: outbound,
30
- }
31
-
32
- const queue_dir = path.resolve(__dirname, 'test-queue')
33
-
34
- describe('outbound_bounce_rfc3464', () => {
35
- beforeEach((done) => {
36
- fs.exists(queue_dir, (exists) => {
37
- if (exists) return done()
38
-
39
- fs.mkdir(queue_dir, (err) => {
40
- if (err) return done(err)
41
- done()
42
- })
43
- })
44
- })
45
-
46
- afterEach((done) => {
47
- fs.exists(queue_dir, (exists) => {
48
- if (!exists) return done()
49
-
50
- const files = fs.readdirSync(queue_dir)
51
- files.forEach((file, index) => {
52
- const curPath = path.resolve(queue_dir, file)
53
- if (fs.lstatSync(curPath).isDirectory()) {
54
- // recurse
55
- return done(new Error(`did not expect an sub folder here ("${curPath}")! cancel`))
56
- }
57
- })
58
- files.forEach((file, index) => {
59
- const curPath = path.resolve(queue_dir, file)
60
- fs.unlinkSync(curPath)
61
- })
62
- done()
63
- })
64
- })
65
-
66
- it('test MAIL FROM responded with 500 5.0.0 triggers send_email() containing bounce msg with codes and message', (done) => {
67
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
68
- const mock_socket = mock_sock.connect('testhost', 'testport')
69
- mock_socket.writable = true
70
-
71
- const orig_send_email = outbound_context.exports.send_email
72
-
73
- outbound_context.exports.send_email = (from, to, contents, cb, opts) => {
74
- assert.ok(true, 'outbound.send_email called')
75
- assert.ok(contents.match(/^Content-type: message\/delivery-status/m), 'its a bounce report')
76
- assert.ok(
77
- contents.match(/^Final-Recipient: rfc822;recipient@domain/m),
78
- 'bounce report contains final recipient',
79
- )
80
- assert.ok(contents.match(/^Action: failed/m), 'DATA-5XX: bounce report contains action field')
81
- assert.ok(
82
- contents.match(/^Status: 5\.0\.0/m),
83
- 'bounce report contains status field with ext. smtp code',
84
- )
85
- assert.ok(
86
- contents.match(/Absolutely not acceptable\. Basic Test Only\./),
87
- 'original upstream message available',
88
- )
89
- outbound_context.exports.send_email = orig_send_email
90
- done()
91
- }
92
-
93
- // The playbook
94
- // from remote: This line is to be sent (from an mocked remote SMTP) to haraka outbound. This is done in this test.
95
- // from haraka: Expected answer from haraka-outbound to the mocked remote SMTP.
96
- // 'test' can hold a function(line) returning true for success, or a string tested for equality
97
- const testPlaybook = [
98
- // Haraka connects, we say first
99
- { from: 'remote', line: '220 testing-smtp' },
100
-
101
- {
102
- from: 'haraka',
103
- test: (line) => line.match(/^EHLO /),
104
- description: 'Haraka should say EHLO',
105
- },
106
- { from: 'remote', line: '220-testing-smtp' },
107
- { from: 'remote', line: '220 8BITMIME' },
108
-
109
- { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
110
- {
111
- from: 'remote',
112
- line: '500 5.0.0 Absolutely not acceptable. Basic Test Only.',
113
- },
114
-
115
- { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
116
- ]
117
-
118
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
119
- })
120
- })
121
-
122
- it('test that early response of 3XX triggers temp_fail', (done) => {
123
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
124
- const mock_socket = mock_sock.connect('testhost', 'testport')
125
- mock_socket.writable = true
126
-
127
- const orig_temp_fail = HMailItem.prototype.temp_fail
128
- HMailItem.prototype.temp_fail = function (err, opts) {
129
- assert.ok(true, 'early-3XX: outbound.temp_fail called')
130
- assert.equal('3.0.0', this.todo.rcpt_to[0].dsn_status, 'early-3XX: dsn status = 3.0.0')
131
- assert.equal('delayed', this.todo.rcpt_to[0].dsn_action, 'early-3XX: dsn action = delayed')
132
- assert.ok(
133
- this.todo.rcpt_to[0].dsn_smtp_response.match(/No time for you right now/),
134
- 'early-3XX: original upstream message available',
135
- )
136
- HMailItem.prototype.temp_fail = orig_temp_fail
137
- done()
138
- }
139
-
140
- const testPlaybook = [
141
- { from: 'remote', line: '220 testing-smtp' },
142
-
143
- {
144
- from: 'haraka',
145
- test: (line) => line.match(/^EHLO /),
146
- description: 'Haraka should say EHLO',
147
- },
148
- { from: 'remote', line: '220-testing-smtp' },
149
- { from: 'remote', line: '220 8BITMIME' },
150
-
151
- { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
152
- {
153
- from: 'remote',
154
- line: '300 3.0.0 No time for you right now',
155
- },
156
-
157
- { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
158
- ]
159
-
160
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
161
- })
162
- })
163
-
164
- it('test that response of 4XX for RCPT-TO triggers temp_fail', (done) => {
165
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
166
- const mock_socket = mock_sock.connect('testhost', 'testport')
167
- mock_socket.writable = true
168
-
169
- const orig_temp_fail = HMailItem.prototype.temp_fail
170
- HMailItem.prototype.temp_fail = function (err, opts) {
171
- assert.ok(true, 'RCPT-TO-4XX: outbound.temp_fail called')
172
- assert.equal('4.0.0', this.todo.rcpt_to[0].dsn_status, 'RCPT-TO-4XX: dsn status = 4.0.0')
173
- assert.equal('delayed', this.todo.rcpt_to[0].dsn_action, 'RCPT-TO-4XX: dsn action = delayed')
174
- assert.ok(
175
- this.todo.rcpt_to[0].dsn_smtp_response.match(/Currently not available\. Try again later\./),
176
- 'RCPT-TO-4XX: original upstream message available',
177
- )
178
- HMailItem.prototype.temp_fail = orig_temp_fail
179
- done()
180
- }
181
- const testPlaybook = [
182
- { from: 'remote', line: '220 testing-smtp' },
183
-
184
- {
185
- from: 'haraka',
186
- test: (line) => line.match(/^EHLO /),
187
- description: 'Haraka should say EHLO',
188
- },
189
- { from: 'remote', line: '220-testing-smtp' },
190
- { from: 'remote', line: '220 8BITMIME' },
191
-
192
- { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
193
- { from: 'remote', line: '250 2.1.0 Ok' },
194
-
195
- { from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
196
- {
197
- from: 'remote',
198
- line: '400 4.0.0 Currently not available. Try again later.',
199
- },
200
-
201
- { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
202
- ]
203
-
204
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
205
- })
206
- })
207
-
208
- it('test that response of 4XX for DATA triggers temp_fail', (done) => {
209
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
210
- const mock_socket = mock_sock.connect('testhost', 'testport')
211
- mock_socket.writable = true
212
-
213
- const orig_temp_fail = HMailItem.prototype.temp_fail
214
- HMailItem.prototype.temp_fail = function (err, opts) {
215
- assert.ok(true, 'DATA-4XX: outbound.temp_fail called')
216
- assert.equal('4.6.0', this.todo.rcpt_to[0].dsn_status, 'DATA-4XX: dsn status = 4.6.0')
217
- assert.equal('delayed', this.todo.rcpt_to[0].dsn_action, 'DATA-4XX: dsn action = delayed')
218
- assert.ok(
219
- this.todo.rcpt_to[0].dsn_smtp_response.match(/Currently I do not like ascii art cats\./),
220
- 'DATA-4XX: original upstream message available',
221
- )
222
- HMailItem.prototype.temp_fail = orig_temp_fail
223
- done()
224
- }
225
- const testPlaybook = [
226
- { from: 'remote', line: '220 testing-smtp' },
227
-
228
- {
229
- from: 'haraka',
230
- test: (line) => line.match(/^EHLO /),
231
- description: 'Haraka should say EHLO',
232
- },
233
- { from: 'remote', line: '220-testing-smtp' },
234
- { from: 'remote', line: '220 8BITMIME' },
235
-
236
- { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
237
- { from: 'remote', line: '250 2.1.0 Ok' },
238
-
239
- { from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
240
- { from: 'remote', line: '250 2.1.5 Ok' },
241
-
242
- { from: 'haraka', test: 'DATA' },
243
- // haraka will send us more lines
244
- {
245
- from: 'remote',
246
- line: '450 4.6.0 Currently I do not like ascii art cats.',
247
- },
248
-
249
- { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
250
- ]
251
-
252
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
253
- })
254
- })
255
-
256
- it('test that response of 5XX for RCPT-TO triggers send_email() containing bounce msg with codes and message', (done) => {
257
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
258
- const mock_socket = mock_sock.connect('testhost', 'testport')
259
- mock_socket.writable = true
260
-
261
- const orig_send_email = outbound_context.exports.send_email
262
- outbound_context.exports.send_email = (from, to, contents, cb, opts) => {
263
- assert.ok(true, 'RCPT-TO-5XX: outbound.send_email called')
264
- assert.ok(
265
- contents.match(/^Content-type: message\/delivery-status/m),
266
- 'RCPT-TO-5XX: its a bounce report',
267
- )
268
- assert.ok(
269
- contents.match(/^Final-Recipient: rfc822;recipient@domain/m),
270
- 'RCPT-TO-5XX: bounce report contains final recipient',
271
- )
272
- assert.ok(contents.match(/^Action: failed/m), 'DATA-5XX: bounce report contains action field')
273
- assert.ok(
274
- contents.match(/^Status: 5\.1\.1/m),
275
- 'RCPT-TO-5XX: bounce report contains status field with our ext. smtp code',
276
- )
277
- assert.ok(
278
- contents.match(/Not available and will not come back/),
279
- 'RCPT-TO-5XX: original upstream message available',
280
- )
281
- outbound_context.exports.send_email = orig_send_email
282
- done()
283
- }
284
- const testPlaybook = [
285
- { from: 'remote', line: '220 testing-smtp' },
286
-
287
- {
288
- from: 'haraka',
289
- test: (line) => line.match(/^EHLO /),
290
- description: 'Haraka should say EHLO',
291
- },
292
- { from: 'remote', line: '220-testing-smtp' },
293
- { from: 'remote', line: '220 8BITMIME' },
294
-
295
- { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
296
- { from: 'remote', line: '250 2.1.0 Ok' },
297
-
298
- { from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
299
- {
300
- from: 'remote',
301
- line: '550 5.1.1 Not available and will not come back',
302
- },
303
-
304
- { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
305
- ]
306
-
307
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
308
- })
309
- })
310
-
311
- it('test that response of 5XX for DATA triggers send_email() containing bounce msg with codes and message', (done) => {
312
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
313
- const mock_socket = mock_sock.connect('testhost', 'testport')
314
- mock_socket.writable = true
315
-
316
- const orig_send_email = outbound_context.exports.send_email
317
- outbound_context.exports.send_email = (from, to, contents, cb, opts) => {
318
- assert.ok(true, 'DATA-5XX: outbound.send_email called')
319
- assert.ok(contents.match(/^Content-type: message\/delivery-status/m), 'DATA-5XX: its a bounce report')
320
- assert.ok(
321
- contents.match(/^Final-Recipient: rfc822;recipient@domain/m),
322
- 'DATA-5XX: bounce report contains final recipient',
323
- )
324
- assert.ok(contents.match(/^Action: failed/m), 'DATA-5XX: bounce report contains action field')
325
- assert.ok(
326
- contents.match(/^Status: 5\.6\.0/m),
327
- 'DATA-5XX: bounce report contains status field with our ext. smtp code',
328
- )
329
- assert.ok(
330
- contents.match(/I never did and will like ascii art cats/),
331
- 'DATA-5XX: original upstream message available',
332
- )
333
- outbound_context.exports.send_email = orig_send_email
334
- done()
335
- }
336
- const testPlaybook = [
337
- { from: 'remote', line: '220 testing-smtp' },
338
-
339
- {
340
- from: 'haraka',
341
- test: (line) => line.match(/^EHLO /),
342
- description: 'Haraka should say EHLO',
343
- },
344
- { from: 'remote', line: '220-testing-smtp' },
345
- { from: 'remote', line: '220 8BITMIME' },
346
-
347
- { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
348
- { from: 'remote', line: '250 2.1.0 Ok' },
349
-
350
- { from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
351
- { from: 'remote', line: '250 2.1.5 Ok' },
352
-
353
- { from: 'haraka', test: 'DATA' },
354
- // haraka will send us more lines
355
- {
356
- from: 'remote',
357
- line: '550 5.6.0 I never did and will like ascii art cats.',
358
- },
359
-
360
- { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
361
- ]
362
-
363
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
364
- })
365
- })
366
- })