usememos/memos · error
enabled notification email requires smtpHost, a positive smt
Error message
enabled notification email requires smtpHost, a positive smtpPort, and fromEmail
What it means
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.
Source
Thrown at store/deployment_config.go:277
{name: "bucket", value: s3Config.Bucket},
} {
if strings.TrimSpace(field.value) == "" {
return errors.Errorf("storageSetting default S3 config.%s is required", field.name)
}
}
}
case storepb.InstanceSettingKey_MEMO_RELATED:
if setting.GetMemoRelatedSetting() == nil {
return errors.New("memoRelatedSetting must be populated for key MEMO_RELATED")
}
case storepb.InstanceSettingKey_NOTIFICATION:
notification := setting.GetNotificationSetting()
if notification == nil {
return errors.New("notificationSetting must be populated for key NOTIFICATION")
}
if email := notification.Email; email != nil && email.Enabled {
if strings.TrimSpace(email.SmtpHost) == "" || email.SmtpPort <= 0 || strings.TrimSpace(email.FromEmail) == "" {
return errors.New("enabled notification email requires smtpHost, a positive smtpPort, and fromEmail")
}
if email.UseTls && email.UseSsl {
return errors.New("notification email cannot enable both useTls and useSsl")
}
}
case storepb.InstanceSettingKey_AI:
if setting.GetAiSetting() == nil {
return errors.New("aiSetting must be populated for key AI")
}
if err := normalizeDeploymentAISetting(setting.GetAiSetting()); err != nil {
return err
}
case storepb.InstanceSettingKey_BASIC, storepb.InstanceSettingKey_TAGS:
return errors.Errorf("key %s cannot be deployment configured", setting.Key)
default:
return errors.Errorf("unsupported instance setting key %s", setting.Key)
}
return nilView on GitHub (pinned to 14d757ce1f)
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.
Example fix
// before
{ "key": "NOTIFICATION", "notificationSetting": { "email": { "enabled": true, "smtpHost": "", "smtpPort": 0, "fromEmail": "" } } }
// after
{ "key": "NOTIFICATION", "notificationSetting": { "email": { "enabled": true, "smtpHost": "smtp.example.com", "smtpPort": 587, "fromEmail": "memos@example.com" } } } Defensive patterns
Strategy: validation
Validate before calling
if e := notification.GetEmail(); e != nil && e.GetEnabled() {
if strings.TrimSpace(e.GetSmtpHost()) == "" || e.GetSmtpPort() <= 0 || strings.TrimSpace(e.GetFromEmail()) == "" {
return errors.New("enabled email requires smtpHost, positive smtpPort, fromEmail")
}
} Type guard
func enabledEmailIsComplete(e *storepb.EmailSetting) bool {
return !e.GetEnabled() ||
(strings.TrimSpace(e.GetSmtpHost()) != "" && e.GetSmtpPort() > 0 && strings.TrimSpace(e.GetFromEmail()) != "")
} Prevention
- 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.
When it happens
Trigger: "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.
Common situations: 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.
Related errors
- notification email cannot enable both useTls and useSsl
- SMTP host is required
- SMTP port must be between 1 and 65535
- from email is required
- notificationSetting must be populated for key NOTIFICATION
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/262bdd0920c1e98e.
Report an issue: GitHub.