// SMTPAuth SMTPAuth
type SMTPAuth struct {
accessToken string
}
// Auth auth
func Auth(token string) smtp.Auth {
return &SMTPAuth{token}
}
// Start start
func (a *SMTPAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "xoauth2", []byte(""), nil
}
// Next next
func (a *SMTPAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
return []byte(a.accessToken), nil
}
return nil, nil
}
Start a connection by running command:
$ openssl s_client -starttls smtp -ign_eof -crlf -connect smtp.office365.com:587
[... SSL handshake...]
250 SMTPUTF8
HELO <your email host> # Send HELO command to server
250 BY3PR04CA0028.outlook.office365.com Hello [134.195.101.47]
The connection establishment has been implemented by net/smtp itself, we only need to implement the auth part by ourselves.
AUTH XOAUTH2
334 # server sends code `334` with message `(empty)` to client
func (a *SMTPAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "xoauth2", []byte(""), nil // "xoauth2" is equivalent to "XOAUTH2"
}
Code 334 represents: Server challenge - the text part contains the Base64-encoded challenge (SMTP return code reference)
334
<base64 token>
235 2.7.0 Authentication successful
// at this point, SMTP server tells us that we need to take a challenge (provide our access token)
// fromServer represents the message follow along with "334"
// more tells us that one more step is required in order to complete the authentication (or flow)
func (a *SMTPAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
// sends the access token to the server
return []byte(a.accessToken), nil
}
return nil, nil
}
Entire authentication flow:
HELO <your email host>
250 BY3PR04CA0028.outlook.office365.com Hello [134.195.101.47]
AUTH XOAUTH2
334
<base64 token>
235 2.7.0 Authentication successful