diff --git a/enterprise/frontend/src/metabase-enterprise/license/components/LicenseAndBillingSettings/LicenseAndBillingSettings.unit.spec.tsx b/enterprise/frontend/src/metabase-enterprise/license/components/LicenseAndBillingSettings/LicenseAndBillingSettings.unit.spec.tsx
index 4c4c22c173020efebc1112a10ae0d40baf715905..d3cb66aeee5b5f0d7b70bb2ce49ad47679de6cee 100644
--- a/enterprise/frontend/src/metabase-enterprise/license/components/LicenseAndBillingSettings/LicenseAndBillingSettings.unit.spec.tsx
+++ b/enterprise/frontend/src/metabase-enterprise/license/components/LicenseAndBillingSettings/LicenseAndBillingSettings.unit.spec.tsx
@@ -30,6 +30,7 @@ const setupState = ({
           value: token,
         },
       ],
+      warnings: {},
     },
   });
 
diff --git a/frontend/src/metabase-types/api/mocks/settings.ts b/frontend/src/metabase-types/api/mocks/settings.ts
index 34f3a7e486a0c48fd8ad56c43ee4d20eaefb150e..fb0f47548827a6732303af08b8f5ae392322c13e 100644
--- a/frontend/src/metabase-types/api/mocks/settings.ts
+++ b/frontend/src/metabase-types/api/mocks/settings.ts
@@ -160,7 +160,7 @@ export const createMockSettings = (
   "email-configured?": false,
   "email-smtp-host": null,
   "email-smtp-port": null,
-  "email-smtp-security": "None",
+  "email-smtp-security": "none",
   "email-smtp-username": null,
   "email-smtp-password": null,
   "embedding-app-origin": "",
diff --git a/frontend/src/metabase-types/api/settings.ts b/frontend/src/metabase-types/api/settings.ts
index 5cbf0fcbd1403fc947427a85a52c570c1632d579..3bf98cf09dad90dca450041b07e5f9cdf15949e2 100644
--- a/frontend/src/metabase-types/api/settings.ts
+++ b/frontend/src/metabase-types/api/settings.ts
@@ -202,7 +202,7 @@ interface InstanceSettings {
   "admin-email": string;
   "email-smtp-host": string | null;
   "email-smtp-port": number | null;
-  "email-smtp-security": "None" | "SSL" | "TLS" | "STARTTLS";
+  "email-smtp-security": "none" | "ssl" | "tls" | "starttls";
   "email-smtp-username": string | null;
   "email-smtp-password": string | null;
   "enable-embedding": boolean;
diff --git a/frontend/src/metabase-types/store/admin.ts b/frontend/src/metabase-types/store/admin.ts
index 3a6b7e15cd31918f99eb9308909157b7da25e2e8..f18f5ddc6e01963edcf1f4cc32ff833e3f295805 100644
--- a/frontend/src/metabase-types/store/admin.ts
+++ b/frontend/src/metabase-types/store/admin.ts
@@ -2,6 +2,7 @@ import type {
   CollectionPermissions,
   GroupsPermissions,
   SettingDefinition,
+  SettingKey,
 } from "metabase-types/api";
 
 export type AdminPathKey =
@@ -37,6 +38,7 @@ export interface AdminState {
   };
   settings: {
     settings: SettingDefinition[];
+    warnings: Partial<Record<SettingKey, unknown>>;
   };
 }
 
diff --git a/frontend/src/metabase-types/store/mocks/admin.ts b/frontend/src/metabase-types/store/mocks/admin.ts
index d1b6dff494489e977075baac7eb6eb03f6cda25c..e193a287745b8e49b4355608ca94db87439e423b 100644
--- a/frontend/src/metabase-types/store/mocks/admin.ts
+++ b/frontend/src/metabase-types/store/mocks/admin.ts
@@ -5,7 +5,7 @@ export const createMockAdminState = (
 ): AdminState => ({
   app: createMockAdminAppState(),
   permissions: createMockPermissionsState(),
-  settings: { settings: [] },
+  settings: { settings: [], warnings: {} },
   ...opts,
 });
 
diff --git a/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.tsx b/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.tsx
index 04f09f2110ee533a6dba8f183e817dd06994a820..ef5258762e5b092b77f6406dbf708a8f21478522 100644
--- a/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.tsx
+++ b/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.tsx
@@ -29,6 +29,7 @@ import {
   updateEmailSettings,
   clearEmailSettings,
 } from "../../settings";
+import { SetByEnvVarWrapper } from "../SettingsSetting";
 
 const BREADCRUMBS = [[t`Email`, "/admin/settings/email"], [t`SMTP`]];
 
@@ -39,7 +40,7 @@ const SEND_TEST_BUTTON_STATES = {
 };
 type ButtonStateType = keyof typeof SEND_TEST_BUTTON_STATES;
 
-interface SMTPConnectionFormProps {
+export interface SMTPConnectionFormProps {
   elements: SettingElement[];
   settingValues: Settings;
 }
@@ -53,17 +54,33 @@ type FormValueProps = Pick<
   | "email-smtp-password"
 >;
 
-const FORM_VALUE_SCHEMA = Yup.object({
-  "email-smtp-host": Yup.string().required(Errors.required).default(""),
-  "email-smtp-port": Yup.number()
-    .positive()
-    .nullable()
-    .required(Errors.required)
-    .default(null),
-  "email-smtp-security": Yup.string(),
-  "email-smtp-username": Yup.string().default(""),
-  "email-smtp-password": Yup.string().default(""),
-});
+const anySchema = Yup.mixed().nullable().default(null);
+
+// we need to allow this form to be submitted even when we have removed certain inputs
+// when they are set by env vars
+const getFormValueSchema = (elementMap: _.Dictionary<SettingElement>) => {
+  return Yup.object({
+    "email-smtp-host": elementMap["email-smtp-host"].is_env_setting
+      ? anySchema
+      : Yup.string().required(Errors.required).default(""),
+    "email-smtp-port": elementMap["email-smtp-port"].is_env_setting
+      ? anySchema
+      : Yup.number()
+          .positive()
+          .nullable()
+          .required(Errors.required)
+          .default(null),
+    "email-smtp-security": elementMap["email-smtp-security"].is_env_setting
+      ? anySchema
+      : Yup.string().default("none"),
+    "email-smtp-username": elementMap["email-smtp-username"].is_env_setting
+      ? anySchema
+      : Yup.string().default(""),
+    "email-smtp-password": elementMap["email-smtp-password"].is_env_setting
+      ? anySchema
+      : Yup.string().default(""),
+  });
+};
 
 export const SMTPConnectionForm = ({
   elements,
@@ -80,11 +97,11 @@ export const SMTPConnectionForm = ({
 
   const initialValues = useMemo<FormValueProps>(
     () => ({
-      "email-smtp-host": settingValues["email-smtp-host"] || "",
+      "email-smtp-host": settingValues["email-smtp-host"],
       "email-smtp-port": settingValues["email-smtp-port"],
-      "email-smtp-security": settingValues["email-smtp-security"] || "none",
-      "email-smtp-username": settingValues["email-smtp-username"] || "",
-      "email-smtp-password": settingValues["email-smtp-password"] || "",
+      "email-smtp-security": settingValues["email-smtp-security"] ?? "none",
+      "email-smtp-username": settingValues["email-smtp-username"] ?? "",
+      "email-smtp-password": settingValues["email-smtp-password"] ?? "",
     }),
     [settingValues],
   );
@@ -136,107 +153,122 @@ export const SMTPConnectionForm = ({
     }
   }, [dispatch, isHosted]);
 
+  const allSetByEnvVars = useMemo(() => {
+    return elements.every(element => element.is_env_setting);
+  }, [elements]);
+
   return (
     <Flex justify="space-between">
-      <Stack spacing="sm" maw={400} style={{ paddingInlineStart: "0.5rem" }}>
+      <Stack spacing="sm" maw={600} style={{ paddingInlineStart: "0.5rem" }}>
         {isEmailConfigured && (
           <Breadcrumbs crumbs={BREADCRUMBS} className={cx(CS.mb3)} />
         )}
         <FormProvider
           initialValues={initialValues}
-          validationSchema={FORM_VALUE_SCHEMA}
+          validationSchema={getFormValueSchema(elementMap)}
           onSubmit={handleUpdateEmailSettings}
           enableReinitialize
         >
           {({ dirty, isValid, isSubmitting, values }) => (
             <Form>
-              <FormTextInput
-                name="email-smtp-host"
-                label={elementMap["email-smtp-host"]["display_name"]}
-                description={elementMap["email-smtp-host"]["description"]}
-                placeholder={elementMap["email-smtp-host"]["placeholder"]}
-                mb="1.5rem"
-                labelProps={{
-                  tt: "uppercase",
-                  mb: "0.5rem",
-                }}
-                descriptionProps={{
-                  fz: "0.75rem",
-                  mb: "0.5rem",
-                }}
-              />
-              <FormTextInput
-                name="email-smtp-port"
-                label={elementMap["email-smtp-port"]["display_name"]}
-                description={elementMap["email-smtp-port"]["description"]}
-                placeholder={elementMap["email-smtp-port"]["placeholder"]}
-                mb="1.5rem"
-                labelProps={{
-                  tt: "uppercase",
-                  mb: "0.5rem",
-                }}
-                descriptionProps={{
-                  fz: "0.75rem",
-                  mb: "0.5rem",
-                }}
-              />
-              <FormRadioGroup
-                name="email-smtp-security"
-                label={elementMap["email-smtp-security"]["display_name"]}
-                description={elementMap["email-smtp-security"]["description"]}
-                mb="1.5rem"
-                labelProps={{
-                  tt: "uppercase",
-                  fz: "0.875rem",
-                  c: "text-medium",
-                  mb: "0.5rem",
-                }}
-              >
-                <Group>
-                  {Object.entries(
-                    elementMap["email-smtp-security"].options || {},
-                  ).map(([value, setting]) => (
-                    <Radio
-                      value={value}
-                      label={setting.name}
-                      key={value}
-                      styles={{
-                        inner: { display: "none" },
-                        label: {
-                          paddingLeft: 0,
-                          color:
-                            values["email-smtp-security"] === value
-                              ? color("brand")
-                              : color("text-dark"),
-                        },
-                      }}
-                    />
-                  ))}
-                </Group>
-              </FormRadioGroup>
-              <FormTextInput
-                name="email-smtp-username"
-                label={elementMap["email-smtp-username"]["display_name"]}
-                description={elementMap["email-smtp-username"]["description"]}
-                placeholder={elementMap["email-smtp-username"]["placeholder"]}
-                mb="1.5rem"
-                labelProps={{
-                  tt: "uppercase",
-                  mb: "0.5rem",
-                }}
-              />
-              <FormTextInput
-                name="email-smtp-password"
-                type="password"
-                label={elementMap["email-smtp-password"]["display_name"]}
-                description={elementMap["email-smtp-password"]["description"]}
-                placeholder={elementMap["email-smtp-password"]["placeholder"]}
-                mb="1.5rem"
-                labelProps={{
-                  tt: "uppercase",
-                  mb: "0.5rem",
-                }}
-              />
+              <SetByEnvVarWrapper setting={elementMap["email-smtp-host"]}>
+                <FormTextInput
+                  name="email-smtp-host"
+                  label={elementMap["email-smtp-host"]["display_name"]}
+                  description={elementMap["email-smtp-host"]["description"]}
+                  placeholder={elementMap["email-smtp-host"]["placeholder"]}
+                  mb="1.5rem"
+                  labelProps={{
+                    tt: "uppercase",
+                    mb: "0.5rem",
+                  }}
+                  descriptionProps={{
+                    fz: "0.75rem",
+                    mb: "0.5rem",
+                  }}
+                />
+              </SetByEnvVarWrapper>
+              <SetByEnvVarWrapper setting={elementMap["email-smtp-port"]}>
+                <FormTextInput
+                  name="email-smtp-port"
+                  label={elementMap["email-smtp-port"]["display_name"]}
+                  description={elementMap["email-smtp-port"]["description"]}
+                  placeholder={elementMap["email-smtp-port"]["placeholder"]}
+                  mb="1.5rem"
+                  labelProps={{
+                    tt: "uppercase",
+                    mb: "0.5rem",
+                  }}
+                  descriptionProps={{
+                    fz: "0.75rem",
+                    mb: "0.5rem",
+                  }}
+                />
+              </SetByEnvVarWrapper>
+              <SetByEnvVarWrapper setting={elementMap["email-smtp-security"]}>
+                <FormRadioGroup
+                  name="email-smtp-security"
+                  label={elementMap["email-smtp-security"]["display_name"]}
+                  description={elementMap["email-smtp-security"]["description"]}
+                  mb="1.5rem"
+                  labelProps={{
+                    tt: "uppercase",
+                    fz: "0.875rem",
+                    c: "text-medium",
+                    mb: "0.5rem",
+                  }}
+                >
+                  <Group>
+                    {elementMap["email-smtp-security"].options?.map(
+                      ({ value, name }) => (
+                        <Radio
+                          value={value as string}
+                          name="email-smtp-security"
+                          label={name}
+                          key={name}
+                          styles={{
+                            inner: { display: "none" },
+                            label: {
+                              paddingLeft: 0,
+                              color:
+                                values["email-smtp-security"] === value
+                                  ? color("brand")
+                                  : color("text-dark"),
+                            },
+                          }}
+                        />
+                      ),
+                    )}
+                  </Group>
+                </FormRadioGroup>
+              </SetByEnvVarWrapper>
+              <SetByEnvVarWrapper setting={elementMap["email-smtp-username"]}>
+                <FormTextInput
+                  name="email-smtp-username"
+                  label={elementMap["email-smtp-username"]["display_name"]}
+                  description={elementMap["email-smtp-username"]["description"]}
+                  placeholder={elementMap["email-smtp-username"]["placeholder"]}
+                  mb="1.5rem"
+                  labelProps={{
+                    tt: "uppercase",
+                    mb: "0.5rem",
+                  }}
+                />
+              </SetByEnvVarWrapper>
+              <SetByEnvVarWrapper setting={elementMap["email-smtp-password"]}>
+                <FormTextInput
+                  name="email-smtp-password"
+                  type="password"
+                  label={elementMap["email-smtp-password"]["display_name"]}
+                  description={elementMap["email-smtp-password"]["description"]}
+                  placeholder={elementMap["email-smtp-password"]["placeholder"]}
+                  mb="1.5rem"
+                  labelProps={{
+                    tt: "uppercase",
+                    mb: "0.5rem",
+                  }}
+                />
+              </SetByEnvVarWrapper>
               {testEmailError && (
                 <Text
                   role="alert"
@@ -250,7 +282,7 @@ export const SMTPConnectionForm = ({
               <Flex mt="1rem" gap="1.5rem">
                 <FormSubmitButton
                   label={t`Save changes`}
-                  disabled={!dirty}
+                  disabled={!dirty || !isValid || isSubmitting}
                   variant="filled"
                 />
                 {!dirty && isValid && !isSubmitting && (
@@ -258,7 +290,12 @@ export const SMTPConnectionForm = ({
                     {SEND_TEST_BUTTON_STATES[sendingEmail]}
                   </Button>
                 )}
-                <Button onClick={handleClearEmailSettings}>{t`Clear`}</Button>
+                <Button
+                  onClick={handleClearEmailSettings}
+                  disabled={allSetByEnvVars}
+                >
+                  {t`Clear`}
+                </Button>
               </Flex>
             </Form>
           )}
diff --git a/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.unit.spec.tsx b/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.unit.spec.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..5a588b1c8b8ad2e1607e12ca3062f6b8781bc63e
--- /dev/null
+++ b/frontend/src/metabase/admin/settings/components/Email/SMTPConnectionForm.unit.spec.tsx
@@ -0,0 +1,388 @@
+import userEvent from "@testing-library/user-event";
+import fetchMock from "fetch-mock";
+
+import {
+  setupEmailEndpoints,
+  setupPropertiesEndpoints,
+  setupSettingsEndpoints,
+} from "__support__/server-mocks";
+import { renderWithProviders, screen } from "__support__/ui";
+import type { SettingDefinition, Settings } from "metabase-types/api";
+import {
+  createMockSettingsState,
+  createMockState,
+} from "metabase-types/store/mocks";
+
+import type { SettingElement } from "../../types";
+
+import type { SMTPConnectionFormProps } from "./SMTPConnectionForm";
+import { SMTPConnectionForm } from "./SMTPConnectionForm";
+
+const defaultSettings = {
+  "email-configured": true,
+} as Partial<Settings>;
+
+const defaultElements = [
+  {
+    placeholder: "smtp.yourservice.com",
+    key: "email-smtp-host",
+    value: null,
+    is_env_setting: false,
+    env_name: "MB_EMAIL_SMTP_HOST",
+    description: "The address of the SMTP server that handles your emails.",
+    default: "Using value of env var $MB_EMAIL_SMTP_HOST",
+    originalValue: null,
+    display_name: "SMTP Host",
+    type: "string",
+    required: true,
+    autoFocus: true,
+  },
+  {
+    placeholder: "587",
+    key: "email-smtp-port",
+    value: 587,
+    is_env_setting: false,
+    env_name: "MB_EMAIL_SMTP_PORT",
+    description: "The port your SMTP server uses for outgoing emails.",
+    default: null,
+    originalValue: 587,
+    display_name: "SMTP Port",
+    type: "number",
+    required: true,
+    validations: [["integer", "That's not a valid port number"]],
+  },
+  {
+    placeholder: "none",
+    key: "email-smtp-security",
+    value: null,
+    is_env_setting: false,
+    env_name: "MB_EMAIL_SMTP_SECURITY",
+    description: null,
+    default: "none",
+    originalValue: null,
+    display_name: "SMTP Security",
+    type: "radio",
+    options: [
+      { value: "none", name: "None" },
+      { value: "ssl", name: "SSL" },
+      { value: "tls", name: "TLS" },
+      { value: "starttls", name: "STARTTLS" },
+    ],
+    defaultValue: "none",
+  },
+  {
+    placeholder: "nicetoseeyou",
+    key: "email-smtp-username",
+    value: "ash@example.com",
+    is_env_setting: false,
+    env_name: "MB_EMAIL_SMTP_USERNAME",
+    description: null,
+    default: null,
+    originalValue: "ash@example.com",
+    display_name: "SMTP Username",
+    type: "string",
+  },
+  {
+    placeholder: "Shhh...",
+    key: "email-smtp-password",
+    value: "**********xy",
+    is_env_setting: false,
+    env_name: "MB_EMAIL_SMTP_PASSWORD",
+    description: null,
+    default: null,
+    originalValue: "**********xy",
+    display_name: "SMTP Password",
+    type: "password",
+  },
+] as SettingElement[];
+
+const defaultValues = {
+  "email-smtp-host": null,
+  "email-smtp-port": null,
+  "email-smtp-security": "none",
+  "email-smtp-username": null,
+} as Settings;
+
+const setup = ({ elements, settingValues }: SMTPConnectionFormProps) => {
+  setupEmailEndpoints();
+  setupSettingsEndpoints(elements as SettingDefinition[]);
+  setupPropertiesEndpoints(settingValues);
+
+  renderWithProviders(
+    <SMTPConnectionForm elements={elements} settingValues={settingValues} />,
+    {
+      storeInitialState: createMockState({
+        settings: createMockSettingsState(defaultSettings),
+      }),
+    },
+  );
+};
+
+describe("SMTP connection form", () => {
+  it("should render the smtp connection form", async () => {
+    setup({ elements: defaultElements, settingValues: defaultValues });
+
+    expect(screen.getByText(/SMTP Host/i)).toBeInTheDocument();
+    expect(screen.getByText(/SMTP Port/i)).toBeInTheDocument();
+    expect(screen.getByText(/SMTP Host/i)).toBeInTheDocument();
+    expect(screen.getByText(/SMTP Username/i)).toBeInTheDocument();
+    expect(screen.getByText(/SMTP Password/i)).toBeInTheDocument();
+  });
+
+  it("should render all security options", () => {
+    setup({ elements: defaultElements, settingValues: defaultValues });
+
+    expect(screen.getByText("None")).toBeInTheDocument();
+    expect(screen.getByText("SSL")).toBeInTheDocument();
+    expect(screen.getByText("TLS")).toBeInTheDocument();
+    expect(screen.getByText("STARTTLS")).toBeInTheDocument();
+  });
+
+  it("should populate the host", () => {
+    const values = {
+      ...defaultValues,
+      "email-smtp-host": "smtp.rotom.com",
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: values });
+
+    expect(screen.getByLabelText(/SMTP host/i)).toHaveDisplayValue(
+      "smtp.rotom.com",
+    );
+  });
+
+  it("should populate the port", () => {
+    const values = {
+      ...defaultValues,
+      "email-smtp-port": 123,
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: values });
+
+    expect(screen.getByLabelText(/SMTP port/i)).toHaveDisplayValue("123");
+  });
+
+  it("should populate the passed security value", () => {
+    const values = {
+      ...defaultValues,
+      "email-smtp-security": "ssl",
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: values });
+
+    expect(screen.getByLabelText("SSL")).toBeChecked();
+    expect(screen.getByLabelText("TLS")).not.toBeChecked();
+  });
+
+  it("should populate the username", () => {
+    const values = {
+      ...defaultValues,
+      "email-smtp-username": "misty@example.com",
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: values });
+
+    expect(screen.getByLabelText(/SMTP username/i)).toHaveDisplayValue(
+      "misty@example.com",
+    );
+  });
+
+  it("should populate the password", () => {
+    const values = {
+      ...defaultValues,
+      "email-smtp-password": "*****chu",
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: values });
+
+    expect(screen.getByLabelText(/SMTP password/i)).toHaveDisplayValue(
+      "*****chu",
+    );
+  });
+
+  it("should show save button as disabled when required fields are empty", () => {
+    setup({ elements: defaultElements, settingValues: defaultValues });
+
+    expect(
+      screen.getByRole("button", { name: /save changes/i }),
+    ).toBeDisabled();
+  });
+
+  it("should show save button as enabled when required fields are filled", async () => {
+    setup({ elements: defaultElements, settingValues: defaultValues });
+
+    expect(
+      screen.getByRole("button", { name: /save changes/i }),
+    ).toBeDisabled();
+
+    await userEvent.type(screen.getByLabelText(/SMTP host/i), "smtp.rotom.com");
+    await userEvent.type(screen.getByLabelText(/SMTP port/i), "123");
+
+    expect(
+      await screen.findByRole("button", { name: /save changes/i }),
+    ).toBeEnabled();
+
+    await userEvent.click(screen.getByLabelText("TLS"));
+    await userEvent.type(
+      screen.getByLabelText(/SMTP username/i),
+      "misty@example.com",
+    );
+    await userEvent.type(
+      screen.getByLabelText(/SMTP password/i),
+      "iheartpikachu",
+    );
+
+    expect(
+      await screen.findByRole("button", { name: /save changes/i }),
+    ).toBeEnabled();
+  });
+
+  it("should submit all settings changes via api", async () => {
+    setup({ elements: defaultElements, settingValues: defaultValues });
+
+    await userEvent.type(screen.getByLabelText(/SMTP host/i), "smtp.rotom.com");
+    await userEvent.type(screen.getByLabelText(/SMTP port/i), "123");
+    await userEvent.click(screen.getByLabelText("TLS"));
+    await userEvent.type(
+      screen.getByLabelText(/SMTP username/i),
+      "misty@example.com",
+    );
+    await userEvent.type(
+      screen.getByLabelText(/SMTP password/i),
+      "iheartpikachu",
+    );
+
+    await userEvent.click(
+      screen.getByRole("button", { name: /save changes/i }),
+    );
+
+    const [emailApiCall] = fetchMock.calls();
+    const body = await emailApiCall?.request?.json();
+
+    expect(body).toEqual({
+      "email-smtp-host": "smtp.rotom.com",
+      "email-smtp-port": "123",
+      "email-smtp-security": "tls",
+      "email-smtp-username": "misty@example.com",
+      "email-smtp-password": "iheartpikachu",
+    });
+  });
+
+  it("should hide setting fields that are set by an environment variable", () => {
+    const elements = [
+      {
+        ...defaultElements[0],
+        is_env_setting: true,
+      },
+      ...defaultElements.slice(1),
+    ];
+
+    setup({ elements, settingValues: defaultValues });
+
+    expect(screen.getByText(/this has been set by the/i)).toBeInTheDocument();
+    expect(screen.getByText(/MB_EMAIL_SMTP_HOST/i)).toBeInTheDocument();
+    expect(screen.getByText(/environment variable/i)).toBeInTheDocument();
+  });
+
+  it("should allow form submission when some fields are set by an environment variable", async () => {
+    const elements = [
+      {
+        ...defaultElements[0],
+        is_env_setting: true,
+      },
+      ...defaultElements.slice(1),
+    ];
+
+    setup({ elements, settingValues: defaultValues });
+
+    expect(screen.getByText(/this has been set by the/i)).toBeInTheDocument();
+    expect(screen.getByText(/MB_EMAIL_SMTP_HOST/i)).toBeInTheDocument();
+    expect(screen.getByText(/environment variable/i)).toBeInTheDocument();
+
+    await userEvent.type(screen.getByLabelText(/SMTP port/i), "123");
+    await userEvent.click(screen.getByLabelText("TLS"));
+    await userEvent.type(
+      screen.getByLabelText(/SMTP username/i),
+      "misty@example.com",
+    );
+    await userEvent.type(
+      screen.getByLabelText(/SMTP password/i),
+      "iheartpikachu",
+    );
+
+    expect(
+      await screen.findByRole("button", { name: /save changes/i }),
+    ).toBeEnabled();
+
+    await userEvent.click(
+      screen.getByRole("button", { name: /save changes/i }),
+    );
+
+    const [emailApiCall] = fetchMock.calls();
+    const body = await emailApiCall?.request?.json();
+
+    expect(body).toEqual({
+      "email-smtp-host": null,
+      "email-smtp-port": "123",
+      "email-smtp-security": "tls",
+      "email-smtp-username": "misty@example.com",
+      "email-smtp-password": "iheartpikachu",
+    });
+  });
+
+  it("should enable test email button when all required fields are populated", async () => {
+    const fullValues = {
+      "email-smtp-host": "smtp.rotom.com",
+      "email-smtp-port": 123,
+      "email-smtp-security": "tls",
+      "email-smtp-username": "misty@example.com",
+      "email-smtp-password": "iheartpikachu",
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: fullValues });
+
+    expect(
+      await screen.findByRole("button", { name: /send test email/i }),
+    ).toBeEnabled();
+  });
+
+  it("should hide test email button when fields are missing", async () => {
+    setup({ elements: defaultElements, settingValues: defaultValues });
+
+    expect(
+      screen.queryByRole("button", { name: /send test email/i }),
+    ).not.toBeInTheDocument();
+  });
+
+  it("should hide test email button when form is dirty", async () => {
+    const fullValues = {
+      "email-smtp-host": "smtp.rotom.com",
+      "email-smtp-port": 123,
+      "email-smtp-security": "tls",
+      "email-smtp-username": "misty@example.com",
+      "email-smtp-password": "iheartpikachu",
+    } as Settings;
+
+    setup({ elements: defaultElements, settingValues: fullValues });
+
+    expect(
+      await screen.findByRole("button", { name: /send test email/i }),
+    ).toBeEnabled();
+    await userEvent.type(screen.getByLabelText(/SMTP host/i), "smtp.rotom.com");
+    expect(
+      screen.queryByRole("button", { name: /send test email/i }),
+    ).not.toBeInTheDocument();
+  });
+
+  it("should enable test email button when all fields are set by environment variables (metabase#45445)", async () => {
+    const elements = defaultElements.map(el => ({
+      ...el,
+      is_env_setting: true,
+    }));
+
+    setup({ elements, settingValues: defaultValues });
+    expect(
+      await screen.findByRole("button", { name: /send test email/i }),
+    ).toBeEnabled();
+  });
+});
diff --git a/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx b/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx
index 5202789b209b2fc25cdccc7b31a8c52e1321b7f1..97909ffa638052fe42250b2b9f0e1eb2d868b329 100644
--- a/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx
+++ b/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx
@@ -6,6 +6,7 @@ import { jt } from "ttag";
 
 import ExternalLink from "metabase/core/components/ExternalLink";
 import { alpha } from "metabase/lib/colors";
+import { Box } from "metabase/ui";
 
 import { settingToFormFieldId, getEnvVarDocsUrl } from "../utils";
 
@@ -95,13 +96,7 @@ export const SettingsSetting = props => {
       {!setting.noHeader && <SettingHeader id={settingId} setting={setting} />}
       <SettingContent>
         {setting.is_env_setting && !setting.forceRenderWidget ? (
-          <SettingEnvVarMessage>
-            {jt`This has been set by the ${(
-              <ExternalLink href={getEnvVarDocsUrl(setting.env_name)}>
-                {setting.env_name}
-              </ExternalLink>
-            )} environment variable.`}
-          </SettingEnvVarMessage>
+          <SetByEnvVar setting={setting} />
         ) : (
           <Widget id={settingId} {...widgetProps} />
         )}
@@ -115,3 +110,25 @@ export const SettingsSetting = props => {
     </SettingRoot>
   );
 };
+
+export const SetByEnvVar = ({ setting }) => (
+  <SettingEnvVarMessage>
+    {jt`This has been set by the ${(
+      <ExternalLink href={getEnvVarDocsUrl(setting.env_name)}>
+        {setting.env_name}
+      </ExternalLink>
+    )} environment variable.`}
+  </SettingEnvVarMessage>
+);
+
+export const SetByEnvVarWrapper = ({ setting, children }) => {
+  if (setting.is_env_setting) {
+    return (
+      <Box mb="lg">
+        <SettingHeader id={setting.key} setting={setting} />
+        <SetByEnvVar setting={setting} />
+      </Box>
+    );
+  }
+  return children;
+};
diff --git a/frontend/src/metabase/admin/settings/selectors.js b/frontend/src/metabase/admin/settings/selectors.js
index 7b4fc5e7c88aeebd07bd6533c14c8a5fa73407e7..5566f8d5a049c3c6d84e925df71b58f6871dcfd8 100644
--- a/frontend/src/metabase/admin/settings/selectors.js
+++ b/frontend/src/metabase/admin/settings/selectors.js
@@ -252,7 +252,12 @@ export const ADMIN_SETTINGS_SECTIONS = {
         display_name: t`SMTP Security`,
         description: null,
         type: "radio",
-        options: { none: "None", ssl: "SSL", tls: "TLS", starttls: "STARTTLS" },
+        options: [
+          { value: "none", name: "None" },
+          { value: "ssl", name: "SSL" },
+          { value: "tls", name: "TLS" },
+          { value: "starttls", name: "STARTTLS" },
+        ],
         defaultValue: "none",
       },
       {
diff --git a/frontend/src/metabase/admin/settings/types.ts b/frontend/src/metabase/admin/settings/types.ts
index e0d6d370bf9d761720f4d56e6b88528a18b36119..2c9828223da1d66db5486df96155db84cfbd6135 100644
--- a/frontend/src/metabase/admin/settings/types.ts
+++ b/frontend/src/metabase/admin/settings/types.ts
@@ -11,6 +11,8 @@ export type SettingElement = {
   key?: SettingKey;
   tab?: string;
   display_name?: string;
+  env_name?: string;
+  is_env_setting?: boolean;
   type?: string;
   description?: string;
   note?: string;
@@ -18,6 +20,8 @@ export type SettingElement = {
   placeholder?: string;
   options?: { value: SettingValue; name: string }[];
   value?: SettingValue;
+  default?: SettingValue;
+  originalValue?: SettingValue;
   defaultValue?: SettingValue;
   required?: boolean;
   autoFocus?: boolean;
diff --git a/frontend/src/metabase/admin/upsells/UpsellHosting.tsx b/frontend/src/metabase/admin/upsells/UpsellHosting.tsx
index 25b407e2901e5d9e3602658970fa10881d1baa0a..aedaad65c898c16a603641ef1dd9b5c63f6d668d 100644
--- a/frontend/src/metabase/admin/upsells/UpsellHosting.tsx
+++ b/frontend/src/metabase/admin/upsells/UpsellHosting.tsx
@@ -27,7 +27,7 @@ export const UpsellHosting = ({ source }: { source: string }) => {
       maxWidth={UPSELL_CARD_WIDTH}
     >
       {jt`${(
-        <strong>{t`Migrate to Metabase Cloud`}</strong>
+        <strong key="migrate">{t`Migrate to Metabase Cloud`}</strong>
       )} for fast, reliable, and secure deployment.`}
     </UpsellCard>
   );
@@ -51,7 +51,7 @@ export const UpsellHostingUpdates = ({ source }: { source: string }) => {
       maxWidth={UPSELL_CARD_WIDTH}
     >
       {jt`${(
-        <strong>{t`Migrate to Metabase Cloud`}</strong>
+        <strong key="migrate">{t`Migrate to Metabase Cloud`}</strong>
       )} for fast, reliable, and secure deployment.`}
     </UpsellCard>
   );
diff --git a/frontend/test/__support__/server-mocks/email.ts b/frontend/test/__support__/server-mocks/email.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a34edf3637e41a697ceb0a4d4c1aad6380e69166
--- /dev/null
+++ b/frontend/test/__support__/server-mocks/email.ts
@@ -0,0 +1,15 @@
+// email settings, why aren't they in the settings endpoint? who knows? ¯\_(ツ)_/¯
+import fetchMock from "fetch-mock";
+
+const defaultSettings = {
+  "email-smtp-host": "smtp.rotom.test",
+  "email-smtp-port": 587,
+  "email-smtp-security": "tls",
+  "email-smtp-username": "misty@rotom.test",
+  "email-smtp-password": "iheartpikachu",
+};
+
+export const setupEmailEndpoints = (settings = defaultSettings) => {
+  fetchMock.put("path:/api/email", settings);
+  fetchMock.delete("path:/api/email", 204);
+};
diff --git a/frontend/test/__support__/server-mocks/index.ts b/frontend/test/__support__/server-mocks/index.ts
index d0510d3db92d12844d34619d9a66337ce940cd0d..25a96caf9a04bc554acb21a6a1709393efdbb90b 100644
--- a/frontend/test/__support__/server-mocks/index.ts
+++ b/frontend/test/__support__/server-mocks/index.ts
@@ -10,6 +10,7 @@ export * from "./constants";
 export * from "./dashboard";
 export * from "./database";
 export * from "./dataset";
+export * from "./email";
 export * from "./field";
 export * from "./group";
 export * from "./impersonation";