net/smtp: return error from SendMail when required AUTH not available

Return an error if an Auth is passed to SendMail but the server does not support authentication.

Fixes #22145

Change-Id: I49a37259c47bbe5145e30fa8a2d05444e60cb378
Reviewed-on: https://go-review.googlesource.com/79776
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index cf699e6..e4e12ae 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -343,10 +343,11 @@
 		}
 	}
 	if a != nil && c.ext != nil {
-		if _, ok := c.ext["AUTH"]; ok {
-			if err = c.Auth(a); err != nil {
-				return err
-			}
+		if _, ok := c.ext["AUTH"]; !ok {
+			return errors.New("smtp: server doesn't support AUTH")
+		}
+		if err = c.Auth(a); err != nil {
+			return err
 		}
 	}
 	if err = c.Mail(from); err != nil {
diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
index d489922..e97aaa4 100644
--- a/src/net/smtp/smtp_test.go
+++ b/src/net/smtp/smtp_test.go
@@ -15,6 +15,7 @@
 	"net/textproto"
 	"runtime"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 )
@@ -635,6 +636,50 @@
 QUIT
 `
 
+func TestSendMailWithAuth(t *testing.T) {
+	l, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Unable to to create listener: %v", err)
+	}
+	defer l.Close()
+	wg := sync.WaitGroup{}
+	var done = make(chan struct{})
+	go func() {
+		defer wg.Done()
+		conn, err := l.Accept()
+		if err != nil {
+			t.Errorf("Accept error: %v", err)
+			return
+		}
+		defer conn.Close()
+
+		tc := textproto.NewConn(conn)
+		tc.PrintfLine("220 hello world")
+		msg, err := tc.ReadLine()
+		if msg == "EHLO localhost" {
+			tc.PrintfLine("250 mx.google.com at your service")
+		}
+		// for this test case, there should have no more traffic
+		<-done
+	}()
+	wg.Add(1)
+
+	err = SendMail(l.Addr().String(), PlainAuth("", "user", "pass", "smtp.google.com"), "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com
+To: other@example.com
+Subject: SendMail test
+
+SendMail is working for me.
+`, "\n", "\r\n", -1)))
+	if err == nil {
+		t.Error("SendMail: Server doesn't support AUTH, expected to get an error, but got none ")
+	}
+	if err.Error() != "smtp: server doesn't support AUTH" {
+		t.Errorf("Expected: smtp: server doesn't support AUTH, got: %s", err)
+	}
+	close(done)
+	wg.Wait()
+}
+
 func TestAuthFailed(t *testing.T) {
 	server := strings.Join(strings.Split(authFailedServer, "\n"), "\r\n")
 	client := strings.Join(strings.Split(authFailedClient, "\n"), "\r\n")
@@ -830,14 +875,9 @@
 }
 
 func sendMail(hostPort string) error {
-	host, _, err := net.SplitHostPort(hostPort)
-	if err != nil {
-		return err
-	}
-	auth := PlainAuth("", "", "", host)
 	from := "joe1@example.com"
 	to := []string{"joe2@example.com"}
-	return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!"))
+	return SendMail(hostPort, nil, from, to, []byte("Subject: test\n\nhowdy!"))
 }
 
 // (copied from net/http/httptest)