From 567276d75d46e186f7fda0c192a4a694446525aa Mon Sep 17 00:00:00 2001 From: James Elliott Date: Mon, 26 Dec 2022 23:59:42 +1100 Subject: [PATCH] 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. --- client.go | 20 ++++++++++++++++++-- client_test.go | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index e988d54..d39c72c 100644 --- a/client.go +++ b/client.go @@ -96,6 +96,9 @@ type Client struct { // enc indicates if a Client connection is encrypted or not enc bool + // noNoop indicates the Noop is to be skipped + noNoop bool + // HELO/EHLO string for the greeting the target SMTP server 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 func (c *Client) TLSPolicy() string { return c.tlspolicy.String() @@ -515,9 +527,13 @@ func (c *Client) checkConn() error { if c.co == nil { return ErrNoActiveConnection } - if err := c.sc.Noop(); err != nil { - return ErrNoActiveConnection + + if !c.noNoop { + if err := c.sc.Noop(); err != nil { + return ErrNoActiveConnection + } } + if err := c.co.SetDeadline(time.Now().Add(c.cto)); err != nil { return ErrDeadlineExtendFailed } diff --git a/client_test.go b/client_test.go index 3399762..f674d4f 100644 --- a/client_test.go +++ b/client_test.go @@ -103,6 +103,8 @@ func TestNewClientWithOptions(t *testing.T) { {"WithDSNMailReturnType() wrong option", WithDSNMailReturnType("FAIL"), true}, {"WithDSNRcptNotifyType()", WithDSNRcptNotifyType(DSNRcptNotifySuccess), false}, {"WithDSNRcptNotifyType() wrong option", WithDSNRcptNotifyType("FAIL"), true}, + {"WithoutNoop()", WithoutNoop(), false}, + { "WithDSNRcptNotifyType() NEVER combination", 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 func TestSetSMTPAuthCustom(t *testing.T) { tests := []struct {