{"record":{"id":"9b229ee64bffd7ea","repo":"Billionmail/BillionMail","slug":"smtp-server-is-required","errorCode":null,"errorMessage":"SMTP server is required","messagePattern":"SMTP server is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/controller/settings/settings_v1_set_blacklist_alert_settings.go","lineNumber":76,"sourceCode":"\t\tres.SetError(gerror.Newf(public.LangCtx(ctx, \"Failed to save alert settings: {}\", err.Error())))\n\t\treturn res, nil\n\t}\n\n\tres.SetSuccess(public.LangCtx(ctx, \"Alert settings saved successfully and test email sent\"))\n\treturn res, nil\n}\n\nfunc validateAlertSettings(settings *v1.SetBlacklistAlertSettingsReq) error {\n\tif settings.SenderEmail == \"\" {\n\t\treturn fmt.Errorf(\"sender email is required\")\n\t}\n\n\tif !strings.Contains(settings.SenderEmail, \"@\") {\n\t\treturn fmt.Errorf(\"invalid sender email format\")\n\t}\n\n\tif settings.SMTPServer == \"\" {\n\t\treturn fmt.Errorf(\"SMTP server is required\")\n\t}\n\n\tif settings.SMTPPort < 1 || settings.SMTPPort > 65535 {\n\t\treturn fmt.Errorf(\"SMTP port must be between 1 and 65535\")\n\t}\n\n\tif settings.SMTPPassword == \"\" {\n\t\treturn fmt.Errorf(\"SMTP password is required\")\n\t}\n\n\tif len(settings.RecipientList) == 0 {\n\t\treturn fmt.Errorf(\"at least one recipient is required\")\n\t}\n\n\tfor _, recipient := range settings.RecipientList {\n\t\tif !strings.Contains(recipient, \"@\") {\n\t\t\treturn fmt.Errorf(\"invalid recipient email format: %s\", recipient)\n\t\t}","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/settings/settings_v1_set_blacklist_alert_settings.go#L58-L94","documentation":"Validation guard inside validateAlertSettings: the blacklist alert settings request was saved with an empty SMTPServer field, so no mail relay host is available to send alert emails. The request is rejected before any settings are persisted.","triggerScenarios":"Calling SetBlacklistAlertSettings without smtpServer in the payload, with an empty string, or with only whitespace.","commonSituations":"Users leave the SMTP relay field blank expecting the local mail server to be used implicitly, or automation scripts omit the field when only updating the recipient list.","solutions":["Provide the relay hostname, e.g. smtp.example.com or mail.example.com","If the internal mail server should be used, set it explicitly to the local MX hostname (public.FormatMX(domain) result, e.g. mail.example.com)","Make the field required in the UI and validate before submit","Trim whitespace and reject blank values client-side"],"exampleFix":"// before\n{ \"smtpServer\": \"\" }\n// after\n{ \"smtpServer\": \"mail.example.com\" }","handlingStrategy":"validation","validationCode":"const server = (settings.smtpServer ?? '').trim();\nif (!server) throw new Error('SMTP server is required');","typeGuard":"function hasSmtpServer(s: unknown): s is { smtpServer: string } {\n  return typeof s === 'object' && s !== null && typeof (s as any).smtpServer === 'string' && (s as any).smtpServer.trim() !== '';\n}","tryCatchPattern":"try {\n  await api.setBlacklistAlertSettings(settings);\n} catch (e) {\n  if (String(e.message).includes('SMTP server is required')) {\n    notify('SMTP relay host is required, e.g. mail.example.com');\n    focusSmtpServerField();\n  } else throw e;\n}","preventionTips":["Always supply the relay hostname explicitly","For the built-in server, use the MX hostname (mail.example.com), not a blank value","Mark the field required in the UI","Trim and reject whitespace-only values before submit"],"tags":["validation","smtp","blacklist-alerts"],"backgroundTag":"missing-required-argument","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}