Single-page site with gallery by album and event, contact form over SMTP, Docker dev/prod setup, and on-server image derivatives. Gallery photos stay local (app/images/ is gitignored). Co-authored-by: Cursor <cursoragent@cursor.com>
72 lines
1.4 KiB
Go
72 lines
1.4 KiB
Go
package mail
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
// Config holds SMTP relay settings from the environment.
|
|
type Config struct {
|
|
Host string
|
|
Port int
|
|
User string
|
|
Password string
|
|
From string
|
|
To string
|
|
// TLS: "auto" (STARTTLS on 587, plain on 25), "tls" (implicit TLS, e.g. 465), "plain"
|
|
TLS string
|
|
}
|
|
|
|
// Load reads SMTP settings from environment variables.
|
|
//
|
|
// Required: SMTP_HOST, SMTP_FROM, SMTP_TO
|
|
// Optional: SMTP_PORT (587), SMTP_USER, SMTP_PASSWORD, SMTP_TLS (auto)
|
|
func Load() (Config, error) {
|
|
host := os.Getenv("SMTP_HOST")
|
|
if host == "" {
|
|
return Config{}, fmt.Errorf("SMTP_HOST is required")
|
|
}
|
|
|
|
from := os.Getenv("SMTP_FROM")
|
|
if from == "" {
|
|
return Config{}, fmt.Errorf("SMTP_FROM is required")
|
|
}
|
|
|
|
to := os.Getenv("SMTP_TO")
|
|
if to == "" {
|
|
return Config{}, fmt.Errorf("SMTP_TO is required")
|
|
}
|
|
|
|
port := 587
|
|
if p := os.Getenv("SMTP_PORT"); p != "" {
|
|
n, err := strconv.Atoi(p)
|
|
if err != nil {
|
|
return Config{}, fmt.Errorf("SMTP_PORT: %w", err)
|
|
}
|
|
port = n
|
|
}
|
|
|
|
tls := os.Getenv("SMTP_TLS")
|
|
if tls == "" {
|
|
tls = "auto"
|
|
}
|
|
|
|
return Config{
|
|
Host: host,
|
|
Port: port,
|
|
User: os.Getenv("SMTP_USER"),
|
|
Password: os.Getenv("SMTP_PASSWORD"),
|
|
From: from,
|
|
To: to,
|
|
TLS: tls,
|
|
}, nil
|
|
}
|
|
|
|
// Enabled reports whether relay settings are present.
|
|
func Enabled() bool {
|
|
return os.Getenv("SMTP_HOST") != "" &&
|
|
os.Getenv("SMTP_FROM") != "" &&
|
|
os.Getenv("SMTP_TO") != ""
|
|
}
|