mirror of
https://github.com/axllent/mailpit.git
synced 2025-04-27 12:32:22 +02:00
Feature: Allow setting SMTP relay configuration values via environment variables (#262)
This commit is contained in:
parent
053779c656
commit
a324d817b3
cmd
config
server
15
cmd/root.go
15
cmd/root.go
@ -79,7 +79,7 @@ func init() {
|
|||||||
// load and warn deprecated ENV vars
|
// load and warn deprecated ENV vars
|
||||||
initDeprecatedConfigFromEnv()
|
initDeprecatedConfigFromEnv()
|
||||||
|
|
||||||
// load ENV vars
|
// load environment variables
|
||||||
initConfigFromEnv()
|
initConfigFromEnv()
|
||||||
|
|
||||||
rootCmd.Flags().StringVarP(&config.DataFile, "db-file", "d", config.DataFile, "Database file to store persistent data")
|
rootCmd.Flags().StringVarP(&config.DataFile, "db-file", "d", config.DataFile, "Database file to store persistent data")
|
||||||
@ -237,6 +237,19 @@ func initConfigFromEnv() {
|
|||||||
if getEnabledFromEnv("MP_SMTP_RELAY_ALL") {
|
if getEnabledFromEnv("MP_SMTP_RELAY_ALL") {
|
||||||
config.SMTPRelayAllIncoming = true
|
config.SMTPRelayAllIncoming = true
|
||||||
}
|
}
|
||||||
|
config.SMTPRelayConfig = config.SMTPRelayConfigStruct{}
|
||||||
|
config.SMTPRelayConfig.Host = os.Getenv("MP_SMTP_RELAY_HOST")
|
||||||
|
if len(os.Getenv("MP_SMTP_RELAY_PORT")) > 0 {
|
||||||
|
config.SMTPRelayConfig.Port, _ = strconv.Atoi(os.Getenv("MP_SMTP_RELAY_PORT"))
|
||||||
|
}
|
||||||
|
config.SMTPRelayConfig.STARTTLS = getEnabledFromEnv("MP_SMTP_RELAY_STARTTLS")
|
||||||
|
config.SMTPRelayConfig.AllowInsecure = getEnabledFromEnv("MP_SMTP_RELAY_ALLOW_INSECURE")
|
||||||
|
config.SMTPRelayConfig.Auth = os.Getenv("MP_SMTP_RELAY_AUTH")
|
||||||
|
config.SMTPRelayConfig.Username = os.Getenv("MP_SMTP_RELAY_USERNAME")
|
||||||
|
config.SMTPRelayConfig.Password = os.Getenv("MP_SMTP_RELAY_PASSWORD")
|
||||||
|
config.SMTPRelayConfig.Secret = os.Getenv("MP_SMTP_RELAY_SECRET")
|
||||||
|
config.SMTPRelayConfig.ReturnPath = os.Getenv("MP_SMTP_RELAY_RETURN_PATH")
|
||||||
|
config.SMTPRelayConfig.AllowedRecipients = os.Getenv("MP_SMTP_RELAY_ALLOWED_RECIPIENTS")
|
||||||
|
|
||||||
// POP3 server
|
// POP3 server
|
||||||
if len(os.Getenv("MP_POP3_BIND_ADDR")) > 0 {
|
if len(os.Getenv("MP_POP3_BIND_ADDR")) > 0 {
|
||||||
|
@ -94,7 +94,7 @@ var (
|
|||||||
SMTPRelayConfigFile string
|
SMTPRelayConfigFile string
|
||||||
|
|
||||||
// SMTPRelayConfig to parse a yaml file and store config of relay SMTP server
|
// SMTPRelayConfig to parse a yaml file and store config of relay SMTP server
|
||||||
SMTPRelayConfig smtpRelayConfigStruct
|
SMTPRelayConfig SMTPRelayConfigStruct
|
||||||
|
|
||||||
// SMTPStrictRFCHeaders will return an error if the email headers contain <CR><CR><LF> (\r\r\n)
|
// SMTPStrictRFCHeaders will return an error if the email headers contain <CR><CR><LF> (\r\r\n)
|
||||||
// @see https://github.com/axllent/mailpit/issues/87 & https://github.com/axllent/mailpit/issues/153
|
// @see https://github.com/axllent/mailpit/issues/87 & https://github.com/axllent/mailpit/issues/153
|
||||||
@ -154,18 +154,20 @@ type AutoTag struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SMTPRelayConfigStruct struct for parsing yaml & storing variables
|
// SMTPRelayConfigStruct struct for parsing yaml & storing variables
|
||||||
type smtpRelayConfigStruct struct {
|
type SMTPRelayConfigStruct struct {
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
STARTTLS bool `yaml:"starttls"`
|
STARTTLS bool `yaml:"starttls"`
|
||||||
AllowInsecure bool `yaml:"allow-insecure"`
|
AllowInsecure bool `yaml:"allow-insecure"`
|
||||||
Auth string `yaml:"auth"` // none, plain, login, cram-md5
|
Auth string `yaml:"auth"` // none, plain, login, cram-md5
|
||||||
Username string `yaml:"username"` // plain & cram-md5
|
Username string `yaml:"username"` // plain & cram-md5
|
||||||
Password string `yaml:"password"` // plain
|
Password string `yaml:"password"` // plain
|
||||||
Secret string `yaml:"secret"` // cram-md5
|
Secret string `yaml:"secret"` // cram-md5
|
||||||
ReturnPath string `yaml:"return-path"` // allow overriding the bounce address
|
ReturnPath string `yaml:"return-path"` // allow overriding the bounce address
|
||||||
RecipientAllowlist string `yaml:"recipient-allowlist"` // regex, if set needs to match for mails to be relayed
|
AllowedRecipients string `yaml:"allowed-recipients"` // regex, if set needs to match for mails to be relayed
|
||||||
RecipientAllowlistRegexp *regexp.Regexp
|
AllowedRecipientsRegexp *regexp.Regexp // compiled regexp using AllowedRecipients
|
||||||
|
// DEPRECATED 2024/03/12
|
||||||
|
RecipientAllowlist string `yaml:"recipient-allowlist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyConfig wil do some basic checking
|
// VerifyConfig wil do some basic checking
|
||||||
@ -371,6 +373,11 @@ func VerifyConfig() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// separate relay config validation to account for environment variables
|
||||||
|
if err := validateRelayConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !ReleaseEnabled && SMTPRelayAllIncoming {
|
if !ReleaseEnabled && SMTPRelayAllIncoming {
|
||||||
return errors.New("[smtp] relay config must be set to relay all messages")
|
return errors.New("[smtp] relay config must be set to relay all messages")
|
||||||
}
|
}
|
||||||
@ -383,7 +390,7 @@ func VerifyConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse & validate the SMTPRelayConfigFile (if set)
|
// Parse the SMTPRelayConfigFile (if set)
|
||||||
func parseRelayConfig(c string) error {
|
func parseRelayConfig(c string) error {
|
||||||
if c == "" {
|
if c == "" {
|
||||||
return nil
|
return nil
|
||||||
@ -408,6 +415,23 @@ func parseRelayConfig(c string) error {
|
|||||||
return errors.New("[smtp] relay host not set")
|
return errors.New("[smtp] relay host not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEPRECATED 2024/03/12
|
||||||
|
if SMTPRelayConfig.RecipientAllowlist != "" {
|
||||||
|
logger.Log().Warn("[smtp] relay 'recipient-allowlist' is deprecated, use 'allowed_recipients' instead")
|
||||||
|
if SMTPRelayConfig.AllowedRecipients == "" {
|
||||||
|
SMTPRelayConfig.AllowedRecipients = SMTPRelayConfig.RecipientAllowlist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the SMTPRelayConfig (if Host is set)
|
||||||
|
func validateRelayConfig() error {
|
||||||
|
if SMTPRelayConfig.Host == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if SMTPRelayConfig.Port == 0 {
|
if SMTPRelayConfig.Port == 0 {
|
||||||
SMTPRelayConfig.Port = 25 // default
|
SMTPRelayConfig.Port = 25 // default
|
||||||
}
|
}
|
||||||
@ -418,17 +442,17 @@ func parseRelayConfig(c string) error {
|
|||||||
SMTPRelayConfig.Auth = "none"
|
SMTPRelayConfig.Auth = "none"
|
||||||
} else if SMTPRelayConfig.Auth == "plain" {
|
} else if SMTPRelayConfig.Auth == "plain" {
|
||||||
if SMTPRelayConfig.Username == "" || SMTPRelayConfig.Password == "" {
|
if SMTPRelayConfig.Username == "" || SMTPRelayConfig.Password == "" {
|
||||||
return fmt.Errorf("[smtp] relay host username or password not set for PLAIN authentication (%s)", c)
|
return fmt.Errorf("[smtp] relay host username or password not set for PLAIN authentication")
|
||||||
}
|
}
|
||||||
} else if SMTPRelayConfig.Auth == "login" {
|
} else if SMTPRelayConfig.Auth == "login" {
|
||||||
SMTPRelayConfig.Auth = "login"
|
SMTPRelayConfig.Auth = "login"
|
||||||
if SMTPRelayConfig.Username == "" || SMTPRelayConfig.Password == "" {
|
if SMTPRelayConfig.Username == "" || SMTPRelayConfig.Password == "" {
|
||||||
return fmt.Errorf("[smtp] relay host username or password not set for LOGIN authentication (%s)", c)
|
return fmt.Errorf("[smtp] relay host username or password not set for LOGIN authentication")
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(SMTPRelayConfig.Auth, "cram") {
|
} else if strings.HasPrefix(SMTPRelayConfig.Auth, "cram") {
|
||||||
SMTPRelayConfig.Auth = "cram-md5"
|
SMTPRelayConfig.Auth = "cram-md5"
|
||||||
if SMTPRelayConfig.Username == "" || SMTPRelayConfig.Secret == "" {
|
if SMTPRelayConfig.Username == "" || SMTPRelayConfig.Secret == "" {
|
||||||
return fmt.Errorf("[smtp] relay host username or secret not set for CRAM-MD5 authentication (%s)", c)
|
return fmt.Errorf("[smtp] relay host username or secret not set for CRAM-MD5 authentication")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("[smtp] relay authentication method not supported: %s", SMTPRelayConfig.Auth)
|
return fmt.Errorf("[smtp] relay authentication method not supported: %s", SMTPRelayConfig.Auth)
|
||||||
@ -438,15 +462,15 @@ func parseRelayConfig(c string) error {
|
|||||||
|
|
||||||
logger.Log().Infof("[smtp] enabling message relaying via %s:%d", SMTPRelayConfig.Host, SMTPRelayConfig.Port)
|
logger.Log().Infof("[smtp] enabling message relaying via %s:%d", SMTPRelayConfig.Host, SMTPRelayConfig.Port)
|
||||||
|
|
||||||
allowlistRegexp, err := regexp.Compile(SMTPRelayConfig.RecipientAllowlist)
|
allowlistRegexp, err := regexp.Compile(SMTPRelayConfig.AllowedRecipients)
|
||||||
|
|
||||||
if SMTPRelayConfig.RecipientAllowlist != "" {
|
if SMTPRelayConfig.AllowedRecipients != "" {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("[smtp] failed to compile relay recipient allowlist regexp: %s", err.Error())
|
return fmt.Errorf("[smtp] failed to compile relay recipient allowlist regexp: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
SMTPRelayConfig.RecipientAllowlistRegexp = allowlistRegexp
|
SMTPRelayConfig.AllowedRecipientsRegexp = allowlistRegexp
|
||||||
logger.Log().Infof("[smtp] relay recipient allowlist is active with the following regexp: %s", SMTPRelayConfig.RecipientAllowlist)
|
logger.Log().Infof("[smtp] relay recipient allowlist is active with the following regexp: %s", SMTPRelayConfig.AllowedRecipients)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +642,7 @@ func ReleaseMessage(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.SMTPRelayConfig.RecipientAllowlistRegexp != nil && !config.SMTPRelayConfig.RecipientAllowlistRegexp.MatchString(address.Address) {
|
if config.SMTPRelayConfig.AllowedRecipientsRegexp != nil && !config.SMTPRelayConfig.AllowedRecipientsRegexp.MatchString(address.Address) {
|
||||||
httpError(w, "Mail address does not match allowlist: "+to)
|
httpError(w, "Mail address does not match allowlist: "+to)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,10 @@ type webUIConfiguration struct {
|
|||||||
SMTPServer string
|
SMTPServer string
|
||||||
// Enforced Return-Path (if set) for relay bounces
|
// Enforced Return-Path (if set) for relay bounces
|
||||||
ReturnPath string
|
ReturnPath string
|
||||||
// Allowlist of accepted recipients
|
// Only allow relaying to these recipients (regex)
|
||||||
|
AllowedRecipients string
|
||||||
|
// DEPRECATED 2024/03/12
|
||||||
|
// swagger:ignore
|
||||||
RecipientAllowlist string
|
RecipientAllowlist string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +60,9 @@ func WebUIConfig(w http.ResponseWriter, _ *http.Request) {
|
|||||||
if config.ReleaseEnabled {
|
if config.ReleaseEnabled {
|
||||||
conf.MessageRelay.SMTPServer = fmt.Sprintf("%s:%d", config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
|
conf.MessageRelay.SMTPServer = fmt.Sprintf("%s:%d", config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
|
||||||
conf.MessageRelay.ReturnPath = config.SMTPRelayConfig.ReturnPath
|
conf.MessageRelay.ReturnPath = config.SMTPRelayConfig.ReturnPath
|
||||||
conf.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.RecipientAllowlist
|
conf.MessageRelay.AllowedRecipients = config.SMTPRelayConfig.AllowedRecipients
|
||||||
|
// DEPRECATED 2024/03/12
|
||||||
|
conf.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.AllowedRecipients
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.DisableHTMLCheck = config.DisableHTMLCheck
|
conf.DisableHTMLCheck = config.DisableHTMLCheck
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func allowedRecipients(to []string) []string {
|
func allowedRecipients(to []string) []string {
|
||||||
if config.SMTPRelayConfig.RecipientAllowlistRegexp == nil {
|
if config.SMTPRelayConfig.AllowedRecipientsRegexp == nil {
|
||||||
return to
|
return to
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,8 +26,8 @@ func allowedRecipients(to []string) []string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.SMTPRelayConfig.RecipientAllowlistRegexp.MatchString(address.Address) {
|
if !config.SMTPRelayConfig.AllowedRecipientsRegexp.MatchString(address.Address) {
|
||||||
logger.Log().Debugf("[smtp] not allowed to relay to %s: does not match the allowlist %s", recipient, config.SMTPRelayConfig.RecipientAllowlist)
|
logger.Log().Debugf("[smtp] not allowed to relay to %s: does not match the allowlist %s", recipient, config.SMTPRelayConfig.AllowedRecipients)
|
||||||
} else {
|
} else {
|
||||||
ar = append(ar, recipient)
|
ar = append(ar, recipient)
|
||||||
}
|
}
|
||||||
|
@ -126,10 +126,10 @@ export default {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-text text-center" v-if="mailbox.uiConfig.MessageRelay.RecipientAllowlist != ''">
|
<div class="form-text text-center" v-if="mailbox.uiConfig.MessageRelay.AllowedRecipients != ''">
|
||||||
Note: A recipient allowlist has been configured. Any mail address not matching it will be rejected.
|
Note: A recipient allowlist has been configured. Any mail address not matching it will be rejected.
|
||||||
<br class="d-none d-md-inline">
|
<br class="d-none d-md-inline">
|
||||||
Configured allowlist: <b>{{ mailbox.uiConfig.MessageRelay.RecipientAllowlist }}</b>
|
Allowed recipients: <b>{{ mailbox.uiConfig.MessageRelay.AllowedRecipients }}</b>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-text text-center">
|
<div class="form-text text-center">
|
||||||
Note: For testing purposes, a unique Message-Id will be generated on send.
|
Note: For testing purposes, a unique Message-Id will be generated on send.
|
||||||
|
@ -1407,14 +1407,14 @@
|
|||||||
"description": "Message Relay information",
|
"description": "Message Relay information",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"AllowedRecipients": {
|
||||||
|
"description": "Only allow relaying to these recipients (regex)",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"Enabled": {
|
"Enabled": {
|
||||||
"description": "Whether message relaying (release) is enabled",
|
"description": "Whether message relaying (release) is enabled",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"RecipientAllowlist": {
|
|
||||||
"description": "Allowlist of accepted recipients",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"ReturnPath": {
|
"ReturnPath": {
|
||||||
"description": "Enforced Return-Path (if set) for relay bounces",
|
"description": "Enforced Return-Path (if set) for relay bounces",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user