diff --git a/client/src/Pages/Settings/SettingsEmail.jsx b/client/src/Pages/Settings/SettingsEmail.jsx
index 88f8f98c1..e7ae88154 100644
--- a/client/src/Pages/Settings/SettingsEmail.jsx
+++ b/client/src/Pages/Settings/SettingsEmail.jsx
@@ -12,6 +12,7 @@ import { useTranslation } from "react-i18next";
import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments";
import { useSendTestEmail } from "../../Hooks/useSendTestEmail";
import { createToast } from "../../Utils/toastUtils";
+import { Switch } from "@mui/material";
const SettingsEmail = ({
isAdmin,
@@ -25,6 +26,21 @@ const SettingsEmail = ({
const { t } = useTranslation();
const theme = useTheme();
+ // Destructure settings with default values
+ const {
+ systemEmailHost = "",
+ systemEmailPort = "",
+ systemEmailSecure = false,
+ systemEmailPool = false,
+ systemEmailUser = "",
+ systemEmailAddress = "",
+ systemEmailPassword = "",
+ systemEmailTLSServername = "",
+ systemEmailConnectionHost = "localhost",
+ systemEmailIgnoreTLS = false,
+ systemEmailRequireTLS = false,
+ systemEmailRejectUnauthorized = true,
+ } = settingsData?.settings || {};
// Local state
const [password, setPassword] = useState("");
const [hasBeenReset, setHasBeenReset] = useState(false);
@@ -47,18 +63,32 @@ const SettingsEmail = ({
const handleSendTestEmail = () => {
// Collect current form values
const emailConfig = {
- systemEmailHost: settingsData?.settings?.systemEmailHost,
- systemEmailPort: settingsData?.settings?.systemEmailPort,
- systemEmailUser: settingsData?.settings?.systemEmailUser,
- systemEmailAddress: settingsData?.settings?.systemEmailAddress,
- systemEmailPassword: password || settingsData?.settings?.systemEmailPassword,
- systemEmailConnectionHost: settingsData?.settings?.systemEmailConnectionHost,
+ systemEmailHost,
+ systemEmailPort,
+ systemEmailSecure,
+ systemEmailPool,
+ systemEmailUser,
+ systemEmailAddress,
+ systemEmailPassword: password || systemEmailPassword,
+ systemEmailTLSServername,
+ systemEmailConnectionHost,
+ systemEmailIgnoreTLS,
+ systemEmailRequireTLS,
+ systemEmailRejectUnauthorized,
};
// Basic validation
- if (!emailConfig.systemEmailHost || !emailConfig.systemEmailPort) {
+ if (
+ !emailConfig.systemEmailHost ||
+ !emailConfig.systemEmailPort ||
+ !emailConfig.systemEmailAddress ||
+ !emailConfig.systemEmailPassword
+ ) {
createToast({
- body: t("settingsEmailRequiredFields", "Email host and port are required"),
+ body: t(
+ "settingsEmailRequiredFields",
+ "Email address, host, port and password are required"
+ ),
variant: "error",
});
return;
@@ -90,7 +120,7 @@ const SettingsEmail = ({
@@ -100,7 +130,7 @@ const SettingsEmail = ({
name="systemEmailPort"
placeholder="425"
type="number"
- value={settingsData?.settings?.systemEmailPort ?? ""}
+ value={systemEmailPort}
onChange={handleChange}
/>
@@ -109,7 +139,7 @@ const SettingsEmail = ({
@@ -118,7 +148,7 @@ const SettingsEmail = ({
@@ -156,23 +186,75 @@ const SettingsEmail = ({
)}
- {t("settingsEmailConnectionHost")}
+ {t("settingsEmailTLSServername")}
-
+ {t("settingsEmailConnectionHost")}
+
+
+
+ {t("settingsEmailSecure")}
+
+ {t("settingsEmailPool")}
+
+ {t("settingsEmailIgnoreTLS")}
+
+ {t("settingsEmailRequireTLS")}
+
+ {t("settingsEmailRejectUnauthorized")}
+
+
+
+ {systemEmailHost &&
+ systemEmailPort &&
+ systemEmailAddress &&
+ systemEmailPassword && (
+
+ )}
diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx
index a3cd88fca..804ca48c7 100644
--- a/client/src/Pages/Settings/index.jsx
+++ b/client/src/Pages/Settings/index.jsx
@@ -56,17 +56,27 @@ const Settings = () => {
// Handlers
const handleChange = async (e) => {
- const { name, value } = e.target;
+ const { name, value, checked } = e.target;
// Special case for showURL until handled properly in the backend
if (name === "showURL") {
dispatch(setShowURL(value));
return;
}
+ let newValue;
+ if (
+ name === "systemEmailIgnoreTLS" ||
+ name === "systemEmailRequireTLS" ||
+ name === "systemEmailRejectUnauthorized" ||
+ name === "systemEmailSecure" ||
+ name === "systemEmailPool"
+ ) {
+ newValue = checked;
+ }
// Build next state early
const newSettingsData = {
...settingsData,
- settings: { ...settingsData.settings, [name]: value },
+ settings: { ...settingsData.settings, [name]: newValue ?? value },
};
// Validate
diff --git a/client/src/Utils/NetworkService.js b/client/src/Utils/NetworkService.js
index ecde44a9e..3059462f9 100644
--- a/client/src/Utils/NetworkService.js
+++ b/client/src/Utils/NetworkService.js
@@ -973,10 +973,12 @@ class NetworkService {
systemEmailPort: emailConfig.systemEmailPort,
systemEmailAddress: emailConfig.systemEmailAddress,
systemEmailPassword: emailConfig.systemEmailPassword,
- // Only include these if they are present
- ...(emailConfig.systemEmailConnectionHost && {
- systemEmailConnectionHost: emailConfig.systemEmailConnectionHost,
- }),
+ systemEmailSecure: emailConfig.systemEmailSecure,
+ systemEmailPool: emailConfig.systemEmailPool,
+ systemEmailIgnoreTLS: emailConfig.systemEmailIgnoreTLS,
+ systemEmailRequireTLS: emailConfig.systemEmailRequireTLS,
+ systemEmailRejectUnauthorized: emailConfig.systemEmailRejectUnauthorized,
+ systemEmailTLSServername: emailConfig.systemEmailTLSServername,
...(emailConfig.systemEmailUser && {
systemEmailUser: emailConfig.systemEmailUser,
}),
diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js
index 043e88f50..f1811a124 100644
--- a/client/src/Validation/validation.js
+++ b/client/src/Validation/validation.js
@@ -290,10 +290,16 @@ const settingsValidation = joi.object({
timezone: joi.string().allow("").optional(),
systemEmailHost: joi.string().allow(""),
systemEmailPort: joi.number().allow(null, ""),
+ systemEmailSecure: joi.boolean().optional(),
+ systemEmailPool: joi.boolean().optional(),
systemEmailAddress: joi.string().allow(""),
systemEmailPassword: joi.string().allow(""),
systemEmailUser: joi.string().allow(""),
- systemEmailConnectionHost: joi.string().allow(""),
+ systemEmailConnectionHost: joi.string().allow("").optional(),
+ systemEmailTLSServername: joi.string().allow(""),
+ systemEmailIgnoreTLS: joi.boolean(),
+ systemEmailRequireTLS: joi.boolean(),
+ systemEmailRejectUnauthorized: joi.boolean(),
});
const dayjsValidator = (value, helpers) => {
diff --git a/client/src/locales/en.json b/client/src/locales/en.json
index bc6c8bbb9..2791dd3e7 100644
--- a/client/src/locales/en.json
+++ b/client/src/locales/en.json
@@ -681,12 +681,18 @@
},
"settingsEmail": "Email",
"settingsEmailDescription": "Configure the email settings for your system. This is used to send notifications and alerts.",
- "settingsEmailHost": "Email host - Hostname or IP address of the SMTP server",
+ "settingsEmailHost": "Email host - Hostname or IP address to connect to",
"settingsEmailPort": "Email port - Port to connect to",
"settingsEmailAddress": "Email address - Used for authentication",
"settingsEmailPassword": "Email password - Password for authentication",
"settingsEmailUser": "Email user - Username for authentication, overrides email address if specified",
"settingsEmailFieldResetLabel": "Password is set. Click Reset to change it.",
+ "settingsEmailTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP",
+ "settingsEmailIgnoreTLS": "Ignore TLS - Disable STARTTLS",
+ "settingsEmailRequireTLS": "Require TLS - Force STARTTLS",
+ "settingsEmailRejectUnauthorized": "Reject Unauthorized",
+ "settingsEmailSecure": "Secure - Use SSL",
+ "settingsEmailPool": "Pool - Enable connection pooling",
"state": "State",
"statusBreadCrumbsStatusPages": "Status Pages",
"statusBreadCrumbsDetails": "Details",
@@ -716,7 +722,7 @@
"settingsTestEmailFailed": "Failed to send test email",
"settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}",
"settingsTestEmailUnknownError": "Unknown error",
- "settingsEmailRequiredFields": "Email host and port are required",
+ "settingsEmailRequiredFields": "Email address, host, port and password are required",
"statusMsg": {
"paused": "Monitoring is paused.",
"up": "Your site is up.",
diff --git a/server/controllers/settingsController.js b/server/controllers/settingsController.js
index 58e8ce9f4..d1010c093 100755
--- a/server/controllers/settingsController.js
+++ b/server/controllers/settingsController.js
@@ -74,6 +74,12 @@ class SettingsController {
systemEmailPassword,
systemEmailUser,
systemEmailConnectionHost,
+ systemEmailSecure,
+ systemEmailPool,
+ systemEmailIgnoreTLS,
+ systemEmailRequireTLS,
+ systemEmailRejectUnauthorized,
+ systemEmailTLSServername,
} = req.body;
const subject = this.stringService.testEmailSubject;
@@ -91,6 +97,12 @@ class SettingsController {
systemEmailAddress,
systemEmailPassword,
systemEmailConnectionHost,
+ systemEmailSecure,
+ systemEmailPool,
+ systemEmailIgnoreTLS,
+ systemEmailRequireTLS,
+ systemEmailRejectUnauthorized,
+ systemEmailTLSServername,
}
);
diff --git a/server/db/models/AppSettings.js b/server/db/models/AppSettings.js
index c47de06fa..cd63118e9 100755
--- a/server/db/models/AppSettings.js
+++ b/server/db/models/AppSettings.js
@@ -32,6 +32,29 @@ const AppSettingsSchema = mongoose.Schema(
type: String,
default: "localhost",
},
+ systemEmailTLSServername: {
+ type: String,
+ },
+ systemEmailSecure: {
+ type: Boolean,
+ default: false,
+ },
+ systemEmailPool: {
+ type: Boolean,
+ default: false,
+ },
+ systemEmailIgnoreTLS: {
+ type: Boolean,
+ default: false,
+ },
+ systemEmailRequireTLS: {
+ type: Boolean,
+ default: false,
+ },
+ systemEmailRejectUnauthorized: {
+ type: Boolean,
+ default: true,
+ },
singleton: {
type: Boolean,
required: true,
diff --git a/server/service/emailService.js b/server/service/emailService.js
index 035cc6505..09123ef93 100755
--- a/server/service/emailService.js
+++ b/server/service/emailService.js
@@ -101,39 +101,37 @@ class EmailService {
const {
systemEmailHost,
systemEmailPort,
+ systemEmailSecure,
+ systemEmailPool,
systemEmailUser,
systemEmailAddress,
systemEmailPassword,
systemEmailConnectionHost,
+ systemEmailTLSServername,
+ systemEmailIgnoreTLS,
+ systemEmailRequireTLS,
+ systemEmailRejectUnauthorized,
} = config;
- const baseEmailConfig = {
+ const emailConfig = {
host: systemEmailHost,
- port: systemEmailPort,
- secure: true,
+ port: Number(systemEmailPort),
+ secure: systemEmailSecure,
auth: {
user: systemEmailUser || systemEmailAddress,
pass: systemEmailPassword,
},
+ name: systemEmailConnectionHost || "localhost",
connectionTimeout: 5000,
+ pool: systemEmailPool,
+ tls: {
+ rejectUnauthorized: systemEmailRejectUnauthorized,
+ ignoreTLS: systemEmailIgnoreTLS,
+ requireTLS: systemEmailRequireTLS,
+ servername: systemEmailTLSServername,
+ },
};
- const isSmtps = Number(systemEmailPort) === 465;
-
- const emailConfig = !isSmtps
- ? {
- ...baseEmailConfig,
- name: systemEmailConnectionHost || "localhost",
- secure: false,
- pool: true,
- tls: { rejectUnauthorized: false },
- }
- : baseEmailConfig;
-
- if (!isSmtps) {
- delete emailConfig.auth;
- }
-
this.transporter = this.nodemailer.createTransport(emailConfig);
const buildHtml = async (template, context) => {
diff --git a/server/validation/joi.js b/server/validation/joi.js
index 622cb9148..5eb24e758 100755
--- a/server/validation/joi.js
+++ b/server/validation/joi.js
@@ -410,7 +410,13 @@ const updateAppSettingsBodyValidation = joi.object({
systemEmailAddress: joi.string().allow(""),
systemEmailPassword: joi.string().allow(""),
systemEmailUser: joi.string().allow(""),
- systemEmailConnectionHost: joi.string().allow(""),
+ systemEmailConnectionHost: joi.string().allow("").optional(),
+ systemEmailTLSServername: joi.string().allow("").optional(),
+ systemEmailSecure: joi.boolean(),
+ systemEmailPool: joi.boolean(),
+ systemEmailIgnoreTLS: joi.boolean(),
+ systemEmailRequireTLS: joi.boolean(),
+ systemEmailRejectUnauthorized: joi.boolean(),
});
//****************************************
@@ -612,10 +618,16 @@ const sendTestEmailBodyValidation = joi.object({
to: joi.string().required(),
systemEmailHost: joi.string(),
systemEmailPort: joi.number(),
+ systemEmailSecure: joi.boolean(),
+ systemEmailPool: joi.boolean(),
systemEmailAddress: joi.string(),
systemEmailPassword: joi.string(),
systemEmailUser: joi.string(),
- systemEmailConnectionHost: joi.string(),
+ systemEmailConnectionHost: joi.string().allow("").optional(),
+ systemEmailIgnoreTLS: joi.boolean(),
+ systemEmailRequireTLS: joi.boolean(),
+ systemEmailRejectUnauthorized: joi.boolean(),
+ systemEmailTLSServername: joi.string().allow("").optional(),
});
export {