package infra import ( "crypto/tls" "fmt" "net" "net/smtp" ) // SMTPConnect establishes an authenticated SMTP connection using the given config. // TLSMode controls encryption: // - "tls" → direct TLS (typical port 465) // - "starttls" → plain connection upgraded with STARTTLS (typical port 587) // - "" → no encryption (typical port 25) // // Returns an *smtp.Client ready to use with SMTPSend. // The caller is responsible for calling client.Quit() when done. func SMTPConnect(cfg SMTPConfig) (*smtp.Client, error) { addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) switch cfg.TLSMode { case "tls": tlsCfg := &tls.Config{ServerName: cfg.Host} conn, err := tls.Dial("tcp", addr, tlsCfg) if err != nil { return nil, fmt.Errorf("smtp_connect: tls dial %s: %w", addr, err) } client, err := smtp.NewClient(conn, cfg.Host) if err != nil { conn.Close() return nil, fmt.Errorf("smtp_connect: new client: %w", err) } if cfg.Username != "" { auth := smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host) if err := client.Auth(auth); err != nil { client.Close() return nil, fmt.Errorf("smtp_connect: auth: %w", err) } } return client, nil case "starttls": conn, err := net.Dial("tcp", addr) if err != nil { return nil, fmt.Errorf("smtp_connect: dial %s: %w", addr, err) } client, err := smtp.NewClient(conn, cfg.Host) if err != nil { conn.Close() return nil, fmt.Errorf("smtp_connect: new client: %w", err) } tlsCfg := &tls.Config{ServerName: cfg.Host} if err := client.StartTLS(tlsCfg); err != nil { client.Close() return nil, fmt.Errorf("smtp_connect: starttls: %w", err) } if cfg.Username != "" { auth := smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host) if err := client.Auth(auth); err != nil { client.Close() return nil, fmt.Errorf("smtp_connect: auth: %w", err) } } return client, nil default: // no encryption client, err := smtp.Dial(addr) if err != nil { return nil, fmt.Errorf("smtp_connect: dial %s: %w", addr, err) } if cfg.Username != "" { auth := smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host) if err := client.Auth(auth); err != nil { client.Close() return nil, fmt.Errorf("smtp_connect: auth: %w", err) } } return client, nil } }