oficina / meet Public

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
Paul Campbell pushed by paul@keymail.dev 85025bc78c43e51317649d70a1ffcd776a0e4b41 parent cae60ed
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"))
+}