mirror of
https://github.com/axllent/mailpit.git
synced 2024-12-28 23:06:43 +02:00
Merge branch 'feature/smtp-tls' into develop
This commit is contained in:
commit
e70cb75d4a
31
README.md
31
README.md
@ -32,31 +32,24 @@ Mailpit was originally **inspired** by MailHog which is [no longer maintained](h
|
||||
|
||||
## Features
|
||||
|
||||
- Runs entirely from a single [static binary](https://mailpit.axllent.org/docs/install/)
|
||||
- Modern web UI to view emails (formatted HTML, highlighted HTML source, text, headers, raw source, and MIME attachments
|
||||
including image thumbnails), including optional [HTTPS](https://mailpit.axllent.org/docs/configuration/https/)
|
||||
- Optional [basic authentication](https://mailpit.axllent.org/docs/configuration/frontend-authentication/) for web UI & API
|
||||
- Runs entirely from a single [static binary](https://mailpit.axllent.org/docs/install/) or multi-architecture [Docker images](https://mailpit.axllent.org/docs/install/docker/)
|
||||
- Modern web UI with advanced [mail search](https://mailpit.axllent.org/docs/usage/search-filters/) to view emails (formatted HTML, highlighted HTML source, text, headers, raw source, and MIME attachments
|
||||
including image thumbnails), including optional [HTTPS](https://mailpit.axllent.org/docs/configuration/http/) & [authentication](https://mailpit.axllent.org/docs/configuration/http/)
|
||||
- [SMTP server](https://mailpit.axllent.org/docs/configuration/smtp/) with optional STARTTLS or SSL/TLS, authentication (including an "accept any" mode)
|
||||
- A [REST API](https://mailpit.axllent.org/docs/api-v1/) for integration testing
|
||||
- Real-time web UI updates using web sockets for new mail & optional [browser notifications](https://mailpit.axllent.org/docs/usage/notifications/) when new mail is received
|
||||
- Optional [POP3 server](https://mailpit.axllent.org/docs/configuration/pop3/) to download captured message directly into your email client
|
||||
- [HTML check](https://mailpit.axllent.org/docs/usage/html-check/) to test & score mail client compatibility with HTML emails
|
||||
- [Link check](https://mailpit.axllent.org/docs/usage/link-check/) to test message links (HTML & text) & linked images
|
||||
- [Spam check](https://mailpit.axllent.org/docs/usage/spamassassin/) to test message "spamminess" using a running SpamAssassin server
|
||||
- [Create screenshots](https://mailpit.axllent.org/docs/usage/html-screenshots/) of HTML messages via web UI
|
||||
- `List-Unsubscribe` syntax validation
|
||||
- Mobile and tablet HTML preview toggle in desktop mode
|
||||
- Advanced [mail search](https://mailpit.axllent.org/docs/usage/search-filters/)
|
||||
- [Message tagging](https://mailpit.axllent.org/docs/usage/tagging/)
|
||||
- Real-time web UI updates using web sockets for new mail & optional browser notifications for new mail (when accessed
|
||||
via either HTTPS or `localhost` only)
|
||||
- SMTP server with optional [STARTTLS & SMTP authentication](https://mailpit.axllent.org/docs/configuration/smtp-authentication/) (including an
|
||||
"accept any" mode)
|
||||
- [SMTP relaying](https://mailpit.axllent.org/docs/configuration/smtp-relay/) (message release) - relay messages via a different SMTP server
|
||||
including an optional allowlist of accepted recipients
|
||||
- Fast SMTP processing & storing - ingesting 100-200 emails per second depending on CPU, network speed & email size,
|
||||
easily handling tens of thousands of emails
|
||||
- Optional [POP3 server](https://mailpit.axllent.org/docs/configuration/pop3/) to download captured message directly into your email client
|
||||
- Configurable automatic email pruning (default keeps the most recent 500 emails)
|
||||
- A simple [REST API](https://mailpit.axllent.org/docs/api-v1/) for integration testing
|
||||
- [Message tagging](https://mailpit.axllent.org/docs/usage/tagging/) including manual tagging or automated tagging using filtering and "plus addressing"
|
||||
- [SMTP relaying](https://mailpit.axllent.org/docs/configuration/smtp-relay/) (message release) - relay messages via a different SMTP server including an optional allowlist of accepted recipients
|
||||
- Fast message [storing & processing](https://mailpit.axllent.org/docs/configuration/email-storage/) - ingesting 100-200 emails per second over SMTP depending on CPU, network speed & email size,
|
||||
easily handling tens of thousands of emails, with automatic email pruning (by default keeping the most recent 500 emails)
|
||||
- `List-Unsubscribe` syntax validation
|
||||
- Optional [webhook](https://mailpit.axllent.org/docs/integration/webhook/) for received messages
|
||||
- Multi-architecture [Docker images](https://mailpit.axllent.org/docs/install/docker/)
|
||||
|
||||
|
||||
## Installation
|
||||
|
21
cmd/root.go
21
cmd/root.go
@ -108,7 +108,8 @@ func init() {
|
||||
rootCmd.Flags().BoolVar(&config.SMTPAuthAcceptAny, "smtp-auth-accept-any", config.SMTPAuthAcceptAny, "Accept any SMTP username and password, including none")
|
||||
rootCmd.Flags().StringVar(&config.SMTPTLSCert, "smtp-tls-cert", config.SMTPTLSCert, "TLS certificate for SMTP (STARTTLS) - requires smtp-tls-key")
|
||||
rootCmd.Flags().StringVar(&config.SMTPTLSKey, "smtp-tls-key", config.SMTPTLSKey, "TLS key for SMTP (STARTTLS) - requires smtp-tls-cert")
|
||||
rootCmd.Flags().BoolVar(&config.SMTPTLSRequired, "smtp-tls-required", config.SMTPTLSRequired, "Require TLS SMTP encryption")
|
||||
rootCmd.Flags().BoolVar(&config.SMTPRequireSTARTTLS, "smtp-require-starttls", config.SMTPRequireSTARTTLS, "Require SMTP client use STARTTLS")
|
||||
rootCmd.Flags().BoolVar(&config.SMTPRequireTLS, "smtp-require-tls", config.SMTPRequireTLS, "Require client use SSL/TLS")
|
||||
rootCmd.Flags().BoolVar(&config.SMTPAuthAllowInsecure, "smtp-auth-allow-insecure", config.SMTPAuthAllowInsecure, "Allow insecure PLAIN & LOGIN SMTP authentication")
|
||||
rootCmd.Flags().BoolVar(&config.SMTPStrictRFCHeaders, "smtp-strict-rfc-headers", config.SMTPStrictRFCHeaders, "Return SMTP error if message headers contain <CR><CR><LF>")
|
||||
rootCmd.Flags().IntVar(&config.SMTPMaxRecipients, "smtp-max-recipients", config.SMTPMaxRecipients, "Maximum SMTP recipients allowed")
|
||||
@ -146,6 +147,11 @@ func init() {
|
||||
rootCmd.Flags().Lookup("smtp-ssl-cert").Deprecated = "use --smtp-tls-cert"
|
||||
rootCmd.Flags().Lookup("smtp-ssl-key").Hidden = true
|
||||
rootCmd.Flags().Lookup("smtp-ssl-key").Deprecated = "use --smtp-tls-key"
|
||||
|
||||
// DEPRECATED FLAGS 2024/03/16
|
||||
rootCmd.Flags().BoolVar(&config.SMTPRequireSTARTTLS, "smtp-tls-required", config.SMTPRequireSTARTTLS, "smtp-require-starttls")
|
||||
rootCmd.Flags().Lookup("smtp-tls-required").Hidden = true
|
||||
rootCmd.Flags().Lookup("smtp-tls-required").Deprecated = "use --smtp-require-starttls"
|
||||
}
|
||||
|
||||
// Load settings from environment
|
||||
@ -213,9 +219,13 @@ func initConfigFromEnv() {
|
||||
}
|
||||
config.SMTPTLSCert = os.Getenv("MP_SMTP_TLS_CERT")
|
||||
config.SMTPTLSKey = os.Getenv("MP_SMTP_TLS_KEY")
|
||||
if getEnabledFromEnv("MP_SMTP_TLS_REQUIRED") {
|
||||
config.SMTPTLSRequired = true
|
||||
if getEnabledFromEnv("MP_SMTP_REQUIRE_STARTTLS") {
|
||||
config.SMTPRequireSTARTTLS = true
|
||||
}
|
||||
if getEnabledFromEnv("MP_SMTP_REQUIRE_TLS") {
|
||||
config.SMTPRequireTLS = true
|
||||
}
|
||||
|
||||
if getEnabledFromEnv("MP_SMTP_AUTH_ALLOW_INSECURE") {
|
||||
config.SMTPAuthAllowInsecure = true
|
||||
}
|
||||
@ -306,6 +316,11 @@ func initDeprecatedConfigFromEnv() {
|
||||
logger.Log().Warn("ENV MP_STRICT_RFC_HEADERS has been deprecated, use MP_SMTP_STRICT_RFC_HEADERS")
|
||||
config.SMTPStrictRFCHeaders = true
|
||||
}
|
||||
// deprecated 2024/03.16
|
||||
if getEnabledFromEnv("MP_SMTP_TLS_REQUIRED") {
|
||||
logger.Log().Warn("ENV MP_SMTP_TLS_REQUIRED has been deprecated, use MP_SMTP_REQUIRE_STARTTLS")
|
||||
config.SMTPRequireSTARTTLS = true
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper to get a boolean from an environment variable
|
||||
|
@ -53,10 +53,14 @@ var (
|
||||
// SMTPTLSKey file
|
||||
SMTPTLSKey string
|
||||
|
||||
// SMTPTLSRequired to enforce TLS
|
||||
// SMTPRequireSTARTTLS to enforce the use of STARTTLS
|
||||
// The only allowed commands are NOOP, EHLO, STARTTLS and QUIT (as specified in RFC 3207) until
|
||||
// the connection is upgraded to TLS i.e. until STARTTLS is issued.
|
||||
SMTPTLSRequired bool
|
||||
SMTPRequireSTARTTLS bool
|
||||
|
||||
// SMTPRequireTLS to allow only SSL/TLS connections for all connections
|
||||
//
|
||||
SMTPRequireTLS bool
|
||||
|
||||
// SMTPAuthFile for SMTP authentication
|
||||
SMTPAuthFile string
|
||||
@ -242,12 +246,16 @@ func VerifyConfig() error {
|
||||
if !isFile(SMTPTLSKey) {
|
||||
return fmt.Errorf("[smtp] TLS key not found: %s", SMTPTLSKey)
|
||||
}
|
||||
} else if SMTPTLSRequired {
|
||||
} else if SMTPRequireTLS {
|
||||
return errors.New("[smtp] TLS cannot be required without an SMTP TLS certificate and key")
|
||||
} else if SMTPRequireSTARTTLS {
|
||||
return errors.New("[smtp] STARTTLS cannot be required without an SMTP TLS certificate and key")
|
||||
}
|
||||
|
||||
if SMTPTLSRequired && SMTPAuthAllowInsecure {
|
||||
return errors.New("[smtp] TLS cannot be required while also allowing insecure authentication")
|
||||
if SMTPRequireSTARTTLS && SMTPAuthAllowInsecure || SMTPRequireTLS && SMTPAuthAllowInsecure {
|
||||
return errors.New("[smtp] TLS cannot be required with --smtp-auth-allow-insecure")
|
||||
}
|
||||
if SMTPRequireSTARTTLS && SMTPRequireTLS {
|
||||
return errors.New("[smtp] TLS & STARTTLS cannot be required together")
|
||||
}
|
||||
|
||||
if SMTPAuthFile != "" {
|
||||
@ -265,6 +273,18 @@ func VerifyConfig() error {
|
||||
if err := auth.SetSMTPAuth(string(b)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !SMTPAuthAllowInsecure {
|
||||
// https://www.rfc-editor.org/rfc/rfc4954
|
||||
// A server implementation MUST implement a configuration in which
|
||||
// it does NOT permit any plaintext password mechanisms, unless either
|
||||
// the STARTTLS [SMTP-TLS] command has been negotiated or some other
|
||||
// mechanism that protects the session from password snooping has been
|
||||
// provided. Server sites SHOULD NOT use any configuration which
|
||||
// permits a plaintext password mechanism without such a protection
|
||||
// mechanism against password snooping.
|
||||
SMTPRequireSTARTTLS = true
|
||||
}
|
||||
}
|
||||
|
||||
if auth.SMTPCredentials != nil && SMTPAuthAcceptAny {
|
||||
@ -272,7 +292,7 @@ func VerifyConfig() error {
|
||||
}
|
||||
|
||||
if SMTPTLSCert == "" && (auth.SMTPCredentials != nil || SMTPAuthAcceptAny) && !SMTPAuthAllowInsecure {
|
||||
return errors.New("[smtp] authentication requires TLS encryption, run with `--smtp-auth-allow-insecure` to allow insecure authentication")
|
||||
return errors.New("[smtp] authentication requires STARTTLS or TLS encryption, run with `--smtp-auth-allow-insecure` to allow insecure authentication")
|
||||
}
|
||||
|
||||
// POP3 server
|
||||
|
@ -177,19 +177,35 @@ func handlerRcpt(remoteAddr net.Addr, from string, to string) bool {
|
||||
func Listen() error {
|
||||
if config.SMTPAuthAllowInsecure {
|
||||
if auth.SMTPCredentials != nil {
|
||||
logger.Log().Info("[smtpd] enabling login auth (insecure)")
|
||||
logger.Log().Info("[smtpd] enabling login authentication (insecure)")
|
||||
} else if config.SMTPAuthAcceptAny {
|
||||
logger.Log().Info("[smtpd] enabling all auth (insecure)")
|
||||
logger.Log().Info("[smtpd] enabling any authentication (insecure)")
|
||||
}
|
||||
} else {
|
||||
if auth.SMTPCredentials != nil {
|
||||
logger.Log().Info("[smtpd] enabling login auth (TLS)")
|
||||
logger.Log().Info("[smtpd] enabling login authentication")
|
||||
} else if config.SMTPAuthAcceptAny {
|
||||
logger.Log().Info("[smtpd] enabling any auth (TLS)")
|
||||
logger.Log().Info("[smtpd] enabling any authentication")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Log().Infof("[smtpd] starting on %s", config.SMTPListen)
|
||||
smtpType := "no encryption"
|
||||
|
||||
if config.SMTPTLSCert != "" {
|
||||
if config.SMTPRequireSTARTTLS {
|
||||
smtpType = "STARTTLS required"
|
||||
} else if config.SMTPRequireTLS {
|
||||
smtpType = "SSL/TLS required"
|
||||
} else {
|
||||
smtpType = "STARTTLS optional"
|
||||
if !config.SMTPAuthAllowInsecure && auth.SMTPCredentials != nil {
|
||||
smtpType = "STARTTLS required"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Log().Infof("[smtpd] starting on %s (%s)", config.SMTPListen, smtpType)
|
||||
|
||||
return listenAndServe(config.SMTPListen, mailHandler, authHandler)
|
||||
}
|
||||
@ -221,7 +237,8 @@ func listenAndServe(addr string, handler smtpd.Handler, authHandler smtpd.AuthHa
|
||||
}
|
||||
|
||||
if config.SMTPTLSCert != "" {
|
||||
srv.TLSRequired = config.SMTPTLSRequired
|
||||
srv.TLSRequired = config.SMTPRequireSTARTTLS
|
||||
srv.TLSListener = config.SMTPRequireTLS // if true overrules srv.TLSRequired
|
||||
if err := srv.ConfigureTLS(config.SMTPTLSCert, config.SMTPTLSKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user