| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 | 
							- package gomail
 
- import (
 
- 	"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
 
- }
 
 
  |