• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

haraka / Haraka / 26860023436

03 Jun 2026 02:27AM UTC coverage: 72.488% (-0.006%) from 72.494%
26860023436

push

github

web-flow
dep(eslint): update @haraka/eslint-config to v3, fix surfaced warnings (#3586)

1721 of 2268 branches covered (75.88%)

33 of 45 new or added lines in 15 files covered. (73.33%)

19 existing lines in 3 files now uncovered.

7807 of 10770 relevant lines covered (72.49%)

25.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.96
/plugins/queue/smtp_proxy.js
1
'use strict'
10✔
2
// Proxy to an SMTP server
10✔
3
// Opens the connection to the ongoing SMTP server at MAIL FROM time
10✔
4
// and passes back any errors seen on the ongoing server to the
10✔
5
// originating server.
10✔
6

10✔
7
const smtp_client_mod = require('../../smtp_client')
10✔
8
const tls_socket = require('../../tls_socket')
10✔
9

10✔
10
exports.register = function () {
10✔
11
    this.load_smtp_proxy_ini()
×
12

×
13
    if (this.cfg.main.enable_outbound) {
×
14
        this.register_hook('queue_outbound', 'hook_queue')
×
15
    }
×
16
}
×
17

×
18
exports.load_smtp_proxy_ini = function () {
10✔
19
    this.cfg = this.config.get(
13✔
20
        'smtp_proxy.ini',
13✔
21
        {
13✔
22
            booleans: [
13✔
23
                '-main.enable_tls',
13✔
24
                '+main.enable_outbound',
13✔
25
                '+tls.requestCert',
13✔
26
                '+tls.honorCipherOrder',
13✔
27
                '-tls.rejectUnauthorized',
13✔
28
            ],
13✔
29
        },
13✔
30
        () => {
13✔
31
            this.load_smtp_proxy_ini()
13✔
32
        },
×
33
    )
×
34

×
35
    // Build backend TLS options from tls.ini [main] + this plugin's [tls] section.
13✔
36
    // Re-derived on every (re)load so SIGHUP picks up edits.
13✔
37
    this.tls_options = tls_socket.load_plugin_tls_options(this.cfg.tls || {})
13✔
38

13✔
39
    if (this.cfg.main.enable_outbound) {
13!
40
        this.lognotice('outbound enabled, will default to disabled in Haraka v3 (see #1472)')
13✔
41
    }
13✔
42
}
13✔
43

13✔
44
exports.hook_mail = function (next, connection) {
10✔
45
    const c = this.cfg.main
×
46
    connection.loginfo(
×
47
        this,
×
48
        `forwarding to ${c.forwarding_host_pool ? 'configured forwarding_host_pool' : `${c.host}:${c.port}`}`,
×
49
    )
×
50
    smtp_client_mod.get_client_plugin(this, connection, c, (err, smtp_client) => {
×
51
        connection.notes.smtp_client = smtp_client
×
52
        smtp_client.next = next
×
53

×
54
        smtp_client.on('mail', smtp_client.call_next)
×
55
        smtp_client.on('rcpt', smtp_client.call_next)
×
56
        smtp_client.on('data', smtp_client.call_next)
×
57

×
58
        smtp_client.on('dot', () => {
×
59
            if (smtp_client.is_dead_sender(this, connection)) {
×
60
                delete connection.notes.smtp_client
×
61
                return
×
62
            }
×
63

×
64
            smtp_client.call_next(OK, smtp_client.response)
×
65
            smtp_client.release()
×
66
            delete connection.notes.smtp_client
×
67
        })
×
68

×
69
        smtp_client.on('error', () => {
×
70
            delete connection.notes.smtp_client
×
71
        })
×
72

×
NEW
73
        smtp_client.on('bad_code', (code) => {
×
74
            smtp_client.call_next(code.match(/^4/) ? DENYSOFT : DENY, smtp_client.response.slice())
×
75

×
76
            if (smtp_client.command !== 'rcpt') {
×
77
                // errors are OK for rcpt, but nothing else
×
78
                // this can also happen if the destination server
×
79
                // times out, but that is okay.
×
80
                connection.loginfo(this, 'message denied, proxying failed')
×
81
                smtp_client.release()
×
82
                delete connection.notes.smtp_client
×
83
            }
×
84
        })
×
85
    })
×
86
}
×
87

×
88
exports.hook_rcpt_ok = (next, connection, recipient) => {
10✔
89
    const { smtp_client } = connection.notes
×
90
    if (!smtp_client) return next()
×
91
    if (smtp_client.is_dead_sender(this, connection)) {
×
92
        delete connection.notes.smtp_client
×
93
        return
×
94
    }
×
95
    smtp_client.next = next
×
96
    smtp_client.send_command('RCPT', `TO:${recipient.format(!smtp_client.smtputf8)}`)
×
97
}
×
98

×
99
exports.hook_data = (next, connection) => {
10✔
100
    const { smtp_client } = connection.notes
×
101
    if (!smtp_client) return next()
×
102

×
103
    if (smtp_client.is_dead_sender(this, connection)) {
×
104
        delete connection.notes.smtp_client
×
105
        return
×
106
    }
×
107
    smtp_client.next = next
×
108
    smtp_client.send_command('DATA')
×
109
}
×
110

×
111
exports.hook_queue = function (next, connection) {
10✔
112
    if (!connection?.transaction || !connection?.notes) return next()
2✔
113

1✔
114
    const { smtp_client } = connection.notes
1✔
115
    if (!smtp_client) return next()
1✔
116

1✔
117
    if (smtp_client.is_dead_sender(this, connection)) {
2!
118
        delete connection.notes.smtp_client
×
119
        return
×
120
    }
×
121
    smtp_client.next = next
×
122
    smtp_client.start_data(connection.transaction.message_stream)
×
123
}
×
124

×
125
exports.hook_rset = (next, connection) => {
10✔
126
    const { smtp_client } = connection.notes
3✔
127
    if (!smtp_client) return next()
3✔
128
    smtp_client.release()
3✔
129
    delete connection.notes.smtp_client
1✔
130
    next()
1✔
131
}
1✔
132

1✔
133
exports.hook_quit = exports.hook_rset
10✔
134

10✔
135
exports.hook_disconnect = (next, connection) => {
10✔
136
    const { smtp_client } = connection.notes
2✔
137
    if (!smtp_client) return next()
2✔
138
    smtp_client.release()
1✔
139
    delete connection.notes.smtp_client
1✔
140
    smtp_client.call_next()
1✔
141
    next()
1✔
142
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc