mirror of
https://github.com/wneessen/go-mail.git
synced 2024-12-22 18:50:37 +01:00
Merge pull request #157 from wneessen/nil_checks
Eleminate potential null pointer exceptions
This commit is contained in:
commit
d5b410dca4
7 changed files with 93 additions and 37 deletions
|
@ -511,10 +511,15 @@ func (c *Client) DialWithContext(pc context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
c.sc, err = smtp.NewClient(c.co, c.host)
|
||||
sc, err := smtp.NewClient(c.co, c.host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sc == nil {
|
||||
return fmt.Errorf("SMTP client is nil")
|
||||
}
|
||||
c.sc = sc
|
||||
|
||||
if c.l != nil {
|
||||
c.sc.SetLogger(c.l)
|
||||
}
|
||||
|
|
27
msg.go
27
msg.go
|
@ -287,7 +287,9 @@ func (m *Msg) SetAddrHeader(h AddrHeader, v ...string) error {
|
|||
}
|
||||
switch h {
|
||||
case HeaderFrom:
|
||||
m.addrHeader[h] = []*mail.Address{al[0]}
|
||||
if len(al) > 0 {
|
||||
m.addrHeader[h] = []*mail.Address{al[0]}
|
||||
}
|
||||
default:
|
||||
m.addrHeader[h] = al
|
||||
}
|
||||
|
@ -518,7 +520,9 @@ func (m *Msg) RequestMDNTo(t ...string) error {
|
|||
}
|
||||
tl = append(tl, a.String())
|
||||
}
|
||||
m.genHeader[HeaderDispositionNotificationTo] = tl
|
||||
if _, ok := m.genHeader[HeaderDispositionNotificationTo]; ok {
|
||||
m.genHeader[HeaderDispositionNotificationTo] = tl
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -539,7 +543,9 @@ func (m *Msg) RequestMDNAddTo(t string) error {
|
|||
var tl []string
|
||||
tl = append(tl, m.genHeader[HeaderDispositionNotificationTo]...)
|
||||
tl = append(tl, a.String())
|
||||
m.genHeader[HeaderDispositionNotificationTo] = tl
|
||||
if _, ok := m.genHeader[HeaderDispositionNotificationTo]; ok {
|
||||
m.genHeader[HeaderDispositionNotificationTo] = tl
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -591,8 +597,8 @@ func (m *Msg) GetAddrHeader(h AddrHeader) []*mail.Address {
|
|||
// GetAddrHeaderString returns the address string of the requested address header of the Msg
|
||||
func (m *Msg) GetAddrHeaderString(h AddrHeader) []string {
|
||||
var al []string
|
||||
for i := range m.addrHeader[h] {
|
||||
al = append(al, m.addrHeader[h][i].String())
|
||||
for _, mh := range m.addrHeader[h] {
|
||||
al = append(al, mh.String())
|
||||
}
|
||||
return al
|
||||
}
|
||||
|
@ -999,9 +1005,12 @@ func (m *Msg) WriteToSendmailWithContext(ctx context.Context, sp string, a ...st
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to set STDIN pipe: %w", err)
|
||||
}
|
||||
if se == nil || si == nil {
|
||||
return fmt.Errorf("received nil for STDERR or STDIN pipe")
|
||||
}
|
||||
|
||||
// Start the execution and write to STDIN
|
||||
if err := ec.Start(); err != nil {
|
||||
if err = ec.Start(); err != nil {
|
||||
return fmt.Errorf("could not start sendmail execution: %w", err)
|
||||
}
|
||||
_, err = m.WriteTo(si)
|
||||
|
@ -1012,7 +1021,7 @@ func (m *Msg) WriteToSendmailWithContext(ctx context.Context, sp string, a ...st
|
|||
}
|
||||
|
||||
// Close STDIN and wait for completion or cancellation of the sendmail executable
|
||||
if err := si.Close(); err != nil {
|
||||
if err = si.Close(); err != nil {
|
||||
return fmt.Errorf("failed to close STDIN pipe: %w", err)
|
||||
}
|
||||
|
||||
|
@ -1025,7 +1034,7 @@ func (m *Msg) WriteToSendmailWithContext(ctx context.Context, sp string, a ...st
|
|||
return fmt.Errorf("sendmail command failed: %s", string(serr))
|
||||
}
|
||||
|
||||
if err := ec.Wait(); err != nil {
|
||||
if err = ec.Wait(); err != nil {
|
||||
return fmt.Errorf("sendmail command execution failed: %w", err)
|
||||
}
|
||||
|
||||
|
@ -1069,7 +1078,7 @@ func (m *Msg) HasSendError() bool {
|
|||
// corresponding error was of temporary nature and should be retried later
|
||||
func (m *Msg) SendErrorIsTemp() bool {
|
||||
var e *SendError
|
||||
if errors.As(m.sendError, &e) {
|
||||
if errors.As(m.sendError, &e) && e != nil {
|
||||
return e.isTemp
|
||||
}
|
||||
return false
|
||||
|
|
66
msg_test.go
66
msg_test.go
|
@ -216,6 +216,9 @@ func (mw uppercaseMiddleware) Handle(m *Msg) *Msg {
|
|||
if !ok {
|
||||
fmt.Println("can't find the subject header")
|
||||
}
|
||||
if s == nil || len(s) < 1 {
|
||||
s = append(s, "")
|
||||
}
|
||||
m.Subject(strings.ToUpper(s[0]))
|
||||
return m
|
||||
}
|
||||
|
@ -231,6 +234,9 @@ func (mw encodeMiddleware) Handle(m *Msg) *Msg {
|
|||
if !ok {
|
||||
fmt.Println("can't find the subject header")
|
||||
}
|
||||
if s == nil || len(s) < 1 {
|
||||
s = append(s, "")
|
||||
}
|
||||
m.Subject(strings.Replace(s[0], "a", "@", -1))
|
||||
return m
|
||||
}
|
||||
|
@ -752,7 +758,9 @@ func TestMsg_SetMessageIDWithValue(t *testing.T) {
|
|||
t.Errorf("SetMessageID() failed. Expected value, got: empty")
|
||||
return
|
||||
}
|
||||
m.genHeader[HeaderMessageID] = nil
|
||||
if _, ok := m.genHeader[HeaderMessageID]; ok {
|
||||
m.genHeader[HeaderMessageID] = nil
|
||||
}
|
||||
v := "This.is.a.message.id"
|
||||
vf := "<This.is.a.message.id>"
|
||||
m.SetMessageIDWithValue(v)
|
||||
|
@ -773,7 +781,9 @@ func TestMsg_SetMessageIDRandomness(t *testing.T) {
|
|||
m := NewMsg()
|
||||
m.SetMessageID()
|
||||
mid := m.GetGenHeader(HeaderMessageID)
|
||||
mids = append(mids, mid[0])
|
||||
if len(mid) > 0 {
|
||||
mids = append(mids, mid[0])
|
||||
}
|
||||
}
|
||||
c := make(map[string]int)
|
||||
for i := range mids {
|
||||
|
@ -1125,9 +1135,11 @@ func TestMsg_RequestMDN(t *testing.T) {
|
|||
if err := m.RequestMDNTo(v); err != nil {
|
||||
t.Errorf("RequestMDNTo with a single valid address failed: %s", err)
|
||||
}
|
||||
if m.genHeader[HeaderDispositionNotificationTo][0] != fmt.Sprintf("<%s>", v) {
|
||||
t.Errorf("RequestMDNTo with a single valid address failed. Expected: %s, got: %s", v,
|
||||
m.genHeader[HeaderDispositionNotificationTo][0])
|
||||
if val := m.genHeader[HeaderDispositionNotificationTo]; len(val) > 1 {
|
||||
if val[0] != fmt.Sprintf("<%s>", v) {
|
||||
t.Errorf("RequestMDNTo with a single valid address failed. Expected: %s, got: %s", v,
|
||||
val[0])
|
||||
}
|
||||
}
|
||||
m.Reset()
|
||||
|
||||
|
@ -1135,13 +1147,17 @@ func TestMsg_RequestMDN(t *testing.T) {
|
|||
if err := m.RequestMDNTo(vl...); err != nil {
|
||||
t.Errorf("RequestMDNTo with a multiple valid address failed: %s", err)
|
||||
}
|
||||
if m.genHeader[HeaderDispositionNotificationTo][0] != fmt.Sprintf("<%s>", v) {
|
||||
t.Errorf("RequestMDNTo with a multiple valid addresses failed. Expected 0: %s, got 0: %s", v,
|
||||
m.genHeader[HeaderDispositionNotificationTo][0])
|
||||
if val := m.genHeader[HeaderDispositionNotificationTo]; len(val) > 0 {
|
||||
if val[0] != fmt.Sprintf("<%s>", v) {
|
||||
t.Errorf("RequestMDNTo with a multiple valid addresses failed. Expected 0: %s, got 0: %s", v,
|
||||
val[0])
|
||||
}
|
||||
}
|
||||
if m.genHeader[HeaderDispositionNotificationTo][1] != fmt.Sprintf("<%s>", v2) {
|
||||
t.Errorf("RequestMDNTo with a multiple valid addresses failed. Expected 1: %s, got 1: %s", v2,
|
||||
m.genHeader[HeaderDispositionNotificationTo][1])
|
||||
if val := m.genHeader[HeaderDispositionNotificationTo]; len(val) > 1 {
|
||||
if val[1] != fmt.Sprintf("<%s>", v2) {
|
||||
t.Errorf("RequestMDNTo with a multiple valid addresses failed. Expected 1: %s, got 1: %s", v2,
|
||||
val[1])
|
||||
}
|
||||
}
|
||||
m.Reset()
|
||||
|
||||
|
@ -1158,9 +1174,11 @@ func TestMsg_RequestMDN(t *testing.T) {
|
|||
if err := m.RequestMDNAddTo(v2); err != nil {
|
||||
t.Errorf("RequestMDNAddTo with a valid address failed: %s", err)
|
||||
}
|
||||
if m.genHeader[HeaderDispositionNotificationTo][1] != fmt.Sprintf("<%s>", v2) {
|
||||
t.Errorf("RequestMDNTo with a multiple valid addresses failed. Expected 1: %s, got 1: %s", v2,
|
||||
m.genHeader[HeaderDispositionNotificationTo][1])
|
||||
if val := m.genHeader[HeaderDispositionNotificationTo]; len(val) > 1 {
|
||||
if val[1] != fmt.Sprintf("<%s>", v2) {
|
||||
t.Errorf("RequestMDNTo with a multiple valid addresses failed. Expected 1: %s, got 1: %s", v2,
|
||||
val[1])
|
||||
}
|
||||
}
|
||||
m.Reset()
|
||||
|
||||
|
@ -1168,16 +1186,20 @@ func TestMsg_RequestMDN(t *testing.T) {
|
|||
if err := m.RequestMDNToFormat(n, v); err != nil {
|
||||
t.Errorf("RequestMDNToFormat with a single valid address failed: %s", err)
|
||||
}
|
||||
if m.genHeader[HeaderDispositionNotificationTo][0] != fmt.Sprintf(`"%s" <%s>`, n, v) {
|
||||
t.Errorf(`RequestMDNToFormat with a single valid address failed. Expected: "%s" <%s>, got: %s`, n, v,
|
||||
m.genHeader[HeaderDispositionNotificationTo][0])
|
||||
if val := m.genHeader[HeaderDispositionNotificationTo]; len(val) > 0 {
|
||||
if val[0] != fmt.Sprintf(`"%s" <%s>`, n, v) {
|
||||
t.Errorf(`RequestMDNToFormat with a single valid address failed. Expected: "%s" <%s>, got: %s`, n, v,
|
||||
val[0])
|
||||
}
|
||||
}
|
||||
if err := m.RequestMDNAddToFormat(n2, v2); err != nil {
|
||||
t.Errorf("RequestMDNAddToFormat with a valid address failed: %s", err)
|
||||
}
|
||||
if m.genHeader[HeaderDispositionNotificationTo][1] != fmt.Sprintf(`"%s" <%s>`, n2, v2) {
|
||||
t.Errorf(`RequestMDNAddToFormat with a single valid address failed. Expected: "%s" <%s>, got: %s`, n2, v2,
|
||||
m.genHeader[HeaderDispositionNotificationTo][1])
|
||||
if val := m.genHeader[HeaderDispositionNotificationTo]; len(val) > 1 {
|
||||
if val[1] != fmt.Sprintf(`"%s" <%s>`, n2, v2) {
|
||||
t.Errorf(`RequestMDNAddToFormat with a single valid address failed. Expected: "%s" <%s>, got: %s`, n2, v2,
|
||||
val[1])
|
||||
}
|
||||
}
|
||||
m.Reset()
|
||||
|
||||
|
@ -2567,6 +2589,10 @@ func TestMsg_WriteToFile(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("failed to stat output file: %s", err)
|
||||
}
|
||||
if fi == nil {
|
||||
t.Errorf("received empty file handle")
|
||||
return
|
||||
}
|
||||
if fi.Size() <= 0 {
|
||||
t.Errorf("output file is expected to contain data but its size is zero")
|
||||
}
|
||||
|
|
|
@ -67,13 +67,13 @@ func (mw *msgWriter) writeMsg(m *Msg) {
|
|||
// Set the FROM header (or envelope FROM if FROM is empty)
|
||||
hf := true
|
||||
f, ok := m.addrHeader[HeaderFrom]
|
||||
if !ok || len(f) == 0 {
|
||||
if !ok || (len(f) == 0 || f == nil) {
|
||||
f, ok = m.addrHeader[HeaderEnvelopeFrom]
|
||||
if !ok || len(f) == 0 {
|
||||
if !ok || (len(f) == 0 || f == nil) {
|
||||
hf = false
|
||||
}
|
||||
}
|
||||
if hf {
|
||||
if hf && (len(f) > 0 && f[0] != nil) {
|
||||
mw.writeHeader(Header(HeaderFrom), f[0].String())
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ func (r *Reader) Read(p []byte) (n int, err error) {
|
|||
if r.err != nil {
|
||||
return 0, r.err
|
||||
}
|
||||
if r.empty() {
|
||||
if r.empty() || r.buf == nil {
|
||||
r.Reset()
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
|
|
|
@ -6,7 +6,9 @@ package mail
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -64,9 +66,20 @@ func TestReader_Read_error(t *testing.T) {
|
|||
// TestReader_Read_empty tests the Reader.Read method with an empty buffer
|
||||
func TestReader_Read_empty(t *testing.T) {
|
||||
r := Reader{buf: []byte{}}
|
||||
var p []byte
|
||||
p := make([]byte, 1)
|
||||
p[0] = 'a'
|
||||
_, err := r.Read(p)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
t.Errorf("Reader failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestReader_Read_nil tests the Reader.Read method with a nil buffer
|
||||
func TestReader_Read_nil(t *testing.T) {
|
||||
r := Reader{buf: nil, off: -10}
|
||||
p := make([]byte, 0)
|
||||
_, err := r.Read(p)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
t.Errorf("Reader failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ func (e *SendError) Error() string {
|
|||
// Is implements the errors.Is functionality and compares the SendErrReason
|
||||
func (e *SendError) Is(et error) bool {
|
||||
var t *SendError
|
||||
if errors.As(et, &t) {
|
||||
if errors.As(et, &t) && t != nil {
|
||||
return e.Reason == t.Reason && e.isTemp == t.isTemp
|
||||
}
|
||||
return false
|
||||
|
@ -106,6 +106,9 @@ func (e *SendError) Is(et error) bool {
|
|||
|
||||
// IsTemp returns true if the delivery error is of temporary nature and can be retried
|
||||
func (e *SendError) IsTemp() bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
return e.isTemp
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue