mail: read CARLOS_SMTP_* as the per-variable fallback
The platform delivers CARLOS_SMTP_{HOST,PORT,USER,PASS,FROM} after
carlos email enable; MEET_SMTP_* overrides per variable. Slides' shape.
Without this Meet refuses to start on the platform with no relay.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P6JGj6G5cLrt2Frm8yywgK
1 file changed,
+37
−4
cmd/meet/main.go+37 −4
CI passed — run details
diff --git a/cmd/meet/main.go b/cmd/meet/main.go| index 8e94ce7..24ea113 100644 |
| --- a/cmd/meet/main.go |
| +++ b/cmd/meet/main.go |
| @@ -34,10 +34,7 @@ func main() { |
| } |
| defer d.Close() |
| - var mailer mail.Sender |
| - if os.Getenv("MEET_SMTP_HOST") != "" && os.Getenv("MEET_SMTP_FROM") != "" { |
| - mailer = mail.FromEnv("MEET", logger) |
| - } |
| + mailer := newMailer(logger) |
| cfg := meet.Config{ |
| Env: *env, |
| @@ -64,3 +61,39 @@ func main() { |
| os.Exit(1) |
| } |
| } |
| + |
| +// smtpSetting reads one SMTP setting, this app's own variable first and |
| +// the platform's as the fallback: $MEET_SMTP_HOST, else $CARLOS_SMTP_HOST. |
| +// Per variable, not per set: `carlos email enable` delivers |
| +// CARLOS_SMTP_{HOST,PORT,USER,PASS,FROM}, and the common case is wanting |
| +// every one of them except FROM, which $MEET_SMTP_FROM then overrides on |
| +// its own. Trimmed, because these arrive from an env block where a |
| +// trailing newline is a routine accident. Slides' shape, verbatim. |
| +func smtpSetting(name string) string { |
| + if v := strings.TrimSpace(os.Getenv("MEET_SMTP_" + name)); v != "" { |
| + return v |
| + } |
| + return strings.TrimSpace(os.Getenv("CARLOS_SMTP_" + name)) |
| +} |
| + |
| +// smtpSecret is smtpSetting for the two credentials, untrimmed: a |
| +// password's surrounding whitespace may be part of the password. |
| +func smtpSecret(name string) string { |
| + if v := os.Getenv("MEET_SMTP_" + name); v != "" { |
| + return v |
| + } |
| + return os.Getenv("CARLOS_SMTP_" + name) |
| +} |
| + |
| +// newMailer builds the magic-link sender. HOST and FROM have no sane |
| +// default, so either missing means no relay, and a nil return is what |
| +// lets meet.App refuse to start outside development rather than log |
| +// live links. |
| +func newMailer(logger *slog.Logger) mail.Sender { |
| + host, from := smtpSetting("HOST"), smtpSetting("FROM") |
| + if host == "" || from == "" { |
| + return nil |
| + } |
| + logger.Info("meet: SMTP configured", "host", host, "from", from) |
| + return mail.SMTP(host, smtpSetting("PORT"), from, smtpSecret("USER"), smtpSecret("PASS")) |
| +} |