diff --git a/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx b/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx
index 4f7a06945d..a653527324 100644
--- a/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx
+++ b/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx
@@ -133,6 +133,26 @@ describe('EmailProviderSelect', () => {
);
});
+ it('associates visible labels with manual SMTP fields', () => {
+ render(() => (
+
+ ));
+
+ expect(screen.getByRole('textbox', { name: 'SMTP server' })).toBeInTheDocument();
+ expect(screen.getByRole('spinbutton', { name: 'SMTP port' })).toBeInTheDocument();
+ expect(screen.getByRole('textbox', { name: 'From address' })).toBeInTheDocument();
+ expect(screen.getByRole('textbox', { name: 'Reply-to address' })).toBeInTheDocument();
+ expect(screen.getByRole('textbox', { name: 'Username' })).toBeInTheDocument();
+ expect(screen.getByLabelText('Password / API key')).toHaveAttribute('type', 'password');
+ expect(screen.getByRole('textbox', { name: 'Recipients (one per line)' })).toBeInTheDocument();
+
+ fireEvent.click(screen.getByText('Show advanced options'));
+
+ expect(screen.getByRole('spinbutton', { name: 'Rate limit' })).toBeInTheDocument();
+ expect(screen.getByRole('spinbutton', { name: 'Max retries' })).toBeInTheDocument();
+ expect(screen.getByRole('spinbutton', { name: 'Retry delay (seconds)' })).toBeInTheDocument();
+ });
+
it('loads providers from the API and populates the select', async () => {
render(() => (
diff --git a/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx b/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx
index 9e041a0e45..53f0575ecc 100644
--- a/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx
+++ b/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx
@@ -1,4 +1,4 @@
-import { Show, For } from 'solid-js';
+import { Show, For, createUniqueId } from 'solid-js';
import type { UIEmailConfig } from '@/features/alerts/types';
import {
ALERT_EMAIL_FROM_ADDRESS_LABEL,
@@ -46,6 +46,19 @@ interface EmailProviderSelectProps extends EmailProviderSelectStateProps {
export function EmailProviderSelect(props: EmailProviderSelectProps) {
const state = useEmailProviderSelectState(props);
+ const fieldIdPrefix = `alert-email-${createUniqueId()}`;
+ const fieldIds = {
+ smtpServer: `${fieldIdPrefix}-smtp-server`,
+ smtpPort: `${fieldIdPrefix}-smtp-port`,
+ fromAddress: `${fieldIdPrefix}-from-address`,
+ replyTo: `${fieldIdPrefix}-reply-to`,
+ username: `${fieldIdPrefix}-username`,
+ password: `${fieldIdPrefix}-password`,
+ recipients: `${fieldIdPrefix}-recipients`,
+ rateLimit: `${fieldIdPrefix}-rate-limit`,
+ maxRetries: `${fieldIdPrefix}-max-retries`,
+ retryDelay: `${fieldIdPrefix}-retry-delay`,
+ };
const instructionBoxClass =
'mt-2 rounded border border-blue-200 bg-blue-50 px-3 py-2 text-xs leading-relaxed text-blue-900 dark:border-blue-700 dark:bg-blue-900 dark:text-blue-200';
@@ -103,8 +116,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {