mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-15 02:12:55 +01:00
Merge pull request #335 from wneessen/bug/332_server-does-not-support-smtp-auth-error-when-using-localhost-in-v050
Add default SMTP authentication type to NewClient
This commit is contained in:
commit
e854b2192f
3 changed files with 94 additions and 10 deletions
2
auth.go
2
auth.go
|
@ -47,7 +47,7 @@ const (
|
||||||
// SMTPAuthNoAuth is equivalent to performing no authentication at all. It is a convenience
|
// SMTPAuthNoAuth is equivalent to performing no authentication at all. It is a convenience
|
||||||
// option and should not be used. Instead, for mail servers that do no support/require
|
// option and should not be used. Instead, for mail servers that do no support/require
|
||||||
// authentication, the Client should not be passed the WithSMTPAuth option at all.
|
// authentication, the Client should not be passed the WithSMTPAuth option at all.
|
||||||
SMTPAuthNoAuth SMTPAuthType = ""
|
SMTPAuthNoAuth SMTPAuthType = "NOAUTH"
|
||||||
|
|
||||||
// SMTPAuthPlain is the "PLAIN" authentication mechanism as described in RFC 4616.
|
// SMTPAuthPlain is the "PLAIN" authentication mechanism as described in RFC 4616.
|
||||||
//
|
//
|
||||||
|
|
27
client.go
27
client.go
|
@ -259,11 +259,12 @@ var (
|
||||||
// - An error if any critical default values are missing or options fail to apply.
|
// - An error if any critical default values are missing or options fail to apply.
|
||||||
func NewClient(host string, opts ...Option) (*Client, error) {
|
func NewClient(host string, opts ...Option) (*Client, error) {
|
||||||
c := &Client{
|
c := &Client{
|
||||||
connTimeout: DefaultTimeout,
|
smtpAuthType: SMTPAuthNoAuth,
|
||||||
host: host,
|
connTimeout: DefaultTimeout,
|
||||||
port: DefaultPort,
|
host: host,
|
||||||
tlsconfig: &tls.Config{ServerName: host, MinVersion: DefaultTLSMinVersion},
|
port: DefaultPort,
|
||||||
tlspolicy: DefaultTLSPolicy,
|
tlsconfig: &tls.Config{ServerName: host, MinVersion: DefaultTLSMinVersion},
|
||||||
|
tlspolicy: DefaultTLSPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default HELO/EHLO hostname
|
// Set default HELO/EHLO hostname
|
||||||
|
@ -1064,9 +1065,16 @@ func (c *Client) DialAndSendWithContext(ctx context.Context, messages ...*Msg) e
|
||||||
// determines the supported authentication methods, and applies the appropriate authentication
|
// determines the supported authentication methods, and applies the appropriate authentication
|
||||||
// type. An error is returned if authentication fails.
|
// type. An error is returned if authentication fails.
|
||||||
//
|
//
|
||||||
// This method first verifies the connection to the SMTP server. If no custom authentication
|
// By default NewClient sets the SMTP authentication type to SMTPAuthNoAuth, meaning, that no
|
||||||
// mechanism is provided, it checks which authentication methods are supported by the server.
|
// SMTP authentication will be performed. If the user makes use of SetSMTPAuth or initialzes the
|
||||||
// Based on the configured SMTPAuthType, it sets up the appropriate authentication mechanism.
|
// client with WithSMTPAuth, the SMTP authentication type will be set in the Client, forcing
|
||||||
|
// this method to determine if the server supports the selected authentication method and
|
||||||
|
// assigning the corresponding smtp.Auth function to it.
|
||||||
|
//
|
||||||
|
// If the user set a custom SMTP authentication function using SetSMTPAuthCustom or
|
||||||
|
// WithSMTPAuthCustom, we will not perform any detection and assignment logic and will trust
|
||||||
|
// the user with their provided smtp.Auth function.
|
||||||
|
//
|
||||||
// Finally, it attempts to authenticate the client using the selected method.
|
// Finally, it attempts to authenticate the client using the selected method.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
|
@ -1076,7 +1084,8 @@ func (c *Client) auth() error {
|
||||||
if err := c.checkConn(); err != nil {
|
if err := c.checkConn(); err != nil {
|
||||||
return fmt.Errorf("failed to authenticate: %w", err)
|
return fmt.Errorf("failed to authenticate: %w", err)
|
||||||
}
|
}
|
||||||
if c.smtpAuth == nil && c.smtpAuthType != SMTPAuthCustom {
|
|
||||||
|
if c.smtpAuth == nil && c.smtpAuthType != SMTPAuthNoAuth {
|
||||||
hasSMTPAuth, smtpAuthType := c.smtpClient.Extension("AUTH")
|
hasSMTPAuth, smtpAuthType := c.smtpClient.Extension("AUTH")
|
||||||
if !hasSMTPAuth {
|
if !hasSMTPAuth {
|
||||||
return fmt.Errorf("server does not support SMTP AUTH")
|
return fmt.Errorf("server does not support SMTP AUTH")
|
||||||
|
|
|
@ -1180,6 +1180,81 @@ func TestClient_Send_withBrokenRecipient(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClient_DialWithContext_switchAuth(t *testing.T) {
|
||||||
|
if os.Getenv("TEST_ALLOW_SEND") == "" {
|
||||||
|
t.Skipf("TEST_ALLOW_SEND is not set. Skipping mail sending test")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We start with no auth explicitly set
|
||||||
|
client, err := NewClient(
|
||||||
|
os.Getenv("TEST_HOST"),
|
||||||
|
WithTLSPortPolicy(TLSMandatory),
|
||||||
|
)
|
||||||
|
defer func() {
|
||||||
|
_ = client.Close()
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create client: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = client.DialWithContext(context.Background()); err != nil {
|
||||||
|
t.Errorf("failed to dial to sending server: %s", err)
|
||||||
|
}
|
||||||
|
if err = client.Close(); err != nil {
|
||||||
|
t.Errorf("failed to close client connection: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We switch to LOGIN auth, which the server supports
|
||||||
|
client.SetSMTPAuth(SMTPAuthLogin)
|
||||||
|
client.SetUsername(os.Getenv("TEST_SMTPAUTH_USER"))
|
||||||
|
client.SetPassword(os.Getenv("TEST_SMTPAUTH_PASS"))
|
||||||
|
if err = client.DialWithContext(context.Background()); err != nil {
|
||||||
|
t.Errorf("failed to dial to sending server: %s", err)
|
||||||
|
}
|
||||||
|
if err = client.Close(); err != nil {
|
||||||
|
t.Errorf("failed to close client connection: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We switch to CRAM-MD5, which the server does not support - error expected
|
||||||
|
client.SetSMTPAuth(SMTPAuthCramMD5)
|
||||||
|
if err = client.DialWithContext(context.Background()); err == nil {
|
||||||
|
t.Errorf("expected error when dialing with unsupported auth mechanism, got nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !errors.Is(err, ErrCramMD5AuthNotSupported) {
|
||||||
|
t.Errorf("expected dial error: %s, but got: %s", ErrCramMD5AuthNotSupported, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We switch to CUSTOM by providing PLAIN auth as function - the server supports this
|
||||||
|
client.SetSMTPAuthCustom(smtp.PlainAuth("", os.Getenv("TEST_SMTPAUTH_USER"),
|
||||||
|
os.Getenv("TEST_SMTPAUTH_PASS"), os.Getenv("TEST_HOST")))
|
||||||
|
if client.smtpAuthType != SMTPAuthCustom {
|
||||||
|
t.Errorf("expected auth type to be Custom, got: %s", client.smtpAuthType)
|
||||||
|
}
|
||||||
|
if err = client.DialWithContext(context.Background()); err != nil {
|
||||||
|
t.Errorf("failed to dial to sending server: %s", err)
|
||||||
|
}
|
||||||
|
if err = client.Close(); err != nil {
|
||||||
|
t.Errorf("failed to close client connection: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We switch back to explicit no authenticaiton
|
||||||
|
client.SetSMTPAuth(SMTPAuthNoAuth)
|
||||||
|
if err = client.DialWithContext(context.Background()); err != nil {
|
||||||
|
t.Errorf("failed to dial to sending server: %s", err)
|
||||||
|
}
|
||||||
|
if err = client.Close(); err != nil {
|
||||||
|
t.Errorf("failed to close client connection: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally we set an empty string as SMTPAuthType and expect and error. This way we can
|
||||||
|
// verify that we do not accidentaly skip authentication with an empty string SMTPAuthType
|
||||||
|
client.SetSMTPAuth("")
|
||||||
|
if err = client.DialWithContext(context.Background()); err == nil {
|
||||||
|
t.Errorf("expected error when dialing with empty auth mechanism, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestClient_auth tests the Dial(), Send() and Close() method of Client with broken settings
|
// TestClient_auth tests the Dial(), Send() and Close() method of Client with broken settings
|
||||||
func TestClient_auth(t *testing.T) {
|
func TestClient_auth(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
|
Loading…
Reference in a new issue