smtpSender.Send() now automatically redials in case of a timeout

This commit is contained in:
Alexandre Cesaro 2016-03-14 13:43:57 +01:00
parent 5ceb8e6541
commit afff51fd8c
2 changed files with 57 additions and 10 deletions

13
smtp.go
View File

@ -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
}

View File

@ -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) {