diff --git a/send.go b/send.go index 9115ebe..4b32445 100644 --- a/send.go +++ b/send.go @@ -18,6 +18,7 @@ type Sender interface { type SendCloser interface { Sender Close() error + Reset() error } // A SendFunc is a function that sends emails to the given addresses. diff --git a/send_test.go b/send_test.go index ba59cd3..239b471 100644 --- a/send_test.go +++ b/send_test.go @@ -31,12 +31,17 @@ func (s mockSender) Send(from string, to []string, msg io.WriterTo) error { type mockSendCloser struct { mockSender close func() error + reset func() error } func (s *mockSendCloser) Close() error { return s.close() } +func (s *mockSendCloser) Reset() error { + return s.reset() +} + func TestSend(t *testing.T) { s := &mockSendCloser{ mockSender: stubSend(t, testFrom, []string{testTo1, testTo2}, testMsg), @@ -44,6 +49,10 @@ func TestSend(t *testing.T) { t.Error("Close() should not be called in Send()") return nil }, + reset: func() error { + t.Error("Reset() should not be called in Send()") + return nil + }, } if err := Send(s, getTestMessage()); err != nil { t.Errorf("Send(): %v", err) diff --git a/smtp.go b/smtp.go index 2aa49c8..ee9a393 100644 --- a/smtp.go +++ b/smtp.go @@ -180,6 +180,10 @@ func (c *smtpSender) Close() error { return c.Quit() } +func (c *smtpSender) Reset() error { + return c.smtpClient.Reset() +} + // Stubbed out for tests. var ( netDialTimeout = net.DialTimeout @@ -196,6 +200,7 @@ type smtpClient interface { Auth(smtp.Auth) error Mail(string) error Rcpt(string) error + Reset() error Data() (io.WriteCloser, error) Quit() error Close() error diff --git a/smtp_test.go b/smtp_test.go index b6f9155..3239f43 100644 --- a/smtp_test.go +++ b/smtp_test.go @@ -138,6 +138,19 @@ func TestDialerTimeout(t *testing.T) { }) } +func TestDialerReset(t *testing.T) { + d := NewDialer(testHost, testPort, "user", "pwd") + doTestSMTPReset(t, d, []string{ + "Extension STARTTLS", + "StartTLS", + "Extension AUTH", + "Auth", + "Reset", + "Quit", + "Close", + }) +} + type mockClient struct { t *testing.T i int @@ -195,6 +208,11 @@ func (c *mockClient) Quit() error { return nil } +func (c *mockClient) Reset() error { + c.do("Reset") + return nil +} + func (c *mockClient) Close() error { c.do("Close") return nil @@ -239,6 +257,55 @@ func testSendMailTimeout(t *testing.T, d *Dialer, want []string) { doTestSendMail(t, d, want, true) } +func doTestSMTPReset(t *testing.T, d *Dialer, want []string){ + testClient := &mockClient{ + t: t, + want: want, + addr: addr(d.Host, d.Port), + config: d.TLSConfig, + timeout: false, + } + + netDialTimeout = func(network, address string, d time.Duration) (net.Conn, error) { + if network != "tcp" { + t.Errorf("Invalid network, got %q, want tcp", network) + } + if address != testClient.addr { + t.Errorf("Invalid address, got %q, want %q", + address, testClient.addr) + } + return testConn, nil + } + + tlsClient = func(conn net.Conn, config *tls.Config) *tls.Conn { + if conn != testConn { + t.Errorf("Invalid conn, got %#v, want %#v", conn, testConn) + } + assertConfig(t, config, testClient.config) + return testTLSConn + } + + smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) { + if host != testHost { + t.Errorf("Invalid host, got %q, want %q", host, testHost) + } + return testClient, nil + } + //Start "daemon" mode + s, err := d.Dial() + if err != nil { + t.Error(err) + } + + /* + Call the reset for testing purposes. In practice, this should be called after an error while attempting to send + a message. But per RFC 5321 RSET can be called at any time. + */ + s.Reset() + s.Close() + +} + func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) { testClient := &mockClient{ t: t,