package main import ( "fmt" "log" "log/slog" "net/smtp" "os" "git.nakama.town/fmartingr/gotoolkit/encoding" "github.com/emersion/go-sasl" "git.nakama.town/fmartingr/smtp2shoutrrr" ) // The ANONYMOUS mechanism name. const Anonymous = "ANONYMOUS" type anonymousClient struct { Trace string } func (c *anonymousClient) Start(si *smtp.ServerInfo) (mech string, ir []byte, err error) { mech = Anonymous ir = []byte(c.Trace) return } func (c *anonymousClient) Next(challenge []byte, b bool) (response []byte, err error) { return nil, sasl.ErrUnexpectedServerChallenge } // A client implementation of the ANONYMOUS authentication mechanism, as // described in RFC 4505. func NewAnonymousClient(trace string) smtp.Auth { return &anonymousClient{trace} } // The PLAIN mechanism name. const Plain = "PLAIN" type plainClient struct { Identity string Username string Password string } func (a *plainClient) Start(si *smtp.ServerInfo) (mech string, ir []byte, err error) { mech = "PLAIN" ir = []byte(a.Identity + "\x00" + a.Username + "\x00" + a.Password) return } func (a *plainClient) Next(challenge []byte, b bool) (response []byte, err error) { slog.Info("Next: %v", slog.String("challenge", string(challenge))) return nil, nil } // A client implementation of the PLAIN authentication mechanism, as described // in RFC 4616. Authorization identity may be left blank to indicate that it is // the same as the username. func NewPlainClient(identity, username, password string) smtp.Auth { return &plainClient{identity, username, password} } func main() { var config smtp2shoutrrr.Config configPath := "config.toml" f, err := os.Open(configPath) if err != nil { slog.Error("Error opening config file", slog.String("err", err.Error()), slog.String("path", configPath)) return } enc := encoding.NewTOMLEncoding() if err := enc.DecodeReader(f, &config); err != nil { slog.Error("Error decoding config file", slog.String("err", err.Error()), slog.String("path", configPath)) return } config.SetDefaults() // hostname is used by PlainAuth to validate the TLS certificate. hostname := "localhost" auth := NewPlainClient("", config.Username, config.Password) // auth := NewAnonymousClient("test") slog.Info("Using first recipient configuration to send a test email") if len(config.Recipients) == 0 { slog.Error("No recipients found in configuration") return } if len(config.Recipients[0].Addresses) == 0 { slog.Error("No email addresses found in first recipient configuration") return } recipients := []string{config.Recipients[0].Addresses[0]} msg := []byte("Subject: Test notification\r\n\r\nThis is a test notification") from := "hello@localhost" err = smtp.SendMail(fmt.Sprintf("%s:%d", hostname, config.Port), auth, from, recipients, msg) if err != nil { log.Fatal(err) } }