feat: reload SMTP server TLS certificates on change (#209)
This commit is contained in:
@@ -2,7 +2,7 @@ import { SMTPServer, SMTPServerOptions, SMTPServerSession } from "smtp-server";
|
|||||||
import { Readable } from "stream";
|
import { Readable } from "stream";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { simpleParser } from "mailparser";
|
import { simpleParser } from "mailparser";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync, watch, FSWatcher } from "fs";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
@@ -53,10 +53,19 @@ async function sendEmailToUnsend(emailData: any, apiKey: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadCertificates(): { key?: Buffer; cert?: Buffer } {
|
||||||
|
return {
|
||||||
|
key: SSL_KEY_PATH ? readFileSync(SSL_KEY_PATH) : undefined,
|
||||||
|
cert: SSL_CERT_PATH ? readFileSync(SSL_CERT_PATH) : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialCerts = loadCertificates();
|
||||||
|
|
||||||
const serverOptions: SMTPServerOptions = {
|
const serverOptions: SMTPServerOptions = {
|
||||||
secure: false,
|
secure: false,
|
||||||
key: SSL_KEY_PATH ? readFileSync(SSL_KEY_PATH) : undefined,
|
key: initialCerts.key,
|
||||||
cert: SSL_CERT_PATH ? readFileSync(SSL_CERT_PATH) : undefined,
|
cert: initialCerts.cert,
|
||||||
onData(
|
onData(
|
||||||
stream: Readable,
|
stream: Readable,
|
||||||
session: SMTPServerSession,
|
session: SMTPServerSession,
|
||||||
@@ -109,6 +118,9 @@ const serverOptions: SMTPServerOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function startServers() {
|
function startServers() {
|
||||||
|
const servers: SMTPServer[] = [];
|
||||||
|
const watchers: FSWatcher[] = [];
|
||||||
|
|
||||||
if (SSL_KEY_PATH && SSL_CERT_PATH) {
|
if (SSL_KEY_PATH && SSL_CERT_PATH) {
|
||||||
// Implicit SSL/TLS for ports 465 and 2465
|
// Implicit SSL/TLS for ports 465 and 2465
|
||||||
[465, 2465].forEach((port) => {
|
[465, 2465].forEach((port) => {
|
||||||
@@ -123,6 +135,8 @@ function startServers() {
|
|||||||
server.on("error", (err) => {
|
server.on("error", (err) => {
|
||||||
console.error(`Error occurred on port ${port}:`, err);
|
console.error(`Error occurred on port ${port}:`, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
servers.push(server);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +151,39 @@ function startServers() {
|
|||||||
server.on("error", (err) => {
|
server.on("error", (err) => {
|
||||||
console.error(`Error occurred on port ${port}:`, err);
|
console.error(`Error occurred on port ${port}:`, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
servers.push(server);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (SSL_KEY_PATH && SSL_CERT_PATH) {
|
||||||
|
const reloadCertificates = () => {
|
||||||
|
try {
|
||||||
|
const { key, cert } = loadCertificates();
|
||||||
|
if (key && cert) {
|
||||||
|
servers.forEach((srv) => srv.updateSecureContext({ key, cert }));
|
||||||
|
console.log("TLS certificates reloaded");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to reload TLS certificates", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[SSL_KEY_PATH, SSL_CERT_PATH].forEach((file) => {
|
||||||
|
watchers.push(watch(file, { persistent: false }, reloadCertificates));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { servers, watchers };
|
||||||
}
|
}
|
||||||
|
|
||||||
startServers();
|
const { servers, watchers } = startServers();
|
||||||
|
|
||||||
|
function shutdown() {
|
||||||
|
console.log("Shutting down SMTP server...");
|
||||||
|
watchers.forEach((w) => w.close());
|
||||||
|
servers.forEach((s) => s.close());
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
["SIGINT", "SIGTERM", "SIGQUIT"].forEach((signal) => {
|
||||||
|
process.on(signal, shutdown);
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user