feat: without noop option

This allows disabling the Noop command during the dial. This is useful for servers which delay potentially unwanted clients when they perform commands other than AUTH.
This commit is contained in:
James Elliott 2022-12-26 23:59:42 +11:00
parent 6a7d49f1b6
commit 567276d75d
No known key found for this signature in database
GPG key ID: 0F1C4A096E857E49
2 changed files with 41 additions and 2 deletions

View file

@ -96,6 +96,9 @@ type Client struct {
// enc indicates if a Client connection is encrypted or not // enc indicates if a Client connection is encrypted or not
enc bool enc bool
// noNoop indicates the Noop is to be skipped
noNoop bool
// HELO/EHLO string for the greeting the target SMTP server // HELO/EHLO string for the greeting the target SMTP server
helo string helo string
@ -366,6 +369,15 @@ func WithDSNRcptNotifyType(rno ...DSNRcptNotifyOption) Option {
} }
} }
// WithoutNoop disables the Client Noop check during connections. This is primarily for servers which delay responses
// to SMTP commands that are not the AUTH command. For example Microsoft Exchange's Tarpit.
func WithoutNoop() Option {
return func(c *Client) error {
c.noNoop = true
return nil
}
}
// TLSPolicy returns the currently set TLSPolicy as string // TLSPolicy returns the currently set TLSPolicy as string
func (c *Client) TLSPolicy() string { func (c *Client) TLSPolicy() string {
return c.tlspolicy.String() return c.tlspolicy.String()
@ -515,9 +527,13 @@ func (c *Client) checkConn() error {
if c.co == nil { if c.co == nil {
return ErrNoActiveConnection return ErrNoActiveConnection
} }
if !c.noNoop {
if err := c.sc.Noop(); err != nil { if err := c.sc.Noop(); err != nil {
return ErrNoActiveConnection return ErrNoActiveConnection
} }
}
if err := c.co.SetDeadline(time.Now().Add(c.cto)); err != nil { if err := c.co.SetDeadline(time.Now().Add(c.cto)); err != nil {
return ErrDeadlineExtendFailed return ErrDeadlineExtendFailed
} }

View file

@ -103,6 +103,8 @@ func TestNewClientWithOptions(t *testing.T) {
{"WithDSNMailReturnType() wrong option", WithDSNMailReturnType("FAIL"), true}, {"WithDSNMailReturnType() wrong option", WithDSNMailReturnType("FAIL"), true},
{"WithDSNRcptNotifyType()", WithDSNRcptNotifyType(DSNRcptNotifySuccess), false}, {"WithDSNRcptNotifyType()", WithDSNRcptNotifyType(DSNRcptNotifySuccess), false},
{"WithDSNRcptNotifyType() wrong option", WithDSNRcptNotifyType("FAIL"), true}, {"WithDSNRcptNotifyType() wrong option", WithDSNRcptNotifyType("FAIL"), true},
{"WithoutNoop()", WithoutNoop(), false},
{ {
"WithDSNRcptNotifyType() NEVER combination", "WithDSNRcptNotifyType() NEVER combination",
WithDSNRcptNotifyType(DSNRcptNotifySuccess, DSNRcptNotifyNever), true, WithDSNRcptNotifyType(DSNRcptNotifySuccess, DSNRcptNotifyNever), true,
@ -461,6 +463,27 @@ func TestWithDSNRcptNotifyType(t *testing.T) {
} }
} }
// TestWithoutNoop tests the WithoutNoop method for the Client object
func TestWithoutNoop(t *testing.T) {
c, err := NewClient(DefaultHost, WithoutNoop())
if err != nil {
t.Errorf("failed to create new client: %s", err)
return
}
if !c.noNoop {
t.Errorf("WithoutNoop failed. c.noNoop expected to be: %t, got: %t", true, c.noNoop)
}
c, err = NewClient(DefaultHost)
if err != nil {
t.Errorf("failed to create new client: %s", err)
return
}
if c.noNoop {
t.Errorf("WithoutNoop failed. c.noNoop expected to be: %t, got: %t", false, c.noNoop)
}
}
// TestSetSMTPAuthCustom tests the SetSMTPAuthCustom method for the Client object // TestSetSMTPAuthCustom tests the SetSMTPAuthCustom method for the Client object
func TestSetSMTPAuthCustom(t *testing.T) { func TestSetSMTPAuthCustom(t *testing.T) {
tests := []struct { tests := []struct {