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