Haraka 3.1.1 → 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.
- package/.prettierignore +4 -0
- package/CONTRIBUTORS.md +5 -5
- package/Changes.md +62 -50
- package/Plugins.md +3 -1
- package/README.md +1 -1
- package/bin/haraka +475 -479
- package/config/outbound.ini +3 -0
- package/connection.js +1072 -1108
- package/docs/Connection.md +29 -30
- package/docs/CoreConfig.md +38 -39
- package/docs/CustomReturnCodes.md +0 -1
- package/docs/HAProxy.md +2 -2
- package/docs/Header.md +1 -1
- package/docs/Logging.md +29 -5
- package/docs/Outbound.md +93 -78
- package/docs/Plugins.md +103 -108
- package/docs/Transaction.md +49 -51
- package/docs/Tutorial.md +127 -143
- package/docs/deprecated/access.md +0 -1
- package/docs/deprecated/backscatterer.md +2 -3
- package/docs/deprecated/connect.rdns_access.md +18 -27
- package/docs/deprecated/data.headers.md +0 -1
- package/docs/deprecated/data.nomsgid.md +1 -2
- package/docs/deprecated/data.noreceived.md +1 -2
- package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
- package/docs/deprecated/dkim_sign.md +13 -17
- package/docs/deprecated/dkim_verify.md +9 -17
- package/docs/deprecated/dnsbl.md +36 -38
- package/docs/deprecated/dnswl.md +41 -43
- package/docs/deprecated/lookup_rdns.strict.md +21 -34
- package/docs/deprecated/mail_from.access.md +17 -25
- package/docs/deprecated/mail_from.blocklist.md +9 -12
- package/docs/deprecated/mail_from.nobounces.md +1 -2
- package/docs/deprecated/rcpt_to.access.md +20 -27
- package/docs/deprecated/rcpt_to.blocklist.md +10 -13
- package/docs/deprecated/rcpt_to.routes.md +0 -1
- package/docs/deprecated/rdns.regexp.md +13 -15
- package/docs/plugins/aliases.md +89 -89
- package/docs/plugins/auth/auth_bridge.md +5 -7
- package/docs/plugins/auth/auth_ldap.md +11 -14
- package/docs/plugins/auth/auth_proxy.md +10 -12
- package/docs/plugins/auth/auth_vpopmaild.md +5 -6
- package/docs/plugins/auth/flat_file.md +4 -4
- package/docs/plugins/block_me.md +3 -3
- package/docs/plugins/data.signatures.md +1 -2
- package/docs/plugins/delay_deny.md +3 -4
- package/docs/plugins/max_unrecognized_commands.md +4 -4
- package/docs/plugins/prevent_credential_leaks.md +6 -6
- package/docs/plugins/process_title.md +18 -18
- package/docs/plugins/queue/deliver.md +2 -3
- package/docs/plugins/queue/discard.md +4 -4
- package/docs/plugins/queue/lmtp.md +1 -3
- package/docs/plugins/queue/qmail-queue.md +7 -9
- package/docs/plugins/queue/quarantine.md +16 -21
- package/docs/plugins/queue/rabbitmq.md +8 -11
- package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
- package/docs/plugins/queue/smtp_bridge.md +7 -10
- package/docs/plugins/queue/smtp_forward.md +42 -34
- package/docs/plugins/queue/smtp_proxy.md +30 -29
- package/docs/plugins/queue/test.md +1 -3
- package/docs/plugins/rcpt_to.in_host_list.md +6 -6
- package/docs/plugins/rcpt_to.max_count.md +1 -1
- package/docs/plugins/record_envelope_addresses.md +3 -3
- package/docs/plugins/reseed_rng.md +6 -6
- package/docs/plugins/status.md +9 -8
- package/docs/plugins/tarpit.md +7 -11
- package/docs/plugins/tls.md +12 -17
- package/docs/plugins/toobusy.md +4 -4
- package/docs/plugins/xclient.md +3 -3
- package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
- package/docs/tutorials/SettingUpOutbound.md +6 -9
- package/endpoint.js +35 -38
- package/eslint.config.mjs +22 -19
- package/haraka.js +42 -47
- package/host_pool.js +75 -79
- package/http/html/404.html +45 -49
- package/http/html/index.html +39 -28
- package/http/package.json +2 -4
- package/line_socket.js +27 -28
- package/logger.js +182 -201
- package/outbound/client_pool.js +33 -33
- package/outbound/config.js +64 -59
- package/outbound/fsync_writestream.js +24 -25
- package/outbound/hmail.js +888 -835
- package/outbound/index.js +194 -187
- package/outbound/qfile.js +49 -52
- package/outbound/queue.js +197 -190
- package/outbound/timer_queue.js +41 -43
- package/outbound/tls.js +68 -61
- package/outbound/todo.js +11 -11
- package/package.json +32 -32
- package/plugins/.eslintrc.yaml +0 -1
- package/plugins/auth/auth_base.js +123 -127
- package/plugins/auth/auth_bridge.js +7 -7
- package/plugins/auth/auth_proxy.js +121 -126
- package/plugins/auth/auth_vpopmaild.js +84 -85
- package/plugins/auth/flat_file.js +18 -17
- package/plugins/block_me.js +31 -31
- package/plugins/data.signatures.js +13 -13
- package/plugins/delay_deny.js +65 -61
- package/plugins/prevent_credential_leaks.js +23 -23
- package/plugins/process_title.js +125 -128
- package/plugins/profile.js +5 -5
- package/plugins/queue/deliver.js +3 -3
- package/plugins/queue/discard.js +13 -14
- package/plugins/queue/lmtp.js +16 -17
- package/plugins/queue/qmail-queue.js +54 -55
- package/plugins/queue/quarantine.js +68 -70
- package/plugins/queue/rabbitmq.js +80 -87
- package/plugins/queue/rabbitmq_amqplib.js +75 -54
- package/plugins/queue/smtp_bridge.js +16 -16
- package/plugins/queue/smtp_forward.js +175 -179
- package/plugins/queue/smtp_proxy.js +69 -71
- package/plugins/queue/test.js +9 -9
- package/plugins/rcpt_to.host_list_base.js +30 -34
- package/plugins/rcpt_to.in_host_list.js +19 -19
- package/plugins/record_envelope_addresses.js +4 -4
- package/plugins/reseed_rng.js +4 -4
- package/plugins/status.js +90 -97
- package/plugins/tarpit.js +25 -14
- package/plugins/tls.js +68 -68
- package/plugins/toobusy.js +21 -23
- package/plugins/xclient.js +51 -53
- package/plugins.js +276 -293
- package/rfc1869.js +30 -35
- package/server.js +308 -299
- package/smtp_client.js +244 -228
- package/test/.eslintrc.yaml +0 -1
- package/test/connection.js +127 -134
- package/test/endpoint.js +53 -47
- package/test/fixtures/line_socket.js +12 -12
- package/test/fixtures/util_hmailitem.js +89 -85
- package/test/host_pool.js +90 -92
- package/test/installation/plugins/base_plugin.js +2 -2
- package/test/installation/plugins/folder_plugin/index.js +2 -3
- package/test/installation/plugins/inherits.js +3 -3
- package/test/installation/plugins/load_first.js +2 -3
- package/test/installation/plugins/plugin.js +1 -3
- package/test/installation/plugins/tls.js +2 -4
- package/test/logger.js +135 -116
- package/test/outbound/hmail.js +49 -35
- package/test/outbound/index.js +118 -101
- package/test/outbound/qfile.js +51 -53
- package/test/outbound_bounce_net_errors.js +84 -69
- package/test/outbound_bounce_rfc3464.js +235 -165
- package/test/plugins/auth/auth_base.js +420 -279
- package/test/plugins/auth/auth_vpopmaild.js +38 -39
- package/test/plugins/queue/smtp_forward.js +126 -104
- package/test/plugins/rcpt_to.host_list_base.js +85 -67
- package/test/plugins/rcpt_to.in_host_list.js +159 -112
- package/test/plugins/status.js +71 -64
- package/test/plugins/tls.js +37 -34
- package/test/plugins.js +97 -92
- package/test/rfc1869.js +19 -26
- package/test/server.js +293 -272
- package/test/smtp_client.js +180 -176
- package/test/tls_socket.js +62 -66
- package/test/transaction.js +159 -160
- package/tls_socket.js +331 -333
- 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
|
|
16
|
-
const 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
|
|
20
|
-
const HMailItem
|
|
21
|
-
const obc
|
|
22
|
-
const outbound
|
|
23
|
-
const mock_sock
|
|
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()) {
|
|
54
|
-
|
|
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(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
{
|
|
99
|
+
{ from: 'remote', line: '220 testing-smtp' },
|
|
91
100
|
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
{
|
|
97
|
-
{
|
|
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
|
-
{
|
|
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
|
-
|
|
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(
|
|
119
|
-
|
|
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
|
-
{
|
|
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
|
-
{
|
|
131
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
154
|
-
|
|
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
|
-
{
|
|
182
|
+
{ from: 'remote', line: '220 testing-smtp' },
|
|
159
183
|
|
|
160
|
-
{
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
{
|
|
165
|
-
{
|
|
192
|
+
{ from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
|
|
193
|
+
{ from: 'remote', line: '250 2.1.0 Ok' },
|
|
166
194
|
|
|
167
|
-
{
|
|
168
|
-
{
|
|
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
|
-
{
|
|
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
|
-
|
|
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(
|
|
189
|
-
|
|
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
|
-
{
|
|
226
|
+
{ from: 'remote', line: '220 testing-smtp' },
|
|
194
227
|
|
|
195
|
-
{
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
{
|
|
200
|
-
{
|
|
236
|
+
{ from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
|
|
237
|
+
{ from: 'remote', line: '250 2.1.0 Ok' },
|
|
201
238
|
|
|
202
|
-
{
|
|
203
|
-
{
|
|
239
|
+
{ from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
|
|
240
|
+
{ from: 'remote', line: '250 2.1.5 Ok' },
|
|
204
241
|
|
|
205
|
-
{
|
|
242
|
+
{ from: 'haraka', test: 'DATA' },
|
|
206
243
|
// haraka will send us more lines
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
244
|
+
{
|
|
245
|
+
from: 'remote',
|
|
246
|
+
line: '450 4.6.0 Currently I do not like ascii art cats.',
|
|
247
|
+
},
|
|
211
248
|
|
|
212
|
-
|
|
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
|
-
|
|
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(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
assert.ok(
|
|
232
|
-
|
|
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
|
-
{
|
|
285
|
+
{ from: 'remote', line: '220 testing-smtp' },
|
|
237
286
|
|
|
238
|
-
{
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
{
|
|
243
|
-
{
|
|
295
|
+
{ from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
|
|
296
|
+
{ from: 'remote', line: '250 2.1.0 Ok' },
|
|
244
297
|
|
|
245
|
-
{
|
|
246
|
-
{
|
|
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
|
-
{
|
|
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
|
-
|
|
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(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
{
|
|
337
|
+
{ from: 'remote', line: '220 testing-smtp' },
|
|
274
338
|
|
|
275
|
-
{
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
{
|
|
280
|
-
{
|
|
347
|
+
{ from: 'haraka', test: 'MAIL FROM:<sender@domain>' },
|
|
348
|
+
{ from: 'remote', line: '250 2.1.0 Ok' },
|
|
281
349
|
|
|
282
|
-
{
|
|
283
|
-
{
|
|
350
|
+
{ from: 'haraka', test: 'RCPT TO:<recipient@domain>' },
|
|
351
|
+
{ from: 'remote', line: '250 2.1.5 Ok' },
|
|
284
352
|
|
|
285
|
-
{
|
|
353
|
+
{ from: 'haraka', test: 'DATA' },
|
|
286
354
|
// haraka will send us more lines
|
|
287
|
-
{
|
|
355
|
+
{
|
|
356
|
+
from: 'remote',
|
|
357
|
+
line: '550 5.6.0 I never did and will like ascii art cats.',
|
|
358
|
+
},
|
|
288
359
|
|
|
289
|
-
{
|
|
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
|
-
|