parent
d7294067b8
commit
de623e612d
10
README.md
10
README.md
|
@ -76,6 +76,16 @@ bypass the verification of the server's certificate chain and host name by using
|
||||||
|
|
||||||
Note, however, that this is insecure and should not be used in production.
|
Note, however, that this is insecure and should not be used in production.
|
||||||
|
|
||||||
|
### 504 5.7.4 Unrecognized authentication type
|
||||||
|
|
||||||
|
If you get this error, you should try using the LOGIN authentication mechanism:
|
||||||
|
|
||||||
|
addr := "smtp.example.com:587"
|
||||||
|
auth := gomail.LoginAuth("username", "password", "smtp.example.com")
|
||||||
|
mailer := gomail.NewCustomMailer(addr, auth)
|
||||||
|
|
||||||
|
See [issue #16](https://github.com/go-gomail/gomail/issues/16).
|
||||||
|
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package gomail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/smtp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type loginAuth struct {
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
host string
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginAuth returns an Auth that implements the LOGIN authentication mechanism.
|
||||||
|
func LoginAuth(username, password, host string) smtp.Auth {
|
||||||
|
return &loginAuth{username, password, host}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
||||||
|
if !server.TLS {
|
||||||
|
advertised := false
|
||||||
|
for _, mechanism := range server.Auth {
|
||||||
|
if mechanism == "LOGIN" {
|
||||||
|
advertised = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !advertised {
|
||||||
|
return "", nil, errors.New("gomail: unencrypted connection")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if server.Name != a.host {
|
||||||
|
return "", nil, errors.New("gomail: wrong host name")
|
||||||
|
}
|
||||||
|
return "LOGIN", nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||||
|
if !more {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
command := strings.ToLower(strings.TrimSuffix(string(fromServer), ":"))
|
||||||
|
switch command {
|
||||||
|
case "username":
|
||||||
|
return []byte(fmt.Sprintf("%s", a.username)), nil
|
||||||
|
case "password":
|
||||||
|
return []byte(fmt.Sprintf("%s", a.password)), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("gomail: unexpected server challenge: %s", command)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package gomail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/smtp"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type output struct {
|
||||||
|
proto string
|
||||||
|
data []string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
testUser = "user"
|
||||||
|
testPwd = "pwd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPlainAuth(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
serverProtos []string
|
||||||
|
serverChallenges []string
|
||||||
|
proto string
|
||||||
|
data []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
serverProtos: []string{"LOGIN"},
|
||||||
|
serverChallenges: []string{"Username:", "Password:"},
|
||||||
|
proto: "LOGIN",
|
||||||
|
data: []string{"", testUser, testPwd},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
auth := LoginAuth(testUser, testPwd, testHost)
|
||||||
|
server := &smtp.ServerInfo{
|
||||||
|
Name: testHost,
|
||||||
|
TLS: true,
|
||||||
|
Auth: test.serverProtos,
|
||||||
|
}
|
||||||
|
proto, toServer, err := auth.Start(server)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Start error: %v", err)
|
||||||
|
}
|
||||||
|
if proto != test.proto {
|
||||||
|
t.Errorf("Invalid protocol, got %q, want %q", proto, test.proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
got := string(toServer)
|
||||||
|
if got != test.data[i] {
|
||||||
|
t.Errorf("Invalid response, got %q, want %q", got, test.data[i])
|
||||||
|
}
|
||||||
|
for _, challenge := range test.serverChallenges {
|
||||||
|
toServer, err = auth.Next([]byte(challenge), true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Auth error: %v", err)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
got = string(toServer)
|
||||||
|
if got != test.data[i] {
|
||||||
|
t.Errorf("Invalid response, got %q, want %q", got, test.data[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue