mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-22 13:50:49 +01:00
WriteToSendmailWithContext tests revealed a race condition which has been fixed
This commit is contained in:
parent
3c642be4eb
commit
0e00b165f9
2 changed files with 48 additions and 25 deletions
48
msg.go
48
msg.go
|
@ -1,7 +1,6 @@
|
||||||
package mail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -29,18 +28,24 @@ type Msg struct {
|
||||||
// addrHeader is a slice of strings that the different mail AddrHeader fields
|
// addrHeader is a slice of strings that the different mail AddrHeader fields
|
||||||
addrHeader map[AddrHeader][]*mail.Address
|
addrHeader map[AddrHeader][]*mail.Address
|
||||||
|
|
||||||
|
// attachments represent the different attachment File of the Msg
|
||||||
|
attachments []*File
|
||||||
|
|
||||||
// boundary is the MIME content boundary
|
// boundary is the MIME content boundary
|
||||||
boundary string
|
boundary string
|
||||||
|
|
||||||
// charset represents the charset of the mail (defaults to UTF-8)
|
// charset represents the charset of the mail (defaults to UTF-8)
|
||||||
charset Charset
|
charset Charset
|
||||||
|
|
||||||
// encoding represents the message encoding (the encoder will be a corresponding WordEncoder)
|
// embeds represent the different embedded File of the Msg
|
||||||
encoding Encoding
|
embeds []*File
|
||||||
|
|
||||||
// encoder represents a mime.WordEncoder from the std lib
|
// encoder represents a mime.WordEncoder from the std lib
|
||||||
encoder mime.WordEncoder
|
encoder mime.WordEncoder
|
||||||
|
|
||||||
|
// encoding represents the message encoding (the encoder will be a corresponding WordEncoder)
|
||||||
|
encoding Encoding
|
||||||
|
|
||||||
// genHeader is a slice of strings that the different generic mail Header fields
|
// genHeader is a slice of strings that the different generic mail Header fields
|
||||||
genHeader map[Header][]string
|
genHeader map[Header][]string
|
||||||
|
|
||||||
|
@ -49,12 +54,6 @@ type Msg struct {
|
||||||
|
|
||||||
// parts represent the different parts of the Msg
|
// parts represent the different parts of the Msg
|
||||||
parts []*Part
|
parts []*Part
|
||||||
|
|
||||||
// attachments represent the different attachment File of the Msg
|
|
||||||
attachments []*File
|
|
||||||
|
|
||||||
// embeds represent the different embedded File of the Msg
|
|
||||||
embeds []*File
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendmailPath is the default system path to the sendmail binary
|
// SendmailPath is the default system path to the sendmail binary
|
||||||
|
@ -511,14 +510,21 @@ func (m *Msg) WriteToSendmailWithContext(ctx context.Context, sp string, a ...st
|
||||||
ec.Args = append(ec.Args, "-oi", "-t")
|
ec.Args = append(ec.Args, "-oi", "-t")
|
||||||
ec.Args = append(ec.Args, a...)
|
ec.Args = append(ec.Args, a...)
|
||||||
|
|
||||||
var ebuf bytes.Buffer
|
se, err := ec.StderrPipe()
|
||||||
ec.Stderr = &ebuf
|
if err != nil {
|
||||||
ses := bufio.NewScanner(&ebuf)
|
return fmt.Errorf("failed to set STDERR pipe: %w", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = se.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
si, err := ec.StdinPipe()
|
si, err := ec.StdinPipe()
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = si.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -526,23 +532,17 @@ func (m *Msg) WriteToSendmailWithContext(ctx context.Context, sp string, a ...st
|
||||||
}
|
}
|
||||||
_, err = m.Write(si)
|
_, err = m.Write(si)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = si.Close()
|
|
||||||
return fmt.Errorf("failed to write mail to buffer: %w", err)
|
return fmt.Errorf("failed to write mail to buffer: %w", err)
|
||||||
}
|
}
|
||||||
if err := si.Close(); err != nil {
|
|
||||||
return fmt.Errorf("failed to close STDIN pipe: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the stderr buffer for possible errors
|
// Read the stderr pipe for possible errors
|
||||||
var serr string
|
var serr []byte
|
||||||
for ses.Scan() {
|
en, err := se.Read(serr)
|
||||||
serr += ses.Text()
|
if err != nil {
|
||||||
}
|
|
||||||
if err := ses.Err(); err != nil {
|
|
||||||
return fmt.Errorf("failed to read STDERR pipe: %w", err)
|
return fmt.Errorf("failed to read STDERR pipe: %w", err)
|
||||||
}
|
}
|
||||||
if serr != "" {
|
if en > 0 {
|
||||||
return fmt.Errorf("sendmail execution failed: %s", serr)
|
return fmt.Errorf("sendmail command failed: %s", serr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for completion or cancellation of the sendmail executable
|
// Wait for completion or cancellation of the sendmail executable
|
||||||
|
|
25
msg_test.go
25
msg_test.go
|
@ -1137,5 +1137,28 @@ func TestMsg_Write(t *testing.T) {
|
||||||
t.Errorf("Write() failed: expected written byte length: %d, got: %d", n, wbuf.Len())
|
t.Errorf("Write() failed: expected written byte length: %d, got: %d", n, wbuf.Len())
|
||||||
fmt.Printf("%s", wbuf.String())
|
fmt.Printf("%s", wbuf.String())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestMsg_WriteToSendmailWithCommand tests the WriteToSendmailWithCommand() method of the Msg
|
||||||
|
func TestMsg_WriteToSendmailWithCommand(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
sp string
|
||||||
|
sf bool
|
||||||
|
}{
|
||||||
|
{"Sendmail path: /dev/null", "/dev/null", true},
|
||||||
|
{"Sendmail path: /bin/cat", "/bin/cat", true},
|
||||||
|
{"Sendmail path: /is/invalid", "/is/invalid", true},
|
||||||
|
{"Sendmail path: /usr/bin/true", "/usr/bin/true", false},
|
||||||
|
}
|
||||||
|
m := NewMsg()
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m.SetBodyString(TypeTextPlain, "Plain")
|
||||||
|
if err := m.WriteToSendmailWithCommand(tt.sp); err != nil && !tt.sf {
|
||||||
|
t.Errorf("WriteToSendmailWithCommand() failed: %s", err)
|
||||||
|
}
|
||||||
|
m.Reset()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue