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,4 +1,4 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
3
  // Testing bounce email contents related to errors occuring during SMTP dialog
4
4
 
@@ -12,72 +12,81 @@
12
12
  // * or, in case of 4XX: that temp_fail is called and dsn vars are available)
13
13
 
14
14
  const assert = require('node:assert')
15
- const fs = require('node:fs');
16
- const path = require('node:path');
15
+ const fs = require('node:fs')
16
+ const path = require('node:path')
17
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');
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
24
 
25
- obc.cfg.pool_concurrency_max = 0;
25
+ obc.cfg.pool_concurrency_max = 0
26
26
 
27
27
  const outbound_context = {
28
28
  TODOItem,
29
- exports: outbound
29
+ exports: outbound,
30
30
  }
31
31
 
32
- const queue_dir = path.resolve(__dirname, 'test-queue');
32
+ const queue_dir = path.resolve(__dirname, 'test-queue')
33
33
 
34
34
  describe('outbound_bounce_rfc3464', () => {
35
35
  beforeEach((done) => {
36
- fs.exists(queue_dir, exists => {
37
- if (exists) return done();
36
+ fs.exists(queue_dir, (exists) => {
37
+ if (exists) return done()
38
38
 
39
- fs.mkdir(queue_dir, err => {
40
- if (err) return done(err);
41
- done();
39
+ fs.mkdir(queue_dir, (err) => {
40
+ if (err) return done(err)
41
+ done()
42
42
  })
43
43
  })
44
44
  })
45
45
 
46
46
  afterEach((done) => {
47
- fs.exists(queue_dir, exists => {
47
+ fs.exists(queue_dir, (exists) => {
48
48
  if (!exists) return done()
49
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()) { // recurse
54
- return done(new Error(`did not expect an sub folder here ("${curPath}")! cancel`));
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`))
55
56
  }
56
57
  })
57
- files.forEach((file,index) => {
58
- const curPath = path.resolve(queue_dir, file);
59
- fs.unlinkSync(curPath);
58
+ files.forEach((file, index) => {
59
+ const curPath = path.resolve(queue_dir, file)
60
+ fs.unlinkSync(curPath)
60
61
  })
61
- done();
62
+ done()
62
63
  })
63
64
  })
64
65
 
65
66
  it('test MAIL FROM responded with 500 5.0.0 triggers send_email() containing bounce msg with codes and message', (done) => {
66
-
67
67
  util_hmailitem.newMockHMailItem(outbound_context, done, {}, (mock_hmail) => {
68
- const mock_socket = mock_sock.connect('testhost', 'testport');
69
- mock_socket.writable = true;
68
+ const mock_socket = mock_sock.connect('testhost', 'testport')
69
+ mock_socket.writable = true
70
70
 
71
- const orig_send_email = outbound_context.exports.send_email;
71
+ const orig_send_email = outbound_context.exports.send_email
72
72
 
73
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(contents.match(/^Final-Recipient: rfc822;recipient@domain/m), 'bounce report contains final recipient');
77
- assert.ok(contents.match(/^Action: failed/m), 'DATA-5XX: bounce report contains action field');
78
- assert.ok(contents.match(/^Status: 5\.0\.0/m), 'bounce report contains status field with ext. smtp code');
79
- assert.ok(contents.match(/Absolutely not acceptable\. Basic Test Only\./), 'original upstream message available');
80
- outbound_context.exports.send_email = orig_send_email;
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
81
90
  done()
82
91
  }
83
92
 
@@ -87,210 +96,271 @@ describe('outbound_bounce_rfc3464', () => {
87
96
  // 'test' can hold a function(line) returning true for success, or a string tested for equality
88
97
  const testPlaybook = [
89
98
  // Haraka connects, we say first
90
- { 'from': 'remote', 'line': '220 testing-smtp' },
99
+ { from: 'remote', line: '220 testing-smtp' },
91
100
 
92
- { 'from': 'haraka', 'test': line => line.match(/^EHLO /), 'description': 'Haraka should say EHLO' },
93
- { 'from': 'remote', 'line': '220-testing-smtp' },
94
- { 'from': 'remote', 'line': '220 8BITMIME' },
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' },
95
108
 
96
- { 'from': 'haraka', 'test': 'MAIL FROM:<sender@domain>' },
97
- { 'from': 'remote', 'line': '500 5.0.0 Absolutely not acceptable. Basic Test Only.' },
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
+ },
98
114
 
99
- { 'from': 'haraka', 'test': 'QUIT', end_test: true }, // this will trigger calling the callback
100
- ];
115
+ { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
116
+ ]
101
117
 
102
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {
103
- })
118
+ util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
104
119
  })
105
120
  })
106
121
 
107
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
108
126
 
109
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, mock_hmail => {
110
- const mock_socket = mock_sock.connect('testhost', 'testport');
111
- mock_socket.writable = true;
112
-
113
- const orig_temp_fail = HMailItem.prototype.temp_fail;
127
+ const orig_temp_fail = HMailItem.prototype.temp_fail
114
128
  HMailItem.prototype.temp_fail = function (err, opts) {
115
- assert.ok(true, 'early-3XX: outbound.temp_fail called');
116
- assert.equal('3.0.0', this.todo.rcpt_to[0].dsn_status, 'early-3XX: dsn status = 3.0.0');
117
- assert.equal('delayed', this.todo.rcpt_to[0].dsn_action, 'early-3XX: dsn action = delayed');
118
- assert.ok(this.todo.rcpt_to[0].dsn_smtp_response.match(/No time for you right now/), 'early-3XX: original upstream message available');
119
- HMailItem.prototype.temp_fail = orig_temp_fail;
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
120
137
  done()
121
138
  }
122
139
 
123
140
  const testPlaybook = [
124
- { 'from': 'remote', 'line': '220 testing-smtp' },
125
-
126
- { 'from': 'haraka', 'test': line => line.match(/^EHLO /), 'description': 'Haraka should say EHLO' },
127
- { 'from': 'remote', 'line': '220-testing-smtp' },
128
- { 'from': 'remote', 'line': '220 8BITMIME' },
141
+ { from: 'remote', line: '220 testing-smtp' },
129
142
 
130
- { 'from': 'haraka', 'test': 'MAIL FROM:<sender@domain>' },
131
- { 'from': 'remote', 'line': '300 3.0.0 No time for you right now' },
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' },
132
150
 
133
- { 'from': 'haraka', 'test': 'QUIT', end_test: true }, // this will trigger calling the callback
134
- ];
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
+ },
135
156
 
136
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {
157
+ { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
158
+ ]
137
159
 
138
- })
160
+ util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
139
161
  })
140
162
  })
141
163
 
142
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
143
168
 
144
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, mock_hmail => {
145
- const mock_socket = mock_sock.connect('testhost', 'testport');
146
- mock_socket.writable = true;
147
-
148
- const orig_temp_fail = HMailItem.prototype.temp_fail;
169
+ const orig_temp_fail = HMailItem.prototype.temp_fail
149
170
  HMailItem.prototype.temp_fail = function (err, opts) {
150
- assert.ok(true, 'RCPT-TO-4XX: outbound.temp_fail called');
151
- assert.equal('4.0.0', this.todo.rcpt_to[0].dsn_status, 'RCPT-TO-4XX: dsn status = 4.0.0');
152
- assert.equal('delayed', this.todo.rcpt_to[0].dsn_action, 'RCPT-TO-4XX: dsn action = delayed');
153
- assert.ok(this.todo.rcpt_to[0].dsn_smtp_response.match(/Currently not available\. Try again later\./), 'RCPT-TO-4XX: original upstream message available');
154
- HMailItem.prototype.temp_fail = orig_temp_fail;
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
155
179
  done()
156
- };
180
+ }
157
181
  const testPlaybook = [
158
- { 'from': 'remote', 'line': '220 testing-smtp' },
182
+ { from: 'remote', line: '220 testing-smtp' },
159
183
 
160
- { 'from': 'haraka', 'test': line => line.match(/^EHLO /), 'description': 'Haraka should say EHLO' },
161
- { 'from': 'remote', 'line': '220-testing-smtp' },
162
- { 'from': 'remote', 'line': '220 8BITMIME' },
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' },
163
191
 
164
- { 'from': 'haraka', 'test': 'MAIL FROM:<sender@domain>' },
165
- { 'from': 'remote', 'line': '250 2.1.0 Ok' },
192
+ { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
193
+ { from: 'remote', line: '250 2.1.0 Ok' },
166
194
 
167
- { 'from': 'haraka', 'test': 'RCPT TO:<recipient@domain>' },
168
- { 'from': 'remote', 'line': '400 4.0.0 Currently not available. Try again later.' },
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
+ },
169
200
 
170
- { 'from': 'haraka', 'test': 'QUIT', end_test: true }, // this will trigger calling the callback
171
- ];
201
+ { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
202
+ ]
172
203
 
173
204
  util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
174
205
  })
175
206
  })
176
207
 
177
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
178
212
 
179
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, mock_hmail => {
180
- const mock_socket = mock_sock.connect('testhost', 'testport');
181
- mock_socket.writable = true;
182
-
183
- const orig_temp_fail = HMailItem.prototype.temp_fail;
213
+ const orig_temp_fail = HMailItem.prototype.temp_fail
184
214
  HMailItem.prototype.temp_fail = function (err, opts) {
185
- assert.ok(true, 'DATA-4XX: outbound.temp_fail called');
186
- assert.equal('4.6.0', this.todo.rcpt_to[0].dsn_status, 'DATA-4XX: dsn status = 4.6.0');
187
- assert.equal('delayed', this.todo.rcpt_to[0].dsn_action, 'DATA-4XX: dsn action = delayed');
188
- assert.ok(this.todo.rcpt_to[0].dsn_smtp_response.match(/Currently I do not like ascii art cats\./), 'DATA-4XX: original upstream message available');
189
- HMailItem.prototype.temp_fail = orig_temp_fail;
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
190
223
  done()
191
- };
224
+ }
192
225
  const testPlaybook = [
193
- { 'from': 'remote', 'line': '220 testing-smtp' },
226
+ { from: 'remote', line: '220 testing-smtp' },
194
227
 
195
- { 'from': 'haraka', 'test': line => line.match(/^EHLO /), 'description': 'Haraka should say EHLO' },
196
- { 'from': 'remote', 'line': '220-testing-smtp' },
197
- { 'from': 'remote', 'line': '220 8BITMIME' },
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' },
198
235
 
199
- { 'from': 'haraka', 'test': 'MAIL FROM:<sender@domain>' },
200
- { 'from': 'remote', 'line': '250 2.1.0 Ok' },
236
+ { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
237
+ { from: 'remote', line: '250 2.1.0 Ok' },
201
238
 
202
- { 'from': 'haraka', 'test': 'RCPT TO:<recipient@domain>' },
203
- { 'from': 'remote', 'line': '250 2.1.5 Ok' },
239
+ { from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
240
+ { from: 'remote', line: '250 2.1.5 Ok' },
204
241
 
205
- { 'from': 'haraka', 'test': 'DATA' },
242
+ { from: 'haraka', test: 'DATA' },
206
243
  // haraka will send us more lines
207
- { 'from': 'remote', 'line': '450 4.6.0 Currently I do not like ascii art cats.' },
208
-
209
- { 'from': 'haraka', 'test': 'QUIT', end_test: true }, // this will trigger calling the callback
210
- ];
244
+ {
245
+ from: 'remote',
246
+ line: '450 4.6.0 Currently I do not like ascii art cats.',
247
+ },
211
248
 
212
- util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {
249
+ { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
250
+ ]
213
251
 
214
- })
252
+ util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
215
253
  })
216
254
  })
217
255
 
218
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
219
260
 
220
- util_hmailitem.newMockHMailItem(outbound_context, done, {}, mock_hmail => {
221
- const mock_socket = mock_sock.connect('testhost', 'testport');
222
- mock_socket.writable = true;
223
-
224
- const orig_send_email = outbound_context.exports.send_email;
261
+ const orig_send_email = outbound_context.exports.send_email
225
262
  outbound_context.exports.send_email = (from, to, contents, cb, opts) => {
226
- assert.ok(true, 'RCPT-TO-5XX: outbound.send_email called');
227
- assert.ok(contents.match(/^Content-type: message\/delivery-status/m), 'RCPT-TO-5XX: its a bounce report');
228
- assert.ok(contents.match(/^Final-Recipient: rfc822;recipient@domain/m), 'RCPT-TO-5XX: bounce report contains final recipient');
229
- assert.ok(contents.match(/^Action: failed/m), 'DATA-5XX: bounce report contains action field');
230
- assert.ok(contents.match(/^Status: 5\.1\.1/m), 'RCPT-TO-5XX: bounce report contains status field with our ext. smtp code');
231
- assert.ok(contents.match(/Not available and will not come back/), 'RCPT-TO-5XX: original upstream message available');
232
- outbound_context.exports.send_email = orig_send_email;
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
233
282
  done()
234
- };
283
+ }
235
284
  const testPlaybook = [
236
- { 'from': 'remote', 'line': '220 testing-smtp' },
285
+ { from: 'remote', line: '220 testing-smtp' },
237
286
 
238
- { 'from': 'haraka', 'test': line => line.match(/^EHLO /), 'description': 'Haraka should say EHLO' },
239
- { 'from': 'remote', 'line': '220-testing-smtp' },
240
- { 'from': 'remote', 'line': '220 8BITMIME' },
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' },
241
294
 
242
- { 'from': 'haraka', 'test': 'MAIL FROM:<sender@domain>' },
243
- { 'from': 'remote', 'line': '250 2.1.0 Ok' },
295
+ { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
296
+ { from: 'remote', line: '250 2.1.0 Ok' },
244
297
 
245
- { 'from': 'haraka', 'test': 'RCPT TO:<recipient@domain>' },
246
- { 'from': 'remote', 'line': '550 5.1.1 Not available and will not come back' },
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
+ },
247
303
 
248
- { 'from': 'haraka', 'test': 'QUIT', end_test: true }, // this will trigger calling the callback
249
- ];
304
+ { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
305
+ ]
250
306
 
251
307
  util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
252
308
  })
253
309
  })
254
310
 
255
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
256
315
 
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;
316
+ const orig_send_email = outbound_context.exports.send_email
262
317
  outbound_context.exports.send_email = (from, to, contents, cb, opts) => {
263
- assert.ok(true, 'DATA-5XX: outbound.send_email called');
264
- assert.ok(contents.match(/^Content-type: message\/delivery-status/m), 'DATA-5XX: its a bounce report');
265
- assert.ok(contents.match(/^Final-Recipient: rfc822;recipient@domain/m), 'DATA-5XX: bounce report contains final recipient');
266
- assert.ok(contents.match(/^Action: failed/m), 'DATA-5XX: bounce report contains action field');
267
- assert.ok(contents.match(/^Status: 5\.6\.0/m), 'DATA-5XX: bounce report contains status field with our ext. smtp code');
268
- assert.ok(contents.match(/I never did and will like ascii art cats/), 'DATA-5XX: original upstream message available');
269
- outbound_context.exports.send_email = orig_send_email;
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
270
334
  done()
271
- };
335
+ }
272
336
  const testPlaybook = [
273
- { 'from': 'remote', 'line': '220 testing-smtp' },
337
+ { from: 'remote', line: '220 testing-smtp' },
274
338
 
275
- { 'from': 'haraka', 'test': line => line.match(/^EHLO /), 'description': 'Haraka should say EHLO' },
276
- { 'from': 'remote', 'line': '220-testing-smtp' },
277
- { 'from': 'remote', 'line': '220 8BITMIME' },
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' },
278
346
 
279
- { 'from': 'haraka', 'test': 'MAIL FROM:<sender@domain>' },
280
- { 'from': 'remote', 'line': '250 2.1.0 Ok' },
347
+ { from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
348
+ { from: 'remote', line: '250 2.1.0 Ok' },
281
349
 
282
- { 'from': 'haraka', 'test': 'RCPT TO:<recipient@domain>' },
283
- { 'from': 'remote', 'line': '250 2.1.5 Ok' },
350
+ { from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
351
+ { from: 'remote', line: '250 2.1.5 Ok' },
284
352
 
285
- { 'from': 'haraka', 'test': 'DATA' },
353
+ { from: 'haraka', test: 'DATA' },
286
354
  // haraka will send us more lines
287
- { 'from': 'remote', 'line': '550 5.6.0 I never did and will like ascii art cats.' },
355
+ {
356
+ from: 'remote',
357
+ line: '550 5.6.0 I never did and will like ascii art cats.',
358
+ },
288
359
 
289
- { 'from': 'haraka', 'test': 'QUIT', end_test: true }, // this will trigger calling the callback
290
- ];
360
+ { from: 'haraka', test: 'QUIT', end_test: true }, // this will trigger calling the callback
361
+ ]
291
362
 
292
363
  util_hmailitem.playTestSmtpConversation(mock_hmail, mock_socket, done, testPlaybook, () => {})
293
364
  })
294
365
  })
295
366
  })
296
-