From aed71397c047021c7a1f83ece153dc86e1dcbd28 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Sun, 11 Sep 2022 21:07:15 +0200 Subject: [PATCH] Implemented DSNs as described in RFC 1891 - Added test coverage for the WithDSN* methods - Updated README.md accordingly --- README.md | 2 +- client_test.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ec5605..53039b1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Some of the features of this library: * [X] Support for attachments and inline embeds (from file system, `io.Reader` or `embed.FS`) * [X] Support for different encodings * [X] Support sending mails via a local sendmail command -* [X] Support for requestng MDNs +* [X] Support for requestng MDNs (RFC 8098) and DSNs (RFC 1891) * [X] Message object satisfies `io.WriteTo` and `io.Reader` interfaces * [X] Support for Go's `html/template` and `text/template` (as message body, alternative part or attachment/emebed) * [X] Output to file support which allows storing mail messages as e. g. `.eml` files to disk to open them in a MUA diff --git a/client_test.go b/client_test.go index 8b67f88..f47ef4f 100644 --- a/client_test.go +++ b/client_test.go @@ -94,6 +94,13 @@ func TestNewClientWithOptions(t *testing.T) { false}, {"WithUsername()", WithUsername("test"), false}, {"WithPassword()", WithPassword("test"), false}, + {"WithDSN()", WithDSN(), false}, + {"WithDSNMailReturnType()", WithDSNMailReturnType(DSNMailReturnFull), false}, + {"WithDSNMailReturnType() wrong option", WithDSNMailReturnType("FAIL"), true}, + {"WithDSNRcptNotifyType()", WithDSNRcptNotifyType(DSNRcptNotifySuccess), false}, + {"WithDSNRcptNotifyType() wrong option", WithDSNRcptNotifyType("FAIL"), true}, + {"WithDSNRcptNotifyType() NEVER combination", + WithDSNRcptNotifyType(DSNRcptNotifySuccess, DSNRcptNotifyNever), true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -367,6 +374,87 @@ func TestSetSMTPAuth(t *testing.T) { } } +// TestWithDSN tests the WithDSN method for the Client object +func TestWithDSN(t *testing.T) { + c, err := NewClient(DefaultHost, WithDSN()) + if err != nil { + t.Errorf("failed to create new client: %s", err) + return + } + if !c.dsn { + t.Errorf("WithDSN failed. c.dsn expected to be: %t, got: %t", true, c.dsn) + } + if c.dsnmrtype != DSNMailReturnFull { + t.Errorf("WithDSN failed. c.dsnmrtype expected to be: %s, got: %s", DSNMailReturnFull, + c.dsnmrtype) + } + if c.dsnrntype[0] != string(DSNRcptNotifyFailure) { + t.Errorf("WithDSN failed. c.dsnrntype[0] expected to be: %s, got: %s", DSNRcptNotifyFailure, + c.dsnrntype[0]) + } + if c.dsnrntype[1] != string(DSNRcptNotifySuccess) { + t.Errorf("WithDSN failed. c.dsnrntype[1] expected to be: %s, got: %s", DSNRcptNotifySuccess, + c.dsnrntype[1]) + } +} + +// TestWithDSNMailReturnType tests the WithDSNMailReturnType method for the Client object +func TestWithDSNMailReturnType(t *testing.T) { + tests := []struct { + name string + value DSNMailReturnOption + want string + sf bool + }{ + {"WithDSNMailReturnType: FULL", DSNMailReturnFull, "FULL", false}, + {"WithDSNMailReturnType: HDRS", DSNMailReturnHeadersOnly, "HDRS", false}, + {"WithDSNMailReturnType: INVALID", "INVALID", "", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := NewClient(DefaultHost, WithDSNMailReturnType(tt.value)) + if err != nil && !tt.sf { + t.Errorf("failed to create new client: %s", err) + return + } + if string(c.dsnmrtype) != tt.want { + t.Errorf("WithDSNMailReturnType failed. Expected %s, got: %s", tt.want, string(c.dsnmrtype)) + } + }) + } +} + +// TestWithDSNRcptNotifyType tests the WithDSNRcptNotifyType method for the Client object +func TestWithDSNRcptNotifyType(t *testing.T) { + tests := []struct { + name string + value DSNRcptNotifyOption + want string + sf bool + }{ + {"WithDSNRcptNotifyType: NEVER", DSNRcptNotifyNever, "NEVER", false}, + {"WithDSNRcptNotifyType: SUCCESS", DSNRcptNotifySuccess, "SUCCESS", false}, + {"WithDSNRcptNotifyType: FAILURE", DSNRcptNotifyFailure, "FAILURE", false}, + {"WithDSNRcptNotifyType: DELAY", DSNRcptNotifyDelay, "DELAY", false}, + {"WithDSNRcptNotifyType: INVALID", "INVALID", "", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := NewClient(DefaultHost, WithDSNRcptNotifyType(tt.value)) + if err != nil && !tt.sf { + t.Errorf("failed to create new client: %s", err) + return + } + if len(c.dsnrntype) <= 0 && !tt.sf { + t.Errorf("WithDSNRcptNotifyType failed. Expected at least one DSNRNType but got none") + } + if !tt.sf && c.dsnrntype[0] != tt.want { + t.Errorf("WithDSNRcptNotifyType failed. Expected %s, got: %s", tt.want, c.dsnrntype[0]) + } + }) + } +} + // TestSetSMTPAuthCustom tests the SetSMTPAuthCustom method for the Client object func TestSetSMTPAuthCustom(t *testing.T) { tests := []struct {