Compare commits

..

No commits in common. "8b6a7927efaabdb05102696b8925864a4d9e4f9e" and "eebbaa251391b0e710f131c60046e5ce53244be7" have entirely different histories.

5 changed files with 3294 additions and 4570 deletions

View file

@ -1448,32 +1448,20 @@ func TestClient_SetSMTPAuthCustom(t *testing.T) {
want string
}{
{"CRAM-MD5", smtp.CRAMMD5Auth("", ""), "*smtp.cramMD5Auth"},
{
"LOGIN", smtp.LoginAuth("", "", "", false),
"*smtp.loginAuth",
},
{
"LOGIN-NOENC", smtp.LoginAuth("", "", "", true),
"*smtp.loginAuth",
},
{
"PLAIN", smtp.PlainAuth("", "", "", "", false),
"*smtp.plainAuth",
},
{
"PLAIN-NOENC", smtp.PlainAuth("", "", "", "", true),
"*smtp.plainAuth",
},
{"LOGIN", smtp.LoginAuth("", "", "", false),
"*smtp.loginAuth"},
{"LOGIN-NOENC", smtp.LoginAuth("", "", "", true),
"*smtp.loginAuth"},
{"PLAIN", smtp.PlainAuth("", "", "", "", false),
"*smtp.plainAuth"},
{"PLAIN-NOENC", smtp.PlainAuth("", "", "", "", true),
"*smtp.plainAuth"},
{"SCRAM-SHA-1", smtp.ScramSHA1Auth("", ""), "*smtp.scramAuth"},
{
"SCRAM-SHA-1-PLUS", smtp.ScramSHA1PlusAuth("", "", nil),
"*smtp.scramAuth",
},
{"SCRAM-SHA-1-PLUS", smtp.ScramSHA1PlusAuth("", "", nil),
"*smtp.scramAuth"},
{"SCRAM-SHA-256", smtp.ScramSHA256Auth("", ""), "*smtp.scramAuth"},
{
"SCRAM-SHA-256-PLUS", smtp.ScramSHA256PlusAuth("", "", nil),
"*smtp.scramAuth",
},
{"SCRAM-SHA-256-PLUS", smtp.ScramSHA256PlusAuth("", "", nil),
"*smtp.scramAuth"},
{"XOAUTH2", smtp.XOAuth2Auth("", ""), "*smtp.xoauth2Auth"},
}
for _, tt := range tests {
@ -1495,6 +1483,7 @@ func TestClient_SetSMTPAuthCustom(t *testing.T) {
t.Errorf("failed to set custom SMTP auth, expected auth method type: %s, got: %s",
tt.want, authType)
}
})
}
})
@ -1796,7 +1785,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("connect should fail on HELO", func(t *testing.T) {
ctxFail, cancelFail := context.WithCancel(ctx)
ctxFail, cancelFail := context.WithCancel(context.Background())
defer cancelFail()
PortAdder.Add(1)
failServerPort := int(TestServerPortBase + PortAdder.Load())
@ -1831,7 +1820,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("connect with failing auth", func(t *testing.T) {
ctxAuth, cancelAuth := context.WithCancel(ctx)
ctxAuth, cancelAuth := context.WithCancel(context.Background())
defer cancelAuth()
PortAdder.Add(1)
authServerPort := int(TestServerPortBase + PortAdder.Load())
@ -1861,7 +1850,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("connect with STARTTLS", func(t *testing.T) {
ctxTLS, cancelTLS := context.WithCancel(ctx)
ctxTLS, cancelTLS := context.WithCancel(context.Background())
defer cancelTLS()
PortAdder.Add(1)
tlsServerPort := int(TestServerPortBase + PortAdder.Load())
@ -1891,7 +1880,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("connect with STARTTLS Opportunisticly", func(t *testing.T) {
ctxTLS, cancelTLS := context.WithCancel(ctx)
ctxTLS, cancelTLS := context.WithCancel(context.Background())
defer cancelTLS()
PortAdder.Add(1)
tlsServerPort := int(TestServerPortBase + PortAdder.Load())
@ -1921,7 +1910,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("connect with STARTTLS but fail", func(t *testing.T) {
ctxTLS, cancelTLS := context.WithCancel(ctx)
ctxTLS, cancelTLS := context.WithCancel(context.Background())
defer cancelTLS()
PortAdder.Add(1)
tlsServerPort := int(TestServerPortBase + PortAdder.Load())
@ -1952,7 +1941,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("want STARTTLS, but server does not support it", func(t *testing.T) {
ctxTLS, cancelTLS := context.WithCancel(ctx)
ctxTLS, cancelTLS := context.WithCancel(context.Background())
defer cancelTLS()
PortAdder.Add(1)
tlsServerPort := int(TestServerPortBase + PortAdder.Load())
@ -1982,7 +1971,7 @@ func TestClient_DialWithContext(t *testing.T) {
}
})
t.Run("connect with SSL", func(t *testing.T) {
ctxSSL, cancelSSL := context.WithCancel(ctx)
ctxSSL, cancelSSL := context.WithCancel(context.Background())
defer cancelSSL()
PortAdder.Add(1)
sslServerPort := int(TestServerPortBase + PortAdder.Load())
@ -2316,6 +2305,7 @@ func TestClient_auth(t *testing.T) {
if err := client.Close(); err != nil {
t.Errorf("failed to close client connection: %s", err)
}
})
t.Run(tt.name+" should fail", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
@ -2494,9 +2484,6 @@ func TestClient_Send(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2511,9 +2498,6 @@ func TestClient_Send(t *testing.T) {
})
t.Run("send with no connection should fail", func(t *testing.T) {
client, err := NewClient(DefaultHost)
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.Send(message); err == nil {
t.Errorf("client should have failed to send email with no connection")
}
@ -2546,9 +2530,6 @@ func TestClient_Send(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2603,9 +2584,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2642,9 +2620,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2683,9 +2658,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2729,9 +2701,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2775,9 +2744,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2821,9 +2787,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS), WithDSN())
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2860,9 +2823,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2907,9 +2867,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -2954,9 +2911,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -3000,9 +2954,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -3046,9 +2997,6 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -3092,9 +3040,6 @@ func TestClient_checkConn(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -3129,9 +3074,6 @@ func TestClient_checkConn(t *testing.T) {
t.Cleanup(cancelDial)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to test server: %s", err)
}
@ -3149,9 +3091,6 @@ func TestClient_checkConn(t *testing.T) {
})
t.Run("connection should fail on no connection", func(t *testing.T) {
client, err := NewClient(DefaultHost)
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.checkConn(); err == nil {
t.Errorf("client should have failed on connection check")
}
@ -3480,14 +3419,11 @@ func simpleSMTPServer(ctx context.Context, t *testing.T, props *serverProps) err
if props.SSLListener {
keypair, err := tls.X509KeyPair(localhostCert, localhostKey)
if err != nil {
return fmt.Errorf("failed to read TLS keypair: %w", err)
return fmt.Errorf("failed to read TLS keypair: %s", err)
}
tlsConfig := &tls.Config{Certificates: []tls.Certificate{keypair}}
listener, err = tls.Listen(TestServerProto, fmt.Sprintf("%s:%d", TestServerAddr, props.ListenPort),
tlsConfig)
if err != nil {
t.Fatalf("failed to create TLS listener: %s", err)
}
} else {
listener, err = net.Listen(TestServerProto, fmt.Sprintf("%s:%d", TestServerAddr, props.ListenPort))
}
@ -3568,6 +3504,7 @@ func handleTestServerConnection(connection net.Conn, t *testing.T, props *server
break
}
writeLine("250-localhost.localdomain\r\n" + props.FeatureSet)
break
case strings.HasPrefix(data, "MAIL FROM:"):
if props.FailOnMailFrom {
writeLine("500 5.5.2 Error: fail on MAIL FROM")

View file

@ -901,8 +901,7 @@ func TestEMLToMsgFromReader(t *testing.T) {
}{
{
"RFC5322 A1.1 example mail", exampleMailRFC5322A11, EncodingUSASCII,
"Saying Hello",
},
"Saying Hello"},
{
"Plain text no encoding (7bit)", exampleMailPlain7Bit, EncodingUSASCII,
"Example mail // plain text without encoding",
@ -1159,6 +1158,7 @@ func TestEMLToMsgFromFile(t *testing.T) {
t.Errorf("failed to parse EML string: want subject %s, got %s", "Saying Hello",
gotSubject[0])
}
})
t.Run("EMLToMsgFromFile fails on file not found", func(t *testing.T) {
if _, err := EMLToMsgFromFile("testdata/not-existing.eml"); err == nil {

View file

@ -8,13 +8,69 @@ import (
"testing"
)
var (
genHeaderTests = []struct {
// TestImportance_StringFuncs tests the different string method of the Importance object
func TestImportance_StringFuncs(t *testing.T) {
tests := []struct {
name string
header Header
imp Importance
wantns string
xprio string
want string
}{
{"Header: Content-Description", HeaderContentDescription, "Content-Description"},
{"Importance: Non-Urgent", ImportanceNonUrgent, "0", "5", "non-urgent"},
{"Importance: Low", ImportanceLow, "0", "5", "low"},
{"Importance: Normal", ImportanceNormal, "", "", ""},
{"Importance: High", ImportanceHigh, "1", "1", "high"},
{"Importance: Urgent", ImportanceUrgent, "1", "1", "urgent"},
{"Importance: Unknown", 9, "", "", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.imp.NumString() != tt.wantns {
t.Errorf("wrong number string for Importance returned. Expected: %s, got: %s",
tt.wantns, tt.imp.NumString())
}
if tt.imp.XPrioString() != tt.xprio {
t.Errorf("wrong x-prio string for Importance returned. Expected: %s, got: %s",
tt.xprio, tt.imp.XPrioString())
}
if tt.imp.String() != tt.want {
t.Errorf("wrong string for Importance returned. Expected: %s, got: %s",
tt.want, tt.imp.String())
}
})
}
}
// TestAddrHeader_String tests the string method of the AddrHeader object
func TestAddrHeader_String(t *testing.T) {
tests := []struct {
name string
ah AddrHeader
want string
}{
{"Address header: From", HeaderFrom, "From"},
{"Address header: To", HeaderTo, "To"},
{"Address header: Cc", HeaderCc, "Cc"},
{"Address header: Bcc", HeaderBcc, "Bcc"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.ah.String() != tt.want {
t.Errorf("wrong string for AddrHeader returned. Expected: %s, got: %s",
tt.want, tt.ah.String())
}
})
}
}
// TestHeader_String tests the string method of the Header object
func TestHeader_String(t *testing.T) {
tests := []struct {
name string
h Header
want string
}{
{"Header: Content-Disposition", HeaderContentDisposition, "Content-Disposition"},
{"Header: Content-ID", HeaderContentID, "Content-ID"},
{"Header: Content-Language", HeaderContentLang, "Content-Language"},
@ -22,10 +78,6 @@ var (
{"Header: Content-Transfer-Encoding", HeaderContentTransferEnc, "Content-Transfer-Encoding"},
{"Header: Content-Type", HeaderContentType, "Content-Type"},
{"Header: Date", HeaderDate, "Date"},
{
"Header: Disposition-Notification-To", HeaderDispositionNotificationTo,
"Disposition-Notification-To",
},
{"Header: Importance", HeaderImportance, "Importance"},
{"Header: In-Reply-To", HeaderInReplyTo, "In-Reply-To"},
{"Header: List-Unsubscribe", HeaderListUnsubscribe, "List-Unsubscribe"},
@ -35,90 +87,19 @@ var (
{"Header: Organization", HeaderOrganization, "Organization"},
{"Header: Precedence", HeaderPrecedence, "Precedence"},
{"Header: Priority", HeaderPriority, "Priority"},
{"Header: References", HeaderReferences, "References"},
{"Header: HeaderReferences", HeaderReferences, "References"},
{"Header: Reply-To", HeaderReplyTo, "Reply-To"},
{"Header: Subject", HeaderSubject, "Subject"},
{"Header: User-Agent", HeaderUserAgent, "User-Agent"},
{"Header: X-Auto-Response-Suppress", HeaderXAutoResponseSuppress, "X-Auto-Response-Suppress"},
{"Header: X-Mailer", HeaderXMailer, "X-Mailer"},
{"Header: X-MSMail-Priority", HeaderXMSMailPriority, "X-MSMail-Priority"},
{"Header: X-Priority", HeaderXPriority, "X-Priority"},
}
addrHeaderTests = []struct {
name string
header AddrHeader
want string
}{
{"From", HeaderFrom, "From"},
{"To", HeaderTo, "To"},
{"Cc", HeaderCc, "Cc"},
{"Bcc", HeaderBcc, "Bcc"},
}
)
func TestImportance_Stringer(t *testing.T) {
tests := []struct {
name string
imp Importance
wantnum string
xprio string
want string
}{
{"Non-Urgent", ImportanceNonUrgent, "0", "5", "non-urgent"},
{"Low", ImportanceLow, "0", "5", "low"},
{"Normal", ImportanceNormal, "", "", ""},
{"High", ImportanceHigh, "1", "1", "high"},
{"Urgent", ImportanceUrgent, "1", "1", "urgent"},
{"Unknown", 9, "", "", ""},
}
t.Run("String", func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.imp.String() != tt.want {
t.Errorf("wrong string for Importance returned. Expected: %s, got: %s", tt.want, tt.imp.String())
}
})
}
})
t.Run("NumString", func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.imp.NumString() != tt.wantnum {
t.Errorf("wrong number string for Importance returned. Expected: %s, got: %s", tt.wantnum,
tt.imp.NumString())
}
})
}
})
t.Run("XPrioString", func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.imp.XPrioString() != tt.xprio {
t.Errorf("wrong x-prio string for Importance returned. Expected: %s, got: %s", tt.xprio,
tt.imp.XPrioString())
}
})
}
})
}
func TestAddrHeader_Stringer(t *testing.T) {
for _, tt := range addrHeaderTests {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.header.String() != tt.want {
t.Errorf("wrong string for AddrHeader returned. Expected: %s, got: %s",
tt.want, tt.header.String())
}
})
}
}
func TestHeader_Stringer(t *testing.T) {
for _, tt := range genHeaderTests {
t.Run(tt.name, func(t *testing.T) {
if tt.header.String() != tt.want {
if tt.h.String() != tt.want {
t.Errorf("wrong string for Header returned. Expected: %s, got: %s",
tt.want, tt.header.String())
tt.want, tt.h.String())
}
})
}

12
msg.go
View file

@ -583,9 +583,6 @@ func (m *Msg) SetAddrHeader(header AddrHeader, values ...string) error {
// References:
// - https://datatracker.ietf.org/doc/html/rfc5322#section-3.4
func (m *Msg) SetAddrHeaderIgnoreInvalid(header AddrHeader, values ...string) {
if m.addrHeader == nil {
m.addrHeader = make(map[AddrHeader][]*mail.Address)
}
var addresses []*mail.Address
for _, addrVal := range values {
address, err := mail.ParseAddress(m.encodeString(addrVal))
@ -594,14 +591,7 @@ func (m *Msg) SetAddrHeaderIgnoreInvalid(header AddrHeader, values ...string) {
}
addresses = append(addresses, address)
}
switch header {
case HeaderFrom:
if len(addresses) > 0 {
m.addrHeader[header] = []*mail.Address{addresses[0]}
}
default:
m.addrHeader[header] = addresses
}
m.addrHeader[header] = addresses
}
// EnvelopeFrom sets the envelope from address for the Msg.

File diff suppressed because it is too large Load diff