Enhance sendmail functionality with message size limit and input validation

This commit is contained in:
Ralph Slooten
2026-05-14 16:36:27 +12:00
parent 786f263d32
commit cae0f638af
2 changed files with 34 additions and 23 deletions
+19 -2
View File
@@ -23,6 +23,7 @@ import (
"path"
"regexp"
"strings"
"time"
"net"
@@ -136,17 +137,33 @@ func Run() {
}
defer func() { _ = conn.Close() }()
go func() { _, _ = io.Copy(os.Stdout, conn) }()
done := make(chan struct{})
go func() {
_, _ = io.Copy(os.Stdout, conn)
close(done)
}()
_, _ = io.Copy(conn, os.Stdin)
if cw, ok := conn.(interface{ CloseWrite() error }); ok {
_ = cw.CloseWrite()
}
select {
case <-done:
case <-time.After(30 * time.Second):
}
return
}
body, err := io.ReadAll(os.Stdin)
const maxMessageSize = 1000 * 1024 * 1024
body, err := io.ReadAll(io.LimitReader(os.Stdin, maxMessageSize+1))
if err != nil {
fmt.Fprintln(os.Stderr, "error reading stdin")
os.Exit(11)
}
if len(body) > maxMessageSize {
fmt.Fprintf(os.Stderr, "message exceeds %d MiB size cap\n", maxMessageSize/(1024*1024))
os.Exit(11)
}
msg, err := mail.ReadMessage(bytes.NewReader(body))
if err != nil {
+15 -21
View File
@@ -10,8 +10,6 @@ import (
"net/smtp"
"os"
"strings"
"github.com/axllent/mailpit/internal/logger"
)
// Send is a wrapper for smtp.SendMail() which also supports sending via unix sockets.
@@ -29,6 +27,15 @@ func Send(addr string, from string, to []string, msg []byte) error {
return fmt.Errorf("no To addresses specified")
}
if err := validateLine(fromAddress.Address); err != nil {
return err
}
for _, recipient := range to {
if err := validateLine(recipient); err != nil {
return err
}
}
if !isSocket {
return sendMail(addr, nil, fromAddress.Address, to, msg)
}
@@ -40,16 +47,15 @@ func Send(addr string, from string, to []string, msg []byte) error {
client, err := smtp.NewClient(conn, "")
if err != nil {
_ = conn.Close()
return err
}
defer func() { _ = client.Close() }()
// Set the sender
if err := client.Mail(fromAddress.Address); err != nil {
fmt.Fprintln(os.Stderr, "error sending mail")
logger.Log().Fatal(err)
return fmt.Errorf("error setting sender: %w", err)
}
// Set the recipient
for _, a := range to {
if err := client.Rcpt(a); err != nil {
return err
@@ -61,29 +67,17 @@ func Send(addr string, from string, to []string, msg []byte) error {
return err
}
_, err = wc.Write(msg)
if err != nil {
if _, err := wc.Write(msg); err != nil {
return err
}
err = wc.Close()
if err != nil {
if err := wc.Close(); err != nil {
return err
}
return nil
return client.Quit()
}
func sendMail(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
if err := validateLine(from); err != nil {
return err
}
for _, recipient := range to {
if err := validateLine(recipient); err != nil {
return err
}
}
c, err := smtp.Dial(addr)
if err != nil {
return err