Skip to content

Commit

Permalink
Auto detect authentication type
Browse files Browse the repository at this point in the history
Signed-off-by: utkarshm <utkarshm@jfrog.com>
  • Loading branch information
utkarshm committed Jun 28, 2023
1 parent 812c77e commit 1785868
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 40 deletions.
77 changes: 40 additions & 37 deletions email.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ SMTPServer represents a SMTP Server
If authentication is CRAM-MD5 then the Password is the Secret
*/
type SMTPServer struct {
Authentication AuthType
Encryption Encryption
Username string
Password string
Expand Down Expand Up @@ -123,19 +122,21 @@ func (contentType ContentType) string() string {
return contentTypes[contentType]
}

type AuthType int
type AuthType string

const (
// AuthPlain implements the PLAIN authentication
AuthPlain AuthType = iota
AuthPlain AuthType = "PLAIN"
// AuthLogin implements the LOGIN authentication
AuthLogin
AuthLogin AuthType = "LOGIN"
// AuthCRAMMD5 implements the CRAM-MD5 authentication
AuthCRAMMD5
// AuthNone for SMTP servers without authentication
AuthNone
AuthCRAMMD5 AuthType = "CRAM-MD5"
)

func (at AuthType) String() string {
return string(at)
}

// NewMSG creates a new email. It uses UTF-8 by default. All charsets: http://webcheatsheet.com/HTML/character_sets_list.php
func NewMSG() *Email {
email := &Email{
Expand All @@ -152,7 +153,6 @@ func NewMSG() *Email {
// NewSMTPClient returns the client for send email
func NewSMTPClient() *SMTPServer {
server := &SMTPServer{
Authentication: AuthPlain,
Encryption: EncryptionNone,
ConnectTimeout: 10 * time.Second,
SendTimeout: 10 * time.Second,
Expand Down Expand Up @@ -717,7 +717,7 @@ func dial(host string, port string, encryption Encryption, config *tls.Config) (

// smtpConnect connects to the smtp server and starts TLS and passes auth
// if necessary
func smtpConnect(host, port, helo string, a auth, at AuthType, encryption Encryption, config *tls.Config) (*smtpClient, error) {
func smtpConnect(host, port, helo string, encryption Encryption, config *tls.Config) (*smtpClient, error) {
// connect to the mail server
c, err := dial(host, port, encryption, config)

Expand Down Expand Up @@ -746,42 +746,32 @@ func smtpConnect(host, port, helo string, a auth, at AuthType, encryption Encryp
}
}

// only pass authentication if defined
if at != AuthNone {
// pass the authentication if necessary
if a != nil {
if ok, _ := c.extension("AUTH"); ok {
if err = c.authenticate(a); err != nil {
c.close()
return nil, fmt.Errorf("Mail Error on Auth: %w", err)
}
}
}
}

return c, nil
}

// Connect returns the smtp client
func (server *SMTPServer) Connect() (*SMTPClient, error) {

var a auth

switch server.Authentication {
case AuthPlain:
func (server *SMTPServer) getAuth(a string) (auth, error) {
var afn auth
switch a {
case AuthPlain.String():
if server.Username != "" || server.Password != "" {
a = plainAuthfn("", server.Username, server.Password, server.Host)
afn = plainAuthfn("", server.Username, server.Password, server.Host)
}
case AuthLogin:
case AuthLogin.String():
if server.Username != "" || server.Password != "" {
a = loginAuthfn("", server.Username, server.Password, server.Host)
afn = loginAuthfn("", server.Username, server.Password, server.Host)
}
case AuthCRAMMD5:
case AuthCRAMMD5.String():
if server.Username != "" || server.Password != "" {
a = cramMD5Authfn(server.Username, server.Password)
afn = cramMD5Authfn(server.Username, server.Password)
}
default:
return nil, fmt.Errorf("Mail Error on determining auth type, %s is not supported", a)
}
return afn, nil
}

// Connect returns the smtp client
func (server *SMTPServer) Connect() (*SMTPClient, error) {
var smtpConnectChannel chan error
var c *smtpClient
var err error
Expand All @@ -795,7 +785,7 @@ func (server *SMTPServer) Connect() (*SMTPClient, error) {
if server.ConnectTimeout != 0 {
smtpConnectChannel = make(chan error, 2)
go func() {
c, err = smtpConnect(server.Host, fmt.Sprintf("%d", server.Port), server.Helo, a, server.Authentication, server.Encryption, tlsConfig)
c, err = smtpConnect(server.Host, fmt.Sprintf("%d", server.Port), server.Helo, server.Encryption, tlsConfig)
// send the result
smtpConnectChannel <- err
}()
Expand All @@ -810,12 +800,25 @@ func (server *SMTPServer) Connect() (*SMTPClient, error) {
}
} else {
// no ConnectTimeout, just fire the connect
c, err = smtpConnect(server.Host, fmt.Sprintf("%d", server.Port), server.Helo, a, server.Authentication, server.Encryption, tlsConfig)
c, err = smtpConnect(server.Host, fmt.Sprintf("%d", server.Port), server.Helo, server.Encryption, tlsConfig)
if err != nil {
return nil, err
}
}

// only pass authentication if defined
if server.Username != "" {
// pass the authentication if necessary
if ok, a := c.extension("AUTH"); ok {
afn, err := server.getAuth(a)
if err != nil {
return nil, err
}
if err = c.authenticate(afn); err != nil {
c.close()
return nil, fmt.Errorf("Mail Error on Auth: %w", err)
}
}
}
return &SMTPClient{
Client: c,
KeepAlive: server.KeepAlive,
Expand Down
3 changes: 0 additions & 3 deletions example/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ func TestSendMultipleEmails(t *testing.T) {
client.ConnectTimeout = connectTimeout
client.SendTimeout = sendTimeout

//For authentication you can use AuthPlain, AuthLogin or AuthCRAMMD5
client.Authentication = mail.AuthPlain

//KeepAlive true because the connection need to be open for multiple emails
//For avoid inactivity timeout, every 30 second you can send a NO OPERATION command to smtp client
//use smtpClient.Client.Noop() after 30 second of inactivity in this example
Expand Down

0 comments on commit 1785868

Please sign in to comment.