HouzuoGuo/laitos

Support SMTP over TLS in addition to StartTLS for outgoing mail configuration

suntong opened this issue · 21 comments

Hi @HouzuoGuo,

Would you write a how to for Outgoing mail configuration for SMTP server (via SSL Mail) please?

Azure does not block SSL Mail port 465. I can test it out after you've written it.
If you need Go code that can send SSL Mail, I can look it up for you, but it's the most common one that I used and connect to SMTP server via SSL Mail and send mail just fine.

thanks

Thanks for the proposal, this feature will be soon considered for inclusion in the next version.

Thanks @HouzuoGuo, the go package that I was talking about is
https://github.com/go-gomail/gomail

I had no problem using it to send from Azure to the aliyun SMTP server, where everyone can get a free account.

Please evaluate
e27c24c

Thanks HouzuoGuo,

Hmm, what would happen if dialMTA times out?

Would the err declared and defined on line

conn, err := net.DialTimeout("tcp", net.JoinHostPort(client.MTAHost, strconv.Itoa(client.MTAPort)), MailIOTimeoutSec*time.Second)

overshadow the return, thus the return just get nil?

The function return value will capture the timeout error, there is no overshadow effect taking place.

ok. thanks.

FYI,

https://play.golang.org/p/06JMbuzPE-a

a is re-declared and re-defined on line 12, overshadowing the passed value.

that looks about right!

Hmm..., one more thing, the aliyun mail is really unstable -- in my code, I have to retry quite a bit just to get it connected:

	var conn net.Conn
	d := time.Duration(30 * time.Second)
	for i := 1; i <= 12; i++ {
		conn, err = tls.Dial("tcp", smtpServer, tlsconfig)
		if err == nil {
			break
		}
		// both logging necessary, one to console & one to file
		verbose(0, "Error: %s, in attempt #%d at %s\n", err, i, time.Now())
		log.Printf("Error: %s, in attempt #%d\n", err, i)
		time.Sleep(d)
		d *= 2
	}
	// SMTP connection error, return to the caller
	//abortOn("SMTP connection", err)
	if err != nil {
		return err
	}

The total loop time has been increased from 6 to 8, to 10, and now it is 12.

Would you mind adding the looping for retry, before giving up and return to user?
Thx

does aliyun's mail server seriously require hours of retry as written in your function? Would 10 attempts in 60 seconds be sufficient?

Yeah, unfortunately it does require hours of retry sometimes, considering afternoon (e.g., 2~3pm) American time is just the deep at night when they do maintenance. I.e., 10 attempts in 60 seconds, which gives only 10 minutes, is surely not enough based on my experience --

My loop max of 5 gives 8 minutes, and 6 gives 16 minutes, however, the loop time "has been increased from 6 to 8, to 10, and now it is 12". It is not always this slow, but it does happen.

If you think of standard MTA, it will even retry for days.

OK, let's say that in a very unfortunate scenario an MTA has an uptime of only 95%, then I'll let outbond mail delivery to retry up to an hour.

If you have used the retry loop in serious code, be aware that it now has a resource leak - the loop won't terminate till end of the planet.

zutto commented

Out of box thing for someone to check, does the tls.dial attempt alternate records listed in dns? (ie, jumping down to another MX entry with lower priority)

I'm just guessing here, but I would believe no large email service, such as aliyun would take all their MX servers down at the same time?

@zutto, yeah, that's a good idea.

@HouzuoGuo,

If you have used the retry loop in serious code, be aware that it now has a resource leak - the loop won't terminate till end of the planet.

I can't grasp what you are trying to say here, would you elaborate please?

Nevermind, I overlooked something.

How does it look now? 777b018

Looks good, however if we're going to write it once and forget about it, then ideally there needs another loop around trying different mail IPs. I.e., if the 1st failed, we don't want to wait for 10 minutes to try the next one, then another 20 minutes to try the third one...

once more question, @HouzuoGuo, you sure laitos mailing will work if I try it on Azures? I.e., are you sure Azures is capable of receiving emails?

Thx

The loop already gives all MTA IPs a chance to deliver mail, throughout all short and long interval attempts. What's missing?

I have an instance of laitos running on Azure and have no trouble sending and receiving emails over there.

Oh, sorry for responding late, Howard,

So let me confirm, say by the time it took 4-minute sleep to loop to one IP of the MTAs, and it failed, before trying the next IP, how long it would need to sleep? 4 minutes or 8 minutes?

Looping over all the available IPs within the same waiting time is a better solution, I think.

PS, based on my experiences, making the connection is the only place that needs retry during the whole mail-sending process, even for unreliable servers like aliyun. If you find adding the extra loop around trying different mail IPs difficult with your current implementation, you may want to simplify your retrying algorithm, e.g., to one that I posted initially, which is very easy to add that extra loop.

Although I appreciate your thoughts I am opposed to establishing subsequent connections to multiple IPs of MTA using same amount of delay, it opens up a possibility for misconfigured MTA to exhaust laitos memory usage.

Ok. respect your decision.