package gomail import ( "crypto/tls" "io" "net" "net/smtp" "testing" ) var ( testAddr = "smtp.example.com:587" testSSLAddr = "smtp.example.com:465" testTLSConn = &tls.Conn{} testConfig = &tls.Config{InsecureSkipVerify: true} testHost = "smtp.example.com" testAuth = smtp.PlainAuth("", "user", "pwd", "smtp.example.com") testFrom = "from@example.com" testTo = []string{"to1@example.com", "to2@example.com"} testBody = "Test message" ) const wantMsg = "To: to1@example.com, to2@example.com\r\n" + "From: from@example.com\r\n" + "Mime-Version: 1.0\r\n" + "Date: 25 Jun 14 17:46 +0000\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + "Content-Transfer-Encoding: quoted-printable\r\n" + "\r\n" + "Test message" func TestDefaultSendMail(t *testing.T) { testSendMail(t, testAddr, nil, []string{ "Extension STARTTLS", "StartTLS", "Extension AUTH", "Auth", "Mail " + testFrom, "Rcpt " + testTo[0], "Rcpt " + testTo[1], "Data", "Write message", "Close writer", "Quit", "Close", }) } func TestSSLSendMail(t *testing.T) { testSendMail(t, testSSLAddr, nil, []string{ "Extension AUTH", "Auth", "Mail " + testFrom, "Rcpt " + testTo[0], "Rcpt " + testTo[1], "Data", "Write message", "Close writer", "Quit", "Close", }) } func TestTLSConfigSendMail(t *testing.T) { testSendMail(t, testAddr, testConfig, []string{ "Extension STARTTLS", "StartTLS", "Extension AUTH", "Auth", "Mail " + testFrom, "Rcpt " + testTo[0], "Rcpt " + testTo[1], "Data", "Write message", "Close writer", "Quit", "Close", }) } func TestTLSConfigSSLSendMail(t *testing.T) { testSendMail(t, testSSLAddr, testConfig, []string{ "Extension AUTH", "Auth", "Mail " + testFrom, "Rcpt " + testTo[0], "Rcpt " + testTo[1], "Data", "Write message", "Close writer", "Quit", "Close", }) } type mockClient struct { t *testing.T i int want []string addr string auth smtp.Auth config *tls.Config } func (c *mockClient) Extension(ext string) (bool, string) { c.do("Extension " + ext) return true, "" } func (c *mockClient) StartTLS(config *tls.Config) error { assertConfig(c.t, config, c.config) c.do("StartTLS") return nil } func (c *mockClient) Auth(a smtp.Auth) error { assertAuth(c.t, a, c.auth) c.do("Auth") return nil } func (c *mockClient) Mail(from string) error { c.do("Mail " + from) return nil } func (c *mockClient) Rcpt(to string) error { c.do("Rcpt " + to) return nil } func (c *mockClient) Data() (io.WriteCloser, error) { c.do("Data") return &mockWriter{c: c, want: wantMsg}, nil } func (c *mockClient) Quit() error { c.do("Quit") return nil } func (c *mockClient) Close() error { c.do("Close") return nil } func (c *mockClient) do(cmd string) { if c.i >= len(c.want) { c.t.Fatalf("Invalid command %q", cmd) } if cmd != c.want[c.i] { c.t.Fatalf("Invalid command, got %q, want %q", cmd, c.want[c.i]) } c.i++ } type mockWriter struct { want string c *mockClient } func (w *mockWriter) Write(p []byte) (int, error) { w.c.do("Write message") compareBodies(w.c.t, string(p), w.want) return len(p), nil } func (w *mockWriter) Close() error { w.c.do("Close writer") return nil } func testSendMail(t *testing.T, addr string, config *tls.Config, want []string) { testClient := &mockClient{ t: t, want: want, addr: addr, auth: testAuth, config: config, } initSMTP = func(addr string) (smtpClient, error) { assertAddr(t, addr, testClient.addr) return testClient, nil } initTLS = func(network, addr string, config *tls.Config) (*tls.Conn, error) { if network != "tcp" { t.Errorf("Invalid network, got %q, want tcp", network) } assertAddr(t, addr, testClient.addr) assertConfig(t, config, testClient.config) return testTLSConn, nil } newClient = func(conn net.Conn, host string) (smtpClient, error) { if conn != testTLSConn { t.Error("Invalid TLS connection used") } if host != testHost { t.Errorf("Invalid host, got %q, want %q", host, testHost) } return testClient, nil } msg := NewMessage() msg.SetHeader("From", testFrom) msg.SetHeader("To", testTo...) msg.SetBody("text/plain", testBody) var settings []MailerSetting if config != nil { settings = []MailerSetting{SetTLSConfig(config)} } mailer := NewCustomMailer(addr, testAuth, settings...) if err := mailer.Send(msg); err != nil { t.Error(err) } } func assertAuth(t *testing.T, got, want smtp.Auth) { if got != want { t.Errorf("Invalid auth, got %#v, want %#v", got, want) } } func assertAddr(t *testing.T, got, want string) { if got != want { t.Errorf("Invalid addr, got %q, want %q", got, want) } } func assertConfig(t *testing.T, got, want *tls.Config) { if want == nil { want = &tls.Config{ServerName: testHost} } if got.ServerName != want.ServerName { t.Errorf("Invalid field ServerName in config, got %q, want %q", got.ServerName, want.ServerName) } if got.InsecureSkipVerify != want.InsecureSkipVerify { t.Errorf("Invalid field InsecureSkipVerify in config, got %v, want %v", got.InsecureSkipVerify, want.InsecureSkipVerify) } }