usememos/memos · error

SMTP host is required

Error message

SMTP host is required

What it means

Returned by Config.Validate() in internal/email/config.go when SMTPHost is the empty string. The SMTP client cannot dial GetServerAddress() ("host:port") without a host, so validation fails fast before any connection attempt. It is a pure configuration error: the mailer was constructed without a host.

Source

Thrown at internal/email/config.go:33

	SMTPPort int
	// SMTPUsername is the SMTP authentication username (usually the email address)
	SMTPUsername string
	// SMTPPassword is the SMTP authentication password or app-specific password
	SMTPPassword string
	// FromEmail is the email address that will appear in the "From" field
	FromEmail string
	// FromName is the display name that will appear in the "From" field
	FromName string
	// UseTLS enables STARTTLS encryption (recommended for port 587)
	UseTLS bool
	// UseSSL enables SSL/TLS encryption (for port 465)
	UseSSL bool
}

// Validate checks if the configuration is valid.
func (c *Config) Validate() error {
	if c.SMTPHost == "" {
		return errors.New("SMTP host is required")
	}
	if c.SMTPPort <= 0 || c.SMTPPort > 65535 {
		return errors.New("SMTP port must be between 1 and 65535")
	}
	if c.FromEmail == "" {
		return errors.New("from email is required")
	}
	return nil
}

// GetServerAddress returns the SMTP server address in the format "host:port".
func (c *Config) GetServerAddress() string {
	return fmt.Sprintf("%s:%d", c.SMTPHost, c.SMTPPort)
}

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Set the SMTP host in Settings > SMTP (e.g., smtp.example.com) or the equivalent config source, then re-validate.
  2. Check that the config key actually maps to Config.SMTPHost (typo/case mismatch in env or YAML keys).
  3. Call Validate() early at startup or after config load so this surfaces before the first send attempt.
  4. Confirm the rest of the config passes too (port 1-65535, FromEmail non-empty) since Validate checks all three.

Example fix

// before
cfg := email.Config{SMTPPort: 587, FromEmail: "noreply@example.com"}

// after
cfg := email.Config{SMTPHost: "smtp.example.com", SMTPPort: 587, FromEmail: "noreply@example.com"}
if err := cfg.Validate(); err != nil {
  return err
}
Defensive patterns

Strategy: validation

Validate before calling

// Go — validate before constructing the mailer
if strings.TrimSpace(cfg.SMTPHost) == "" {
  return errors.New("SMTP host missing: set it in settings or config before enabling mail")
}
if err := cfg.Validate(); err != nil {
  return err
}

Try / catch

if err := cfg.Validate(); err != nil {
  if errors.Is(err, email.ErrHostRequired) { /* if sentinel introduced */ }
  return errors.Wrap(err, "invalid SMTP config")
}

Prevention

When it happens

Trigger: Instantiating email.NewClient / sending mail with a Config whose SMTPHost was never set — e.g., SMTP system setting empty in the Memos admin UI, or an environment/config loader defaulting host to "". First surfaces on the first email send (e.g., a memo notification or test email) or at config validation time.

Common situations: Fresh install where the SMTP settings were never filled; deployment where the SMTP_HOST env var name differs from what the loader expects; adding email notifications to a stack/compose file but leaving host blank; YAML/JSON config with a typo'd key so the field stays zero-valued.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/4c0786934bcbfffc. Report an issue: GitHub.