diff --git a/protocol/smtp/smtp.go b/protocol/smtp/smtp.go index 92b931cdad6133ce5fb947a893a27172217fbe9b..f57970a46c3e52ecaffd81d1eb228b08d234c5f2 100644 --- a/protocol/smtp/smtp.go +++ b/protocol/smtp/smtp.go @@ -58,7 +58,7 @@ func (c *Conn) Close() error { } func (c *Conn) SendMail(username, password, from string, to []string, msg []byte) error { - auth := smtp.PlainAuth("", username, password, c.hostname) + auth := newPlainAuth("", username, password, c.hostname) if ok, _ := c.client.Extension("AUTH"); !ok { return errors.New("server does not support AUTH extension") } @@ -86,3 +86,35 @@ func (c *Conn) SendMail(username, password, from string, to []string, msg []byte } return nil } + +// This is almost a copy of net/smtp/auth.go, but without the TLS +// check. The net/smtp package attempts to autodetect TLS usage by +// checking if the net.Conn it got is actually a *tls.Conn. Since we +// wrap our connection in the logging wrapper, this check fails, and +// net/smtp.PlainAuth will refuse to authenticate, thinking the +// connection is unencrypted. +type plainAuth struct { + identity, username, password string + host string +} + +func newPlainAuth(identity, username, password, host string) smtp.Auth { + return &plainAuth{identity, username, password, host} +} + +func (a *plainAuth) Start(server *smtp.ServerInfo) (string, []byte, error) { + // We know we have TLS. + if server.Name != a.host { + return "", nil, errors.New("wrong host name") + } + resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password) + return "PLAIN", resp, nil +} + +func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) { + if more { + // We've already sent everything. + return nil, errors.New("unexpected server challenge") + } + return nil, nil +}