diff --git a/README.md b/README.md index 2e9eef7..196f013 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,15 @@ Mailpit is inspired by [MailHog](#why-rewrite-mailhog), but much, much faster. ![Mailpit](https://raw.githubusercontent.com/axllent/mailpit/develop/screenshot.png) + ## Features - Runs completely on a single binary - SMTP server (default `0.0.0.0:1025`) - Web UI to view emails (HTML format, text, source and MIME attachments, default `0.0.0.0:8025`) +- Optional HTTPS for web UI ([see wiki](https://github.com/axllent/mailpit/wiki/HTTPS)) - Real-time web UI updates using web sockets for new mail -- Optional basic authentication for web UI (see [wiki](https://github.com/axllent/mailpit/wiki/Basic-authentication)) +- Optional basic authentication for web UI ([see wiki](https://github.com/axllent/mailpit/wiki/Basic-authentication)) - Email storage in either memory or disk (using [CloverDB](https://github.com/ostafen/clover)) - note that in-memory has a physical limit of 1MB per email - Configurable automatic email pruning (default keeps the most recent 500 emails) - Fast SMTP processing & storing - approximately 300-600 emails per second depending on CPU, network speed & email size @@ -24,7 +26,6 @@ Mailpit is inspired by [MailHog](#why-rewrite-mailhog), but much, much faster. ## Planned features -- Optional HTTPS for web UI - Browser notifications for new mail (HTTPS only) diff --git a/cmd/root.go b/cmd/root.go index 873b14c..350bf34 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -87,11 +87,19 @@ func init() { if len(os.Getenv("MP_AUTH_FILE")) > 0 { config.AuthFile = os.Getenv("MP_AUTH_FILE") } + if len(os.Getenv("MP_SSL_CERT")) > 0 { + config.SSLCert = os.Getenv("MP_SSL_CERT") + } + if len(os.Getenv("MP_SSL_KEY")) > 0 { + config.SSLKey = os.Getenv("MP_SSL_KEY") + } rootCmd.Flags().StringVarP(&config.DataDir, "data", "d", config.DataDir, "Optional path to store peristent data") rootCmd.Flags().StringVarP(&config.SMTPListen, "smtp", "s", config.SMTPListen, "SMTP bind interface and port") rootCmd.Flags().StringVarP(&config.HTTPListen, "listen", "l", config.HTTPListen, "HTTP bind interface and port for UI") rootCmd.Flags().IntVarP(&config.MaxMessages, "max", "m", config.MaxMessages, "Max number of messages to store") rootCmd.Flags().StringVarP(&config.AuthFile, "auth-file", "a", config.AuthFile, "A password file for authentication (see wiki)") + rootCmd.Flags().StringVar(&config.SSLCert, "ssl-cert", config.SSLCert, "SSL certificate - requires ssl-key (see wiki)") + rootCmd.Flags().StringVar(&config.SSLKey, "ssl-key", config.SSLKey, "SSL key - requires ssl-cert (see wiki)") rootCmd.Flags().BoolVarP(&config.VerboseLogging, "verbose", "v", false, "Verbose logging") } diff --git a/config/config.go b/config/config.go index de03eea..8619c13 100644 --- a/config/config.go +++ b/config/config.go @@ -2,6 +2,8 @@ package config import ( "errors" + "fmt" + "os" "regexp" "github.com/tg123/go-htpasswd" @@ -26,9 +28,10 @@ var ( // NoLogging for tests NoLogging = false - // SSLCert @TODO + // SSLCert file SSLCert string - // SSLKey @TODO + + // SSLKey file SSLKey string // AuthFile for basic authentication @@ -49,6 +52,10 @@ func VerifyConfig() error { } if AuthFile != "" { + if !isFile(AuthFile) { + return fmt.Errorf("password file not found: %s", AuthFile) + } + a, err := htpasswd.New(AuthFile, htpasswd.DefaultSystems, nil) if err != nil { return err @@ -56,5 +63,29 @@ func VerifyConfig() error { Auth = a } + if SSLCert != "" && SSLKey == "" || SSLCert == "" && SSLKey != "" { + return errors.New("you must provide both an SSL certificate and a key") + } + + if SSLCert != "" { + if !isFile(SSLCert) { + return fmt.Errorf("SSL certificate not found: %s", SSLCert) + } + + if !isFile(SSLKey) { + return fmt.Errorf("SSL key not found: %s", SSLKey) + } + } + return nil } + +// IsFile returns if a path is a file +func isFile(path string) bool { + info, err := os.Stat(path) + if os.IsNotExist(err) || !info.Mode().IsRegular() { + return false + } + + return true +}