-
Notifications
You must be signed in to change notification settings - Fork 122
/
mx-server.js
119 lines (99 loc) · 3.95 KB
/
mx-server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* Copyright (c) Forward Email LLC
* SPDX-License-Identifier: BUSL-1.1
*/
const fs = require('node:fs');
const bytes = require('@forwardemail/bytes');
const ms = require('ms');
const pify = require('pify');
const { SMTPServer } = require('smtp-server');
const RetryClient = require('#helpers/retry-client');
const config = require('#config');
const createMtaStsCache = require('#helpers/create-mta-sts-cache');
const createTangerine = require('#helpers/create-tangerine');
const env = require('#config/env');
const logger = require('#helpers/logger');
const onClose = require('#helpers/on-close');
const onConnect = require('#helpers/on-connect');
const onData = require('#helpers/on-data');
const onMailFrom = require('#helpers/on-mail-from');
const onRcptTo = require('#helpers/on-rcpt-to');
const MAX_BYTES = bytes(env.SMTP_MESSAGE_MAX_SIZE);
// TODO: remove try/catch for isDenylisted/isSilent/isBackscatter
// and replace with catch (err) for onData to detect and store counter
// based off err.name detected or if it was combined then err.errors
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
// TODO: we probably should disable spam scanner
class MX {
constructor(options = {}) {
this.client = options.client;
this.wsp = options.wsp;
this.resolver = createTangerine(this.client, logger);
this.cache = createMtaStsCache(this.client);
// NOTE: this is useful for tests since we can pass `apiEndpoint` in test options
// TODO: remove API and replace with MongoDB calls (and then we can remove API from MX tests)
this.apiClient = new RetryClient(options.apiEndpoint || config.urls.api);
// TODO: rate limiting (?)
this.logger = logger;
// setup our smtp server which listens for incoming email
// TODO: <https://github.com/nodemailer/smtp-server/issues/177>
this.server = new SMTPServer({
//
// most of these options mirror the FE forwarding server options
//
size: MAX_BYTES,
onData: onData.bind(this),
onConnect: onConnect.bind(this),
onClose: onClose.bind(this),
onMailFrom: onMailFrom.bind(this),
onRcptTo: onRcptTo.bind(this),
// NOTE: we don't need to set a value for maxClients
// since we have rate limiting enabled by IP
// maxClients: Infinity, // default is Infinity
// allow 3m to process bulk RCPT TO
socketTimeout: config.socketTimeout,
// default closeTimeout is 30s
closeTimeout: ms('30s'),
// <https://github.com/nodemailer/smtp-server/issues/177>
disableReverseLookup: true,
logger: this.logger,
disabledCommands: ['AUTH'],
secure: false,
needsUpgrade: false,
// <https://github.com/nodemailer/wildduck/issues/563>
// hide8BITMIME: true,
// keys
...(config.env === 'production'
? {
key: fs.readFileSync(env.WEB_SSL_KEY_PATH),
cert: fs.readFileSync(env.WEB_SSL_CERT_PATH),
ca: fs.readFileSync(env.WEB_SSL_CA_PATH)
}
: {})
});
// override logger
this.server.logger = this.logger;
// kind of hacky but I filed a GH issue
// <https://github.com/nodemailer/smtp-server/issues/135>
this.server.address = this.server.server.address.bind(this.server.server);
this.server.on('error', (err) => {
logger.error(err);
});
this.listen = this.listen.bind(this);
this.close = this.close.bind(this);
}
async listen(port = env.MX_PORT, host = '::', ...args) {
await pify(this.server.listen).bind(this.server)(port, host, ...args);
}
async close() {
await pify(this.server.close).bind(this.server);
}
}
module.exports = MX;