mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-06 08:01:24 +00:00
74 lines
1.5 KiB
Go
74 lines
1.5 KiB
Go
package email
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"net/smtp"
|
|
"time"
|
|
|
|
"github.com/warmbly/warmbly/internal/client/netbind"
|
|
)
|
|
|
|
func VerifySMTP(ctx context.Context, host string, port int, user, pass string) bool {
|
|
addr := fmt.Sprintf("%s:%d", host, port)
|
|
|
|
var conn net.Conn
|
|
var err error
|
|
|
|
// Matches the send client's TLS policy: MAIL_TLS_INSECURE is a dev-only
|
|
// knob for the local self-signed sandbox, never set in production.
|
|
tlsConf := &tls.Config{
|
|
ServerName: host,
|
|
InsecureSkipVerify: netbind.InsecureTLS(),
|
|
}
|
|
|
|
switch port {
|
|
case 465:
|
|
dialer := &tls.Dialer{
|
|
NetDialer: &net.Dialer{Timeout: 5 * time.Second},
|
|
Config: tlsConf,
|
|
}
|
|
conn, err = dialer.DialContext(ctx, "tcp", addr)
|
|
|
|
case 587:
|
|
dialer := &net.Dialer{Timeout: 5 * time.Second}
|
|
conn, err = dialer.DialContext(ctx, "tcp", addr)
|
|
|
|
default:
|
|
return false
|
|
}
|
|
// A bad host is ordinary user input, not an exceptional case: dial failed
|
|
// means conn is nil, and closing it would panic this goroutine and take
|
|
// the whole worker down with it.
|
|
if err != nil || conn == nil {
|
|
return false
|
|
}
|
|
defer conn.Close()
|
|
|
|
c, err := smtp.NewClient(conn, host)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
defer c.Close()
|
|
|
|
if port == 587 {
|
|
if err := c.StartTLS(tlsConf); err != nil {
|
|
return false
|
|
}
|
|
}
|
|
|
|
auth := smtp.PlainAuth("", user, pass, host)
|
|
|
|
done := make(chan error, 1)
|
|
go func() { done <- c.Auth(auth) }()
|
|
|
|
select {
|
|
case err := <-done:
|
|
return err == nil
|
|
case <-ctx.Done():
|
|
return false
|
|
}
|
|
}
|