{"record":{"id":"262bdd0920c1e98e","repo":"usememos/memos","slug":"enabled-notification-email-requires-smtphost-a-po","errorCode":null,"errorMessage":"enabled notification email requires smtpHost, a positive smtpPort, and fromEmail","messagePattern":"enabled notification email requires smtpHost, a positive smtpPort, and fromEmail","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"store/deployment_config.go","lineNumber":277,"sourceCode":"\t\t\t\t{name: \"bucket\", value: s3Config.Bucket},\n\t\t\t} {\n\t\t\t\tif strings.TrimSpace(field.value) == \"\" {\n\t\t\t\t\treturn errors.Errorf(\"storageSetting default S3 config.%s is required\", field.name)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase storepb.InstanceSettingKey_MEMO_RELATED:\n\t\tif setting.GetMemoRelatedSetting() == nil {\n\t\t\treturn errors.New(\"memoRelatedSetting must be populated for key MEMO_RELATED\")\n\t\t}\n\tcase storepb.InstanceSettingKey_NOTIFICATION:\n\t\tnotification := setting.GetNotificationSetting()\n\t\tif notification == nil {\n\t\t\treturn errors.New(\"notificationSetting must be populated for key NOTIFICATION\")\n\t\t}\n\t\tif email := notification.Email; email != nil && email.Enabled {\n\t\t\tif strings.TrimSpace(email.SmtpHost) == \"\" || email.SmtpPort <= 0 || strings.TrimSpace(email.FromEmail) == \"\" {\n\t\t\t\treturn errors.New(\"enabled notification email requires smtpHost, a positive smtpPort, and fromEmail\")\n\t\t\t}\n\t\t\tif email.UseTls && email.UseSsl {\n\t\t\t\treturn errors.New(\"notification email cannot enable both useTls and useSsl\")\n\t\t\t}\n\t\t}\n\tcase storepb.InstanceSettingKey_AI:\n\t\tif setting.GetAiSetting() == nil {\n\t\t\treturn errors.New(\"aiSetting must be populated for key AI\")\n\t\t}\n\t\tif err := normalizeDeploymentAISetting(setting.GetAiSetting()); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase storepb.InstanceSettingKey_BASIC, storepb.InstanceSettingKey_TAGS:\n\t\treturn errors.Errorf(\"key %s cannot be deployment configured\", setting.Key)\n\tdefault:\n\t\treturn errors.Errorf(\"unsupported instance setting key %s\", setting.Key)\n\t}\n\treturn nil","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/store/deployment_config.go#L259-L295","documentation":"Thrown when a NOTIFICATION instance-setting file enables email (notification.email.enabled == true) but the SMTP details are incomplete: smtpHost is blank/whitespace, smtpPort is <= 0, or fromEmail is blank. An enabled notifier without a reachable SMTP endpoint would fail every notification at runtime, so deployment validation fails fast at startup.","triggerScenarios":"\"email\": { \"enabled\": true } with smtpHost/fromEmail missing or empty, or smtpPort set to 0 / a negative number; secret-mounting that renders empty strings for host or from-email.","commonSituations":"Enabling email before provisioning SMTP credentials; environment templating (envsubst) substituting empty variables for SMTP_HOST or FROM_EMAIL; forgetting the port when using a mail relay on a non-standard port.","solutions":["Fill in all three fields: \"smtpHost\": \"smtp.example.com\", \"smtpPort\": 587, \"fromEmail\": \"memos@example.com\".","If SMTP is not actually configured yet, set \"enabled\": false until credentials exist.","Check rendered secrets for whitespace-only values if the file is generated."],"exampleFix":"// before\n{ \"key\": \"NOTIFICATION\", \"notificationSetting\": { \"email\": { \"enabled\": true, \"smtpHost\": \"\", \"smtpPort\": 0, \"fromEmail\": \"\" } } }\n\n// after\n{ \"key\": \"NOTIFICATION\", \"notificationSetting\": { \"email\": { \"enabled\": true, \"smtpHost\": \"smtp.example.com\", \"smtpPort\": 587, \"fromEmail\": \"memos@example.com\" } } }","handlingStrategy":"validation","validationCode":"if e := notification.GetEmail(); e != nil && e.GetEnabled() {\n    if strings.TrimSpace(e.GetSmtpHost()) == \"\" || e.GetSmtpPort() <= 0 || strings.TrimSpace(e.GetFromEmail()) == \"\" {\n        return errors.New(\"enabled email requires smtpHost, positive smtpPort, fromEmail\")\n    }\n}","typeGuard":"func enabledEmailIsComplete(e *storepb.EmailSetting) bool {\n    return !e.GetEnabled() ||\n        (strings.TrimSpace(e.GetSmtpHost()) != \"\" && e.GetSmtpPort() > 0 && strings.TrimSpace(e.GetFromEmail()) != \"\")\n}","tryCatchPattern":null,"preventionTips":["Keep enabled:false until every SMTP field is present; flip it last.","Assert rendered secret values are non-empty when the JSON is generated from environment variables."],"tags":["configuration","validation","notification","email","smtp","startup"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}