diff --git a/litellm/proxy/config_resolvers/alerting.py b/litellm/proxy/config_resolvers/alerting.py
index 3704ec09355..292d043e99c 100644
--- a/litellm/proxy/config_resolvers/alerting.py
+++ b/litellm/proxy/config_resolvers/alerting.py
@@ -12,6 +12,7 @@ EMAIL_DESCRIPTORS: tuple[FieldDescriptor, ...] = (
FieldDescriptor("SMTP_HOST", "SMTP_HOST", "SMTP_HOST"),
FieldDescriptor("SMTP_PORT", "SMTP_PORT", "SMTP_PORT", default="587"),
FieldDescriptor("SMTP_TLS", "SMTP_TLS", "SMTP_TLS", default="True"),
+ FieldDescriptor("SMTP_USE_SSL", "SMTP_USE_SSL", "SMTP_USE_SSL", default="False"),
FieldDescriptor("SMTP_USERNAME", "SMTP_USERNAME", "SMTP_USERNAME", is_secret=True),
FieldDescriptor("SMTP_PASSWORD", "SMTP_PASSWORD", "SMTP_PASSWORD", is_secret=True),
FieldDescriptor("SMTP_SENDER_EMAIL", "SMTP_SENDER_EMAIL", "SMTP_SENDER_EMAIL"),
diff --git a/tests/test_litellm/proxy/test_proxy_server.py b/tests/test_litellm/proxy/test_proxy_server.py
index ab64224fdc3..7beff719468 100644
--- a/tests/test_litellm/proxy/test_proxy_server.py
+++ b/tests/test_litellm/proxy/test_proxy_server.py
@@ -1218,6 +1218,7 @@ def test_get_config_returns_email_settings_set_only_in_process_env(monkeypatch):
monkeypatch.setenv("SMTP_HOST", "smtp.env-host.com")
monkeypatch.setenv("SMTP_PORT", "2525")
monkeypatch.setenv("SMTP_TLS", "False")
+ monkeypatch.setenv("SMTP_USE_SSL", "True")
monkeypatch.setenv("SMTP_USERNAME", "env-user")
monkeypatch.setenv("SMTP_PASSWORD", smtp_password)
monkeypatch.setenv("SMTP_SENDER_EMAIL", "alerts@env-host.com")
@@ -1236,6 +1237,7 @@ def test_get_config_returns_email_settings_set_only_in_process_env(monkeypatch):
assert variables["SMTP_HOST"] == "smtp.env-host.com"
assert variables["SMTP_PORT"] == "2525"
assert variables["SMTP_TLS"] == "False"
+ assert variables["SMTP_USE_SSL"] == "True"
assert variables["SMTP_USERNAME"] == "env-user"
assert variables["SMTP_SENDER_EMAIL"] == "alerts@env-host.com"
assert variables["TEST_EMAIL_ADDRESS"] == "admin@env-host.com"
@@ -1269,7 +1271,15 @@ def test_get_config_email_settings_prefer_stored_over_process_env(monkeypatch):
def test_get_config_email_settings_absent_everywhere_stay_none(monkeypatch):
"""A field set in neither source is reported unset rather than invented."""
- for var in ("SMTP_HOST", "SMTP_PORT", "SMTP_TLS", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_SENDER_EMAIL"):
+ for var in (
+ "SMTP_HOST",
+ "SMTP_PORT",
+ "SMTP_TLS",
+ "SMTP_USE_SSL",
+ "SMTP_USERNAME",
+ "SMTP_PASSWORD",
+ "SMTP_SENDER_EMAIL",
+ ):
monkeypatch.delenv(var, raising=False)
variables = _get_email_alert_variables(
diff --git a/ui/litellm-dashboard/src/components/email_settings.test.tsx b/ui/litellm-dashboard/src/components/email_settings.test.tsx
index bd09ca0abc4..1f826857b48 100644
--- a/ui/litellm-dashboard/src/components/email_settings.test.tsx
+++ b/ui/litellm-dashboard/src/components/email_settings.test.tsx
@@ -22,7 +22,12 @@ const alerts = [
variables: {
SMTP_HOST: "smtp.example.com",
SMTP_PORT: "587",
+ SMTP_TLS: "True",
+ SMTP_USE_SSL: "False",
+ SMTP_USERNAME: "smtp-user",
SMTP_PASSWORD: "********",
+ SMTP_SENDER_EMAIL: "alerts@example.com",
+ TEST_EMAIL_ADDRESS: "admin@example.com",
EMAIL_LOGO_URL: "https://example.com/logo.png",
},
},
@@ -53,7 +58,15 @@ describe("EmailSettings", () => {
expect(inputNamed("SMTP_HOST")).toHaveValue("smtp.example.com");
expect(inputNamed("SMTP_PORT")).toHaveValue("587");
+ expect(inputNamed("SMTP_PORT")).toHaveAttribute("type", "number");
+ expect(inputNamed("SMTP_HOST")).toHaveAttribute("type", "text");
+ expect(inputNamed("SMTP_TLS")).toHaveAttribute("type", "text");
+ expect(inputNamed("SMTP_USE_SSL")).toHaveAttribute("type", "text");
+ expect(inputNamed("SMTP_USERNAME")).toHaveAttribute("type", "text");
expect(inputNamed("SMTP_PASSWORD")).toHaveValue("********");
+ expect(inputNamed("SMTP_SENDER_EMAIL")).toHaveAttribute("type", "text");
+ expect(inputNamed("TEST_EMAIL_ADDRESS")).toHaveAttribute("type", "text");
+ expect(inputNamed("EMAIL_LOGO_URL")).toHaveAttribute("type", "text");
expect(document.querySelector('input[name="SLACK_WEBHOOK_URL"]')).toBeNull();
});
@@ -63,6 +76,21 @@ describe("EmailSettings", () => {
expect(screen.getByText("SMTP_HOST")).toBeInTheDocument();
expect(screen.getByText(/Enter the SMTP host address/)).toBeInTheDocument();
expect(screen.getByText(/Enter the SMTP port number/)).toBeInTheDocument();
+ expect(screen.getByText(/Optional SMTP username/)).toBeInTheDocument();
+ expect(screen.getByText(/Optional SMTP password/)).toBeInTheDocument();
+ });
+
+ it("only requires the SMTP host and sender email", () => {
+ renderWithProviders();
+
+ expect(inputNamed("SMTP_HOST")).toBeRequired();
+ expect(inputNamed("SMTP_SENDER_EMAIL")).toBeRequired();
+ expect(inputNamed("SMTP_PORT")).not.toBeRequired();
+ expect(inputNamed("SMTP_TLS")).not.toBeRequired();
+ expect(inputNamed("SMTP_USE_SSL")).not.toBeRequired();
+ expect(inputNamed("SMTP_USERNAME")).not.toBeRequired();
+ expect(inputNamed("SMTP_PASSWORD")).not.toBeRequired();
+ expect(inputNamed("TEST_EMAIL_ADDRESS")).not.toBeRequired();
});
it("submits only the fields the admin actually edited", async () => {
diff --git a/ui/litellm-dashboard/src/components/email_settings.tsx b/ui/litellm-dashboard/src/components/email_settings.tsx
index 85fb4ce1ca3..0cfac8107ad 100644
--- a/ui/litellm-dashboard/src/components/email_settings.tsx
+++ b/ui/litellm-dashboard/src/components/email_settings.tsx
@@ -14,13 +14,22 @@ interface EmailSettingsProps {
const REQUIRED_MARKER = Required * ;
+const REQUIRED_FIELDS = new Set(["SMTP_HOST", "SMTP_SENDER_EMAIL"]);
+
+const FIELD_TYPES: Record = {
+ SMTP_PORT: "number",
+ SMTP_PASSWORD: "password",
+};
+
const FIELD_HELP: Record = {
SMTP_HOST: <>Enter the SMTP host address, e.g. `smtp.resend.com`{REQUIRED_MARKER}>,
- SMTP_PORT: <>Enter the SMTP port number, e.g. `587`{REQUIRED_MARKER}>,
- SMTP_USERNAME: <>Enter the SMTP username, e.g. `username`{REQUIRED_MARKER}>,
- SMTP_PASSWORD: REQUIRED_MARKER,
+ SMTP_PORT: <>Enter the SMTP port number, e.g. `587`>,
+ SMTP_TLS: <>Use STARTTLS for the SMTP connection. Defaults to `True`>,
+ SMTP_USE_SSL: <>Use implicit SSL for the SMTP connection. Defaults to `False`>,
+ SMTP_USERNAME: <>Optional SMTP username for authenticated servers>,
+ SMTP_PASSWORD: <>Optional SMTP password for authenticated servers>,
SMTP_SENDER_EMAIL: <>Enter the sender email address, e.g. `sender@berri.ai`{REQUIRED_MARKER}>,
- TEST_EMAIL_ADDRESS: <>Email Address to send `Test Email Alert` to. example: `info@berri.ai`{REQUIRED_MARKER}>,
+ TEST_EMAIL_ADDRESS: <>Optional address for the `Test Email Alert` action>,
EMAIL_LOGO_URL: <>(Optional) Customize the Logo that appears in the email, pass a url to your logo>,
EMAIL_SUPPORT_CONTACT: (
<>(Optional) Customize the support email address that appears in the email. Default is support@berri.ai>
@@ -115,8 +124,9 @@ const EmailSettings: React.FC = ({ accessToken, premiumUser,
)}