mirror of
https://github.com/axllent/mailpit.git
synced 2025-08-15 20:13:16 +02:00
Feature: HTTPS option for web UI
This commit is contained in:
@@ -8,13 +8,15 @@ Mailpit is inspired by [MailHog](#why-rewrite-mailhog), but much, much faster.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Runs completely on a single binary
|
- Runs completely on a single binary
|
||||||
- SMTP server (default `0.0.0.0:1025`)
|
- 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`)
|
- 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
|
- 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
|
- 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)
|
- 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
|
- 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
|
## Planned features
|
||||||
|
|
||||||
- Optional HTTPS for web UI
|
|
||||||
- Browser notifications for new mail (HTTPS only)
|
- Browser notifications for new mail (HTTPS only)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -87,11 +87,19 @@ func init() {
|
|||||||
if len(os.Getenv("MP_AUTH_FILE")) > 0 {
|
if len(os.Getenv("MP_AUTH_FILE")) > 0 {
|
||||||
config.AuthFile = os.Getenv("MP_AUTH_FILE")
|
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.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.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().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().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().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")
|
rootCmd.Flags().BoolVarP(&config.VerboseLogging, "verbose", "v", false, "Verbose logging")
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/tg123/go-htpasswd"
|
"github.com/tg123/go-htpasswd"
|
||||||
@@ -26,9 +28,10 @@ var (
|
|||||||
// NoLogging for tests
|
// NoLogging for tests
|
||||||
NoLogging = false
|
NoLogging = false
|
||||||
|
|
||||||
// SSLCert @TODO
|
// SSLCert file
|
||||||
SSLCert string
|
SSLCert string
|
||||||
// SSLKey @TODO
|
|
||||||
|
// SSLKey file
|
||||||
SSLKey string
|
SSLKey string
|
||||||
|
|
||||||
// AuthFile for basic authentication
|
// AuthFile for basic authentication
|
||||||
@@ -49,6 +52,10 @@ func VerifyConfig() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if AuthFile != "" {
|
if AuthFile != "" {
|
||||||
|
if !isFile(AuthFile) {
|
||||||
|
return fmt.Errorf("password file not found: %s", AuthFile)
|
||||||
|
}
|
||||||
|
|
||||||
a, err := htpasswd.New(AuthFile, htpasswd.DefaultSystems, nil)
|
a, err := htpasswd.New(AuthFile, htpasswd.DefaultSystems, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -56,5 +63,29 @@ func VerifyConfig() error {
|
|||||||
Auth = a
|
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
|
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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user