1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-01-08 00:39:22 +02:00

Merge branch 'feature/sendmail-bs' into develop

This commit is contained in:
Ralph Slooten 2023-06-03 11:03:17 +12:00
commit 870e523c97
6 changed files with 115 additions and 54 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
/node_modules/
/send
/sendmail/sendmail
/server/ui/dist
/Makefile
/mailpit*

View File

@ -1,23 +1,18 @@
package cmd
import (
"os"
sendmail "github.com/axllent/mailpit/sendmail/cmd"
"github.com/spf13/cobra"
)
var (
smtpAddr = "localhost:1025"
fromAddr string
)
// sendmailCmd represents the sendmail command
var sendmailCmd = &cobra.Command{
Use: "sendmail [flags] [recipients]",
Short: "A sendmail command replacement for Mailpit",
Long: `A sendmail command replacement for Mailpit.
You can optionally create a symlink called 'sendmail' to the Mailpit binary.`,
Run: func(_ *cobra.Command, _ []string) {
sendmail.Run()
},
}
@ -25,13 +20,17 @@ You can optionally create a symlink called 'sendmail' to the Mailpit binary.`,
func init() {
rootCmd.AddCommand(sendmailCmd)
// these are simply repeated for cli consistency
sendmailCmd.Flags().StringVarP(&fromAddr, "from", "f", fromAddr, "SMTP sender")
sendmailCmd.Flags().StringVarP(&smtpAddr, "smtp-addr", "S", smtpAddr, "SMTP server address")
sendmailCmd.Flags().BoolVarP(&sendmail.Verbose, "verbose", "v", false, "Verbose mode (sends debug output to stderr)")
sendmailCmd.Flags().BoolP("long-b", "b", false, "Ignored. This flag exists for sendmail compatibility.")
sendmailCmd.Flags().BoolP("long-i", "i", false, "Ignored. This flag exists for sendmail compatibility.")
sendmailCmd.Flags().BoolP("long-o", "o", false, "Ignored. This flag exists for sendmail compatibility.")
sendmailCmd.Flags().BoolP("long-s", "s", false, "Ignored. This flag exists for sendmail compatibility.")
sendmailCmd.Flags().BoolP("long-t", "t", false, "Ignored. This flag exists for sendmail compatibility.")
// print out manual help screen
rootCmd.SetHelpTemplate(sendmail.HelpTemplate(os.Args[0:2]))
// these are simply repeated for cli consistency as cobra/viper does not allow
// multi-letter single-dash variables (-bs)
sendmailCmd.Flags().StringVarP(&sendmail.FromAddr, "from", "f", sendmail.FromAddr, "SMTP sender")
sendmailCmd.Flags().StringVarP(&sendmail.SMTPAddr, "smtp-addr", "S", sendmail.SMTPAddr, "SMTP server address")
sendmailCmd.Flags().BoolVarP(&sendmail.UseB, "long-b", "b", false, "Handle SMTP commands on standard input (use as -bs)")
sendmailCmd.Flags().BoolVarP(&sendmail.UseS, "long-s", "s", false, "Handle SMTP commands on standard input (use as -bs)")
sendmailCmd.Flags().BoolP("verbose", "v", false, "Verbose mode (sends debug output to stderr)")
sendmailCmd.Flags().Bool("i", false, "Ignored")
sendmailCmd.Flags().Bool("o", false, "Ignored")
sendmailCmd.Flags().Bool("t", false, "Ignored")
}

4
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/leporo/sqlf v1.4.0
github.com/mattn/go-shellwords v1.0.12
github.com/mhale/smtpd v0.8.0
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e
github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.9.2
github.com/spf13/cobra v1.7.0
@ -40,6 +41,7 @@ require (
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/reiver/go-oi v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
@ -49,7 +51,7 @@ require (
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/tools v0.9.3 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect

8
go.sum
View File

@ -93,6 +93,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM=
github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI=
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas=
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e/go.mod h1:+5vNVvEWwEIx86DB9Ke/+a5wBI464eDRo3eF0LcfpWg=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@ -175,8 +179,8 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -3,8 +3,16 @@ package cmd
/**
* Bare bones sendmail drop-in replacement borrowed from MailHog
*
* It uses a bit of a hack for flag parsing in order to be compatible
* with the cobra sendmail subcommand, as sendmail uses `-bc` which
* is not POSIX compatible.
*
* The -bs command-line switch causes sendmail to run a single SMTP session in the
* foreground over its standard input and output, and then exit. The SMTP session
* is exactly like a network SMTP session. Usually, one or more messages are
* submitted to sendmail for delivery.
*/
import (
"bytes"
"fmt"
@ -13,21 +21,27 @@ import (
"net/smtp"
"os"
"os/user"
"strings"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/utils/logger"
"github.com/reiver/go-telnet"
flag "github.com/spf13/pflag"
)
var (
// Verbose flag
Verbose bool
// SMTPAddr address
SMTPAddr = "localhost:1025"
// FromAddr email address
FromAddr string
fromAddr string
// UseB - used to set from `-bs`
UseB bool
// UseS - used to set from `-bs`
UseS bool
)
// Run the Mailpit sendmail replacement.
func Run() {
func init() {
host, err := os.Hostname()
if err != nil {
host = "localhost"
@ -39,47 +53,68 @@ func Run() {
username = user.Username
}
if fromAddr == "" {
fromAddr = username + "@" + host
if FromAddr == "" {
FromAddr = username + "@" + host
}
}
smtpAddr := "localhost:1025"
var recip []string
// Run the Mailpit sendmail replacement.
func Run() {
var recipients []string
// defaults from envars if provided
if len(os.Getenv("MP_SENDMAIL_SMTP_ADDR")) > 0 {
smtpAddr = os.Getenv("MP_SENDMAIL_SMTP_ADDR")
SMTPAddr = os.Getenv("MP_SENDMAIL_SMTP_ADDR")
}
if len(os.Getenv("MP_SENDMAIL_FROM")) > 0 {
fromAddr = os.Getenv("MP_SENDMAIL_FROM")
FromAddr = os.Getenv("MP_SENDMAIL_FROM")
}
// override defaults from cli flags
flag.StringVarP(&fromAddr, "from", "f", fromAddr, "SMTP sender address")
flag.StringVarP(&smtpAddr, "smtp-addr", "S", smtpAddr, "SMTP server address")
flag.BoolVarP(&Verbose, "verbose", "v", false, "Verbose mode (sends debug output to stderr)")
flag.BoolP("long-b", "b", false, "Ignored. This flag exists for sendmail compatibility.")
flag.BoolP("long-i", "i", false, "Ignored. This flag exists for sendmail compatibility.")
flag.BoolP("long-o", "o", false, "Ignored. This flag exists for sendmail compatibility.")
flag.BoolP("long-s", "s", false, "Ignored. This flag exists for sendmail compatibility.")
flag.BoolP("long-t", "t", false, "Ignored. This flag exists for sendmail compatibility.")
flag.CommandLine.SortFlags = false
flag.StringVarP(&FromAddr, "from", "f", FromAddr, "SMTP sender")
flag.StringVarP(&SMTPAddr, "smtp-addr", "S", SMTPAddr, "SMTP server address")
flag.BoolVarP(&UseB, "long-b", "b", false, "Handle SMTP commands on standard input (use as -bs)")
flag.BoolVarP(&UseS, "long-s", "s", false, "Handle SMTP commands on standard input (use as -bs)")
flag.BoolP("verbose", "v", false, "Ignored")
flag.Bool("i", false, "Ignored")
flag.Bool("o", false, "Ignored")
flag.Bool("t", false, "Ignored")
// set the default help
flag.Usage = func() {
fmt.Printf("A sendmail command replacement for Mailpit (%s).\n\n", config.Version)
fmt.Printf("Usage:\n %s [flags] [recipients]\n", os.Args[0])
fmt.Println("\nFlags:")
flag.PrintDefaults()
fmt.Println(HelpTemplate(os.Args[0:1]))
}
var showHelp bool
// avoid 'pflag: help requested' error
flag.BoolVarP(&showHelp, "help", "h", false, "")
flag.Parse()
// allow recipient to be passed as an argument
recip = flag.Args()
// allow recipients to be passed as an argument
recipients = flag.Args()
if Verbose {
fmt.Fprintln(os.Stdout, smtpAddr, fromAddr)
if showHelp {
flag.Usage()
os.Exit(0)
}
// ensure -bs is set
if UseB && !UseS || !UseB && UseS {
fmt.Printf("error: use -bs")
os.Exit(1)
}
// handles `sendmail -bs`
if UseB && UseS {
var caller telnet.Caller = telnet.StandardCaller
// telnet directly to SMTP
if err := telnet.DialToAndCall(SMTPAddr, caller); err != nil {
fmt.Println(err)
os.Exit(1)
}
return
}
body, err := ioutil.ReadAll(os.Stdin)
@ -96,8 +131,8 @@ func Run() {
addresses := []string{}
if len(recip) > 0 {
addresses = recip
if len(recipients) > 0 {
addresses = recipients
} else {
// get all recipients in To, Cc and Bcc
if to, err := msg.Header.AddressList("To"); err == nil {
@ -117,9 +152,29 @@ func Run() {
}
}
err = smtp.SendMail(smtpAddr, nil, fromAddr, addresses, body)
err = smtp.SendMail(SMTPAddr, nil, FromAddr, addresses, body)
if err != nil {
fmt.Fprintln(os.Stderr, "error sending mail")
logger.Log().Fatal(err)
}
}
// HelpTemplate returns a string of the help
func HelpTemplate(args []string) string {
fmt.Println(args)
return fmt.Sprintf(`A sendmail command replacement for Mailpit (%s)
Usage: %s [flags] [recipients] < message
See: https://github.com/axllent/mailpit
Flags:
-S string SMTP server address (default "localhost:1025")
-f string Set the envelope sender address (default "%s")
-bs Handle SMTP commands on standard input
-t Ignored
-i Ignored
-o Ignored
-v Ignored
`, config.Version, strings.Join(args, " "), FromAddr)
}

View File

@ -90,7 +90,7 @@ func mailHandler(origin net.Addr, from string, to []string, data []byte) error {
_, err = storage.Store(data)
if err != nil {
logger.Log().Errorf("[db] error storing message: %d", err.Error())
logger.Log().Errorf("[db] error storing message: %s", err.Error())
return err
}