| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 | package gomailimport (	"crypto/tls"	"fmt"	"io"	"net"	"net/smtp"	"strings"	"time")// A Dialer is a dialer to an SMTP server.type Dialer struct {	// Host represents the host of the SMTP server.	Host string	// Port represents the port of the SMTP server.	Port int	// Username is the username to use to authenticate to the SMTP server.	Username string	// Password is the password to use to authenticate to the SMTP server.	Password string	// Auth represents the authentication mechanism used to authenticate to the	// SMTP server.	Auth smtp.Auth	// SSL defines whether an SSL connection is used. It should be false in	// most cases since the authentication mechanism should use the STARTTLS	// extension instead.	SSL bool	// TSLConfig represents the TLS configuration used for the TLS (when the	// STARTTLS extension is used) or SSL connection.	TLSConfig *tls.Config	// LocalName is the hostname sent to the SMTP server with the HELO command.	// By default, "localhost" is sent.	LocalName string}// NewDialer returns a new SMTP Dialer. The given parameters are used to connect// to the SMTP server.func NewDialer(host string, port int, username, password string) *Dialer {	return &Dialer{		Host:     host,		Port:     port,		Username: username,		Password: password,		SSL:      port == 465,	}}// NewPlainDialer returns a new SMTP Dialer. The given parameters are used to// connect to the SMTP server.//// Deprecated: Use NewDialer instead.func NewPlainDialer(host string, port int, username, password string) *Dialer {	return NewDialer(host, port, username, password)}// 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), 10*time.Second)	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.LocalName != "" {		if err := c.Hello(d.LocalName); err != nil {			return nil, err		}	}	if !d.SSL {		if ok, _ := c.Extension("STARTTLS"); ok {			if err := c.StartTLS(d.tlsConfig()); err != nil {				c.Close()				return nil, err			}		}	}	if d.Auth == nil && d.Username != "" {		if ok, auths := c.Extension("AUTH"); ok {			if strings.Contains(auths, "CRAM-MD5") {				d.Auth = smtp.CRAMMD5Auth(d.Username, d.Password)			} else if strings.Contains(auths, "LOGIN") &&				!strings.Contains(auths, "PLAIN") {				d.Auth = &loginAuth{					username: d.Username,					password: d.Password,					host:     d.Host,				}			} else {				d.Auth = smtp.PlainAuth("", d.Username, d.Password, d.Host)			}		}	}	if d.Auth != nil {		if err = c.Auth(d.Auth); err != nil {			c.Close()			return nil, err		}	}	return &smtpSender{c, d}, nil}func (d *Dialer) tlsConfig() *tls.Config {	if d.TLSConfig == nil {		return &tls.Config{ServerName: d.Host}	}	return d.TLSConfig}func addr(host string, port int) string {	return fmt.Sprintf("%s:%d", host, port)}// DialAndSend opens a connection to the SMTP server, sends the given emails and// closes the connection.func (d *Dialer) DialAndSend(m ...*Message) error {	s, err := d.Dial()	if err != nil {		return err	}	defer s.Close()	return Send(s, m...)}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	}	for _, addr := range to {		if err := c.Rcpt(addr); err != nil {			return err		}	}	w, err := c.Data()	if err != nil {		return err	}	if _, err = msg.WriteTo(w); err != nil {		w.Close()		return err	}	return w.Close()}func (c *smtpSender) Close() error {	return c.Quit()}// Stubbed out for tests.var (	netDialTimeout = net.DialTimeout	tlsClient      = tls.Client	smtpNewClient  = func(conn net.Conn, host string) (smtpClient, error) {		return smtp.NewClient(conn, host)	})type smtpClient interface {	Hello(string) error	Extension(string) (bool, string)	StartTLS(*tls.Config) error	Auth(smtp.Auth) error	Mail(string) error	Rcpt(string) error	Data() (io.WriteCloser, error)	Quit() error	Close() error}
 |