From afff51fd8cbc246672451a1b0b67e8f4a507bad8 Mon Sep 17 00:00:00 2001 From: Alexandre Cesaro Date: Mon, 14 Mar 2016 13:43:57 +0100 Subject: [PATCH] smtpSender.Send() now automatically redials in case of a timeout --- smtp.go | 13 ++++++++++++- smtp_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/smtp.go b/smtp.go index af5d52b..8f19b0c 100644 --- a/smtp.go +++ b/smtp.go @@ -110,7 +110,7 @@ func (d *Dialer) Dial() (SendCloser, error) { } } - return &smtpSender{c}, nil + return &smtpSender{c, d}, nil } func (d *Dialer) tlsConfig() *tls.Config { @@ -138,10 +138,21 @@ func (d *Dialer) DialAndSend(m ...*Message) error { type smtpSender struct { smtpClient + d *Dialer } func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error { if err := c.Mail(from); err != nil { + if err == io.EOF { + // This is probably due to a timeout, so reconnect and try again. + sc, derr := c.d.Dial() + if derr == nil { + if s, ok := sc.(*smtpSender); ok { + *c = *s + return c.Send(from, to, msg) + } + } + } return err } diff --git a/smtp_test.go b/smtp_test.go index 300c9b7..ac1e5ef 100644 --- a/smtp_test.go +++ b/smtp_test.go @@ -115,12 +115,35 @@ func TestDialerNoAuth(t *testing.T) { }) } +func TestDialerTimeout(t *testing.T) { + d := &Dialer{ + Host: testHost, + Port: testPort, + } + testSendMailTimeout(t, d, []string{ + "Extension STARTTLS", + "StartTLS", + "Mail " + testFrom, + "Extension STARTTLS", + "StartTLS", + "Mail " + testFrom, + "Rcpt " + testTo1, + "Rcpt " + testTo2, + "Data", + "Write message", + "Close writer", + "Quit", + "Close", + }) +} + type mockClient struct { - t *testing.T - i int - want []string - addr string - config *tls.Config + t *testing.T + i int + want []string + addr string + config *tls.Config + timeout bool } func (c *mockClient) Hello(localName string) error { @@ -149,6 +172,10 @@ func (c *mockClient) Auth(a smtp.Auth) error { func (c *mockClient) Mail(from string) error { c.do("Mail " + from) + if c.timeout { + c.timeout = false + return io.EOF + } return nil } @@ -204,11 +231,20 @@ func (w *mockWriter) Close() error { } func testSendMail(t *testing.T, d *Dialer, want []string) { + doTestSendMail(t, d, want, false) +} + +func testSendMailTimeout(t *testing.T, d *Dialer, want []string) { + doTestSendMail(t, d, want, true) +} + +func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) { testClient := &mockClient{ - t: t, - want: want, - addr: addr(d.Host, d.Port), - config: d.TLSConfig, + t: t, + want: want, + addr: addr(d.Host, d.Port), + config: d.TLSConfig, + timeout: timeout, } netDial = func(network, address string) (net.Conn, error) {