Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconnect on timeout not working #18

Closed
acroca opened this issue Jan 24, 2018 · 9 comments
Closed

Reconnect on timeout not working #18

acroca opened this issue Jan 24, 2018 · 9 comments

Comments

@acroca
Copy link

acroca commented Jan 24, 2018

Hi,

I'm using this fork and I can't figure out why the reconnect on timeout doesn't work.

I create a new Dialer and Dial right away. If the connection is established it works fine, but as soon as it gets a timeout it doesn't work anymore.

I get this error after getting the timeout:

gomail: could not send email 1: 421 3a031b949411: SMTP command timeout - closing connection

And following attempts to send emails return this error:

gomail: could not send email 1: write tcp 172.18.0.7:36196->172.18.0.3:25: write: broken pipe

If it matters, I use https://github.com/namshi/docker-smtp as a smtp server with no configuration at this point

Do I have to do anything special?

@acroca
Copy link
Author

acroca commented Jan 24, 2018

The error type is *textproto.Error and it doesn't implement net.Error

@ivy
Copy link

ivy commented Jan 27, 2018

@acroca It's possible we may have introduced a bug when #10 was merged. Just to clarify, have you encountered this issue when running against go-gomail as well?

Edit: I see by your last comment that you might be referring to the couple lines in smtpSender.retryError().

@acroca
Copy link
Author

acroca commented Jan 27, 2018

After using go-gomail I started using this fork because I thought the retry was implemented in this fork and not there, so if go-gomail has reconnection after timeout yes, I had the same issue :)

And yes, that's the function I debugged to check the type of the error.

Could it be related with a go version? I'm using 1.9.2, maybe in recent go version updates they changed the type of error returned.

@abc100m
Copy link

abc100m commented Mar 26, 2018

May be there is a bug on std SMTP

// NewClient returns a new Client using an existing connection and host as a
// server name to be used when authenticating.
func NewClient(conn net.Conn, host string) (*Client, error) {
	text := textproto.NewConn(conn)
	_, _, err := text.ReadResponse(220)
	if err != nil {
		text.Close()
		return nil, err
	}
	c := &Client{Text: text, conn: conn, serverName: host, localName: "localhost"}
	_, c.tls = conn.(*tls.Conn)
	return c, nil
}

What happens when server don't send 220 response to we? hangup

_, _, err := text.ReadResponse(220)

So I changed Dial() like

func (d *Dialer) Dial() (SendCloser, error) {
	timer := time.AfterFunc(d.Timeout, func() {
		conn.Close()
	})
    c, err := smtpNewClient(conn, d.HostName)
    timer.Stop()
}

I'm newbie gopher and hope someone can help with this case.

@abc100m
Copy link

abc100m commented Mar 26, 2018

Ha, got it! We could move code

// Dial dials and authenticates to an SMTP server. The returned SendCloser
// should be closed when done using it.
func (d *Dialer) Dial() (SendCloser, error) {
	conn, err := NetDialTimeout("tcp", addr(d.Host, d.Port), d.Timeout)
	if err != nil {
		return nil, err
	}

	if d.SSL {
		conn = tlsClient(conn, d.tlsConfig())
	}

	c, err := smtpNewClient(conn, d.Host)
	if err != nil {
		return nil, err
	}

	if d.Timeout > 0 {
		conn.SetDeadline(time.Now().Add(d.Timeout))
	}
....

to

// Dial dials and authenticates to an SMTP server. The returned SendCloser
// should be closed when done using it.
func (d *Dialer) Dial() (SendCloser, error) {
	conn, err := NetDialTimeout("tcp", addr(d.Host, d.Port), d.Timeout)
	if err != nil {
		return nil, err
	}
	if d.Timeout > 0 {   // to here 
		conn.SetDeadline(time.Now().Add(d.Timeout))
	}
	if d.SSL {
		conn = tlsClient(conn, d.tlsConfig())
	}

	c, err := smtpNewClient(conn, d.Host)   //this line also need timeout
	if err != nil {
		return nil, err
	}
        ...

@abc100m
Copy link

abc100m commented Mar 26, 2018

Sorry, we are not the same issue.

@pedromorgan
Copy link

Cant we set up a test mail server ?

@arundudeemmt
Copy link

hi all ,

is this fixed .... get same error with gomail

@ivy
Copy link

ivy commented Aug 20, 2018

@acroca After seeing so many reports on this, I realize there's a miscommunication on the reason behind the RetryFailure setting. Originally, it was only there to redial when the client times out. In your case and in many other users' cases, what you're experiencing is a server timeout. Unfortunately, there isn't much that can be done to automatically recover without supporting each SMTP server implementation out there.

I'd instead recommend redialing and not relying on this feature. See #33 for my reasoning. I'm closing this issue in the meantime. Thanks and apologies for the long wait.

@ivy ivy closed this as completed Aug 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants