-
Notifications
You must be signed in to change notification settings - Fork 127
/
smtp-server.js
122 lines (102 loc) · 3.76 KB
/
smtp-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
120
121
122
/**
* Copyright (c) Forward Email LLC
* SPDX-License-Identifier: BUSL-1.1
*/
const fs = require('node:fs');
const RateLimiter = require('async-ratelimiter');
const bytes = require('@forwardemail/bytes');
const ms = require('ms');
const pify = require('pify');
const { SMTPServer } = require('smtp-server');
const config = require('#config');
const createTangerine = require('#helpers/create-tangerine');
const env = require('#config/env');
const logger = require('#helpers/logger');
const onAuth = require('#helpers/on-auth');
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);
class SMTP {
constructor(
options = {},
secure = env.SMTP_PORT === 465 || env.SMTP_PORT === 2465
) {
this.client = options.client;
this.resolver = createTangerine(this.client, logger);
//
// NOTE: hard-coded values for now (switch to env later)
// (current limit is 10 failed login attempts per hour)
//
this.rateLimiter = new RateLimiter({
db: this.client,
max: config.smtpLimitMessages,
duration: config.smtpLimitDuration,
namespace: config.smtpLimitNamespace
});
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({
// <https://github.com/nodemailer/smtp-server/pull/192>
authRequiredMessage: config.authRequiredMessage,
//
// 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),
onAuth: onAuth.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: secure ? ['STARTTLS'] : [],
secure,
needsUpgrade: secure,
authMethods: ['PLAIN', 'LOGIN'], // XOAUTH2, CRAM-MD5
// just in case smtp-server changes default and patch semver bump (unlikely but safeguard)
allowInsecureAuth:
config.env === 'production' ? false : env.SMTP_ALLOW_INSECURE_AUTH,
authOptional: 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.SMTP_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 = SMTP;