package mailer import ( "bufio" "net" "strconv" "strings" "testing" ) func TestSendFailsWhenConfigMissing(t *testing.T) { t.Setenv("EMAIL_HOST", "") t.Setenv("EMAIL_PORT", "") t.Setenv("EMAIL_FROM", "") if err := Send("user@example.com", "subj", "body"); err == nil { t.Fatal("expected error for incomplete email config") } } func TestSendPlainSMTP(t *testing.T) { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("failed to listen: %v", err) } defer ln.Close() done := make(chan error, 1) go func() { conn, err := ln.Accept() if err != nil { done <- err return } defer conn.Close() r := bufio.NewReader(conn) w := bufio.NewWriter(conn) write := func(s string) error { if _, err := w.WriteString(s); err != nil { return err } return w.Flush() } if err := write("220 localhost Simple Mail Transfer Service Ready\r\n"); err != nil { done <- err return } for { line, err := r.ReadString('\n') if err != nil { done <- err return } cmd := strings.TrimSpace(line) switch { case strings.HasPrefix(strings.ToUpper(cmd), "EHLO") || strings.HasPrefix(strings.ToUpper(cmd), "HELO"): if err := write("250-localhost\r\n250 AUTH PLAIN\r\n"); err != nil { done <- err return } case strings.HasPrefix(strings.ToUpper(cmd), "MAIL FROM"): if err := write("250 OK\r\n"); err != nil { done <- err return } case strings.HasPrefix(strings.ToUpper(cmd), "RCPT TO"): if err := write("250 OK\r\n"); err != nil { done <- err return } case strings.HasPrefix(strings.ToUpper(cmd), "DATA"): if err := write("354 End data with .\r\n"); err != nil { done <- err return } for { d, err := r.ReadString('\n') if err != nil { done <- err return } if strings.TrimSpace(d) == "." { break } } if err := write("250 OK queued\r\n"); err != nil { done <- err return } case strings.HasPrefix(strings.ToUpper(cmd), "QUIT"): _ = write("221 Bye\r\n") done <- nil return default: if err := write("250 OK\r\n"); err != nil { done <- err return } } } }() host, portStr, err := net.SplitHostPort(ln.Addr().String()) if err != nil { t.Fatalf("failed to parse listener address: %v", err) } if _, err := strconv.Atoi(portStr); err != nil { t.Fatalf("invalid test smtp port: %v", err) } t.Setenv("EMAIL_HOST", host) t.Setenv("EMAIL_PORT", portStr) t.Setenv("EMAIL_FROM", "noreply@example.com") t.Setenv("EMAIL_HOST_USER", "") t.Setenv("EMAIL_HOST_PASSWORD", "") t.Setenv("EMAIL_USE_TLS", "false") t.Setenv("EMAIL_USE_SSL", "false") if err := Send("user@example.com", "Verify", "Hello"); err != nil { t.Fatalf("expected send success, got error: %v", err) } if err := <-done; err != nil { t.Fatalf("smtp server finished with error: %v", err) } }