package email import ( "context" "net/smtp" "strings" "testing" ) func TestSMTPTransportSendBuildsHeadersForValidInput(t *testing.T) { transport := newSMTPTransport("smtp.example.com", "587", "user", "pass") var captured string called := false prev := smtpSendMail smtpSendMail = func(addr string, auth smtp.Auth, from string, to []string, msg []byte) error { called = true if addr != "smtp.example.com:587" { t.Fatalf("addr=%q", addr) } if from != "sender@example.com" { t.Fatalf("from=%q", from) } if len(to) != 1 || to[0] != "recipient@example.com" { t.Fatalf("to=%v", to) } captured = string(msg) return nil } t.Cleanup(func() { smtpSendMail = prev }) err := transport.Send(context.Background(), FromIdentity{ Email: "sender@example.com", Name: "Descrybe Team", ReplyTo: "reply@example.com", }, Outbound{ To: "recipient@example.com", Subject: "Hello there", Text: "plain body", HTML: "

html body

", Headers: map[string]string{"List-Unsubscribe": ""}, }) if err != nil { t.Fatal(err) } if !called { t.Fatal("expected smtpSendMail to be called") } for _, want := range []string{ "From: Descrybe Team ", "To: recipient@example.com", "Subject: Hello there", "Reply-To: reply@example.com", "List-Unsubscribe: ", } { if !strings.Contains(captured, want) { t.Fatalf("message missing %q:\n%s", want, captured) } } } func TestSMTPTransportSendRejectsHeaderInjection(t *testing.T) { cases := []Outbound{ {To: "recipient@example.com", Subject: "ok\r\nBcc:evil@example.com", Text: "body"}, {To: "recipient@example.com", Subject: "ok", Text: "body", Headers: map[string]string{"X-Test\r\nBcc": "1"}}, {To: "recipient@example.com", Subject: "ok", Text: "body", Headers: map[string]string{"X-Test": "1\r\nBcc:evil@example.com"}}, } for _, tc := range cases { transport := newSMTPTransport("smtp.example.com", "587", "", "") called := false prev := smtpSendMail smtpSendMail = func(addr string, auth smtp.Auth, from string, to []string, msg []byte) error { called = true return nil } err := transport.Send(context.Background(), FromIdentity{ Email: "sender@example.com", ReplyTo: "reply@example.com", }, tc) smtpSendMail = prev if err == nil { t.Fatalf("expected error for %#v", tc) } if called { t.Fatalf("smtpSendMail should not be called for %#v", tc) } } } func TestSMTPTransportSendRejectsReplyToInjection(t *testing.T) { transport := newSMTPTransport("smtp.example.com", "587", "", "") called := false prev := smtpSendMail smtpSendMail = func(addr string, auth smtp.Auth, from string, to []string, msg []byte) error { called = true return nil } t.Cleanup(func() { smtpSendMail = prev }) err := transport.Send(context.Background(), FromIdentity{ Email: "sender@example.com", ReplyTo: "reply@example.com\r\nBcc:evil@example.com", }, Outbound{ To: "recipient@example.com", Subject: "safe", Text: "body", }) if err == nil { t.Fatal("expected invalid reply-to error") } if called { t.Fatal("smtpSendMail should not be called") } }