package config import ( "fmt" "os" "strings" "github.com/joho/godotenv" ) // Config holds all application configuration loaded from environment variables. type Config struct { // IMAP settings IMAPHost string IMAPPort string IMAPUser string IMAPPass string // SMTP settings SMTPHost string SMTPPort string SMTPUser string SMTPPass string // OpenClaw settings OpenClawURL string OpenClawAPIKey string // Bridge settings BridgeCallbackToken string SystemEmail string WhitelistEmails []string // Optional IMAPProxyURL string // Server ListenAddr string // Public callback base URL for OpenClaw callbacks CallbackBaseURL string } // Load reads .env (if present) and populates Config from environment variables. // Returns an error if any required variable is missing. func Load() (*Config, error) { // Best-effort load .env — ignore error if file doesn't exist. _ = godotenv.Load() cfg := &Config{ IMAPHost: os.Getenv("IMAP_HOST"), IMAPPort: os.Getenv("IMAP_PORT"), IMAPUser: os.Getenv("IMAP_USER"), IMAPPass: os.Getenv("IMAP_PASS"), SMTPHost: os.Getenv("SMTP_HOST"), SMTPPort: os.Getenv("SMTP_PORT"), SMTPUser: os.Getenv("SMTP_USER"), SMTPPass: os.Getenv("SMTP_PASS"), OpenClawURL: os.Getenv("OPENCLAW_URL"), OpenClawAPIKey: os.Getenv("OPENCLAW_API_KEY"), BridgeCallbackToken: os.Getenv("BRIDGE_CALLBACK_TOKEN"), SystemEmail: os.Getenv("SYSTEM_EMAIL"), IMAPProxyURL: os.Getenv("IMAP_PROXY_URL"), ListenAddr: os.Getenv("LISTEN_ADDR"), CallbackBaseURL: os.Getenv("CALLBACK_BASE_URL"), } if raw := os.Getenv("WHITELIST_EMAILS"); raw != "" { for _, email := range strings.Split(raw, ",") { if trimmed := strings.TrimSpace(email); trimmed != "" { cfg.WhitelistEmails = append(cfg.WhitelistEmails, trimmed) } } } if cfg.ListenAddr == "" { cfg.ListenAddr = ":8080" } if cfg.CallbackBaseURL == "" { cfg.CallbackBaseURL = "http://localhost" } if err := cfg.validate(); err != nil { return nil, err } return cfg, nil } // validate checks that all required configuration values are present. func (c *Config) validate() error { required := map[string]string{ "IMAP_HOST": c.IMAPHost, "IMAP_PORT": c.IMAPPort, "IMAP_USER": c.IMAPUser, "IMAP_PASS": c.IMAPPass, "SMTP_HOST": c.SMTPHost, "SMTP_PORT": c.SMTPPort, "SMTP_USER": c.SMTPUser, "SMTP_PASS": c.SMTPPass, "OPENCLAW_URL": c.OpenClawURL, "BRIDGE_CALLBACK_TOKEN": c.BridgeCallbackToken, "SYSTEM_EMAIL": c.SystemEmail, } var missing []string for name, val := range required { if val == "" { missing = append(missing, name) } } if len(missing) > 0 { return fmt.Errorf("missing required config: %s", strings.Join(missing, ", ")) } return nil }