Backport #21945 Unfortunately the fallback configuration code for [mailer] that were added in #18982 are incorrect. When you read a value from an ini section that key is added. This leads to a failure of the fallback mechanism. Further there is also a spelling mistake in the startTLS configuration. This PR restructures the mailer code to first map the deprecated settings on to the new ones - and then use ini.MapTo to map those on to the struct with additional validation as necessary. Ref #21744 Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
parent
cddceb9dca
commit
888384a631
5 changed files with 96 additions and 94 deletions
|
@ -1550,7 +1550,7 @@ ROUTER = console
|
||||||
;; Prefix displayed before subject in mail
|
;; Prefix displayed before subject in mail
|
||||||
;SUBJECT_PREFIX =
|
;SUBJECT_PREFIX =
|
||||||
;;
|
;;
|
||||||
;; Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy".
|
;; Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy".
|
||||||
;; - sendmail: use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
|
;; - sendmail: use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
|
||||||
;; - dummy: send email messages to the log as a testing phase.
|
;; - dummy: send email messages to the log as a testing phase.
|
||||||
;; If your provider does not explicitly say which protocol it uses but does provide a port,
|
;; If your provider does not explicitly say which protocol it uses but does provide a port,
|
||||||
|
|
|
@ -672,7 +672,7 @@ and
|
||||||
[Gitea 1.17 configuration document](https://github.com/go-gitea/gitea/blob/release/v1.17/docs/content/doc/advanced/config-cheat-sheet.en-us.md)
|
[Gitea 1.17 configuration document](https://github.com/go-gitea/gitea/blob/release/v1.17/docs/content/doc/advanced/config-cheat-sheet.en-us.md)
|
||||||
|
|
||||||
- `ENABLED`: **false**: Enable to use a mail service.
|
- `ENABLED`: **false**: Enable to use a mail service.
|
||||||
- `PROTOCOL`: **\<empty\>**: Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy". _Before 1.18, this was inferred from a combination of `MAILER_TYPE` and `IS_TLS_ENABLED`._
|
- `PROTOCOL`: **\<empty\>**: Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy". _Before 1.18, this was inferred from a combination of `MAILER_TYPE` and `IS_TLS_ENABLED`._
|
||||||
- SMTP family, if your provider does not explicitly say which protocol it uses but does provide a port, you can set SMTP_PORT instead and this will be inferred.
|
- SMTP family, if your provider does not explicitly say which protocol it uses but does provide a port, you can set SMTP_PORT instead and this will be inferred.
|
||||||
- **sendmail** Use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
|
- **sendmail** Use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
|
||||||
- **dummy** Send email messages to the log as a testing phase.
|
- **dummy** Send email messages to the log as a testing phase.
|
||||||
|
|
|
@ -18,32 +18,33 @@ import (
|
||||||
// Mailer represents mail service.
|
// Mailer represents mail service.
|
||||||
type Mailer struct {
|
type Mailer struct {
|
||||||
// Mailer
|
// Mailer
|
||||||
Name string
|
Name string `ini:"NAME"`
|
||||||
From string
|
From string `ini:"FROM"`
|
||||||
EnvelopeFrom string
|
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
|
||||||
OverrideEnvelopeFrom bool `ini:"-"`
|
OverrideEnvelopeFrom bool `ini:"-"`
|
||||||
FromName string
|
FromName string `ini:"-"`
|
||||||
FromEmail string
|
FromEmail string `ini:"-"`
|
||||||
SendAsPlainText bool
|
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
|
||||||
SubjectPrefix string
|
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
|
||||||
|
|
||||||
// SMTP sender
|
// SMTP sender
|
||||||
Protocol string
|
Protocol string `ini:"PROTOCOL"`
|
||||||
SMTPAddr string
|
SMTPAddr string `ini:"SMTP_ADDR"`
|
||||||
SMTPPort string
|
SMTPPort string `ini:"SMTP_PORT"`
|
||||||
User, Passwd string
|
User string `ini:"USER"`
|
||||||
EnableHelo bool
|
Passwd string `ini:"PASSWD"`
|
||||||
HeloHostname string
|
EnableHelo bool `ini:"ENABLE_HELO"`
|
||||||
ForceTrustServerCert bool
|
HeloHostname string `ini:"HELO_HOSTNAME"`
|
||||||
UseClientCert bool
|
ForceTrustServerCert bool `ini:"FORCE_TRUST_SERVER_CERT"`
|
||||||
ClientCertFile string
|
UseClientCert bool `ini:"USE_CLIENT_CERT"`
|
||||||
ClientKeyFile string
|
ClientCertFile string `ini:"CLIENT_CERT_FILE"`
|
||||||
|
ClientKeyFile string `ini:"CLIENT_KEY_FILE"`
|
||||||
|
|
||||||
// Sendmail sender
|
// Sendmail sender
|
||||||
SendmailPath string
|
SendmailPath string `ini:"SENDMAIL_PATH"`
|
||||||
SendmailArgs []string
|
SendmailArgs []string `ini:"-"`
|
||||||
SendmailTimeout time.Duration
|
SendmailTimeout time.Duration `ini:"SENDMAIL_TIMEOUT"`
|
||||||
SendmailConvertCRLF bool
|
SendmailConvertCRLF bool `ini:"SENDMAIL_CONVERT_CRLF"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MailService the global mailer
|
// MailService the global mailer
|
||||||
|
@ -56,35 +57,12 @@ func newMailService() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
MailService = &Mailer{
|
// Handle Deprecations and map on to new configuration
|
||||||
Name: sec.Key("NAME").MustString(AppName),
|
|
||||||
SendAsPlainText: sec.Key("SEND_AS_PLAIN_TEXT").MustBool(false),
|
|
||||||
|
|
||||||
Protocol: sec.Key("PROTOCOL").In("", []string{"smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy"}),
|
|
||||||
SMTPAddr: sec.Key("SMTP_ADDR").String(),
|
|
||||||
SMTPPort: sec.Key("SMTP_PORT").String(),
|
|
||||||
User: sec.Key("USER").String(),
|
|
||||||
Passwd: sec.Key("PASSWD").String(),
|
|
||||||
EnableHelo: sec.Key("ENABLE_HELO").MustBool(true),
|
|
||||||
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
|
|
||||||
ForceTrustServerCert: sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(false),
|
|
||||||
UseClientCert: sec.Key("USE_CLIENT_CERT").MustBool(false),
|
|
||||||
ClientCertFile: sec.Key("CLIENT_CERT_FILE").String(),
|
|
||||||
ClientKeyFile: sec.Key("CLIENT_KEY_FILE").String(),
|
|
||||||
SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString(""),
|
|
||||||
|
|
||||||
SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"),
|
|
||||||
SendmailTimeout: sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute),
|
|
||||||
SendmailConvertCRLF: sec.Key("SENDMAIL_CONVERT_CRLF").MustBool(true),
|
|
||||||
}
|
|
||||||
MailService.From = sec.Key("FROM").MustString(MailService.User)
|
|
||||||
MailService.EnvelopeFrom = sec.Key("ENVELOPE_FROM").MustString("")
|
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
deprecatedSetting("mailer", "MAILER_TYPE", "mailer", "PROTOCOL")
|
deprecatedSetting("mailer", "MAILER_TYPE", "mailer", "PROTOCOL")
|
||||||
if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") {
|
if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") {
|
||||||
if sec.Key("MAILER_TYPE").String() == "sendmail" {
|
if sec.Key("MAILER_TYPE").String() == "sendmail" {
|
||||||
MailService.Protocol = "sendmail"
|
sec.Key("PROTOCOL").MustString("sendmail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,31 +74,91 @@ func newMailService() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Invalid mailer.HOST (%s): %v", givenHost, err)
|
log.Fatal("Invalid mailer.HOST (%s): %v", givenHost, err)
|
||||||
}
|
}
|
||||||
MailService.SMTPAddr = addr
|
sec.Key("SMTP_ADDR").MustString(addr)
|
||||||
MailService.SMTPPort = port
|
sec.Key("SMTP_PORT").MustString(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
deprecatedSetting("mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL")
|
deprecatedSetting("mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL")
|
||||||
if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") {
|
if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") {
|
||||||
if sec.Key("IS_TLS_ENABLED").MustBool() {
|
if sec.Key("IS_TLS_ENABLED").MustBool() {
|
||||||
MailService.Protocol = "smtps"
|
sec.Key("PROTOCOL").MustString("smtps")
|
||||||
} else {
|
} else {
|
||||||
MailService.Protocol = "smtp+startls"
|
sec.Key("PROTOCOL").MustString("smtp+starttls")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
|
deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
|
||||||
|
if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
|
||||||
|
sec.Key("ENABLE_HELO").MustBool(!sec.Key("DISABLE_HELO").MustBool())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
|
deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
|
||||||
|
if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
|
||||||
|
sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(sec.Key("SKIP_VERIFY").MustBool())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
|
deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
|
||||||
|
if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
|
||||||
|
sec.Key("USE_CLIENT_CERT").MustBool(sec.Key("USE_CERTIFICATE").MustBool())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
|
deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
|
||||||
|
if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
|
||||||
|
sec.Key("CERT_FILE").MustString(sec.Key("CERT_FILE").String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
|
deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
|
||||||
|
if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
|
||||||
|
sec.Key("KEY_FILE").MustString(sec.Key("KEY_FILE").String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: DEPRECATED to be removed in v1.19.0
|
||||||
|
deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
|
||||||
|
if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
|
||||||
|
sec.Key("SEND_AS_PLAIN_TEXT").MustBool(!sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sec.HasKey("PROTOCOL") && sec.Key("PROTOCOL").String() == "smtp+startls" {
|
||||||
|
log.Error("Deprecated fallback `[mailer]` `PROTOCOL = smtp+startls` present. Use `[mailer]` `PROTOCOL = smtp+starttls`` instead. This fallback will be removed in v1.19.0")
|
||||||
|
sec.Key("PROTOCOL").SetValue("smtp+starttls")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default values & validate
|
||||||
|
sec.Key("NAME").MustString(AppName)
|
||||||
|
sec.Key("PROTOCOL").In("", []string{"smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy"})
|
||||||
|
sec.Key("ENABLE_HELO").MustBool(true)
|
||||||
|
sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(false)
|
||||||
|
sec.Key("USE_CLIENT_CERT").MustBool(false)
|
||||||
|
sec.Key("SENDMAIL_PATH").MustString("sendmail")
|
||||||
|
sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute)
|
||||||
|
sec.Key("SENDMAIL_CONVERT_CRLF").MustBool(true)
|
||||||
|
sec.Key("FROM").MustString(sec.Key("USER").String())
|
||||||
|
|
||||||
|
// Now map the values on to the MailService
|
||||||
|
MailService = &Mailer{}
|
||||||
|
if err := sec.MapTo(MailService); err != nil {
|
||||||
|
log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infer SMTPPort if not set
|
||||||
if MailService.SMTPPort == "" {
|
if MailService.SMTPPort == "" {
|
||||||
switch MailService.Protocol {
|
switch MailService.Protocol {
|
||||||
case "smtp":
|
case "smtp":
|
||||||
MailService.SMTPPort = "25"
|
MailService.SMTPPort = "25"
|
||||||
case "smtps":
|
case "smtps":
|
||||||
MailService.SMTPPort = "465"
|
MailService.SMTPPort = "465"
|
||||||
case "smtp+startls":
|
case "smtp+starttls":
|
||||||
MailService.SMTPPort = "587"
|
MailService.SMTPPort = "587"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Infer Protocol
|
||||||
if MailService.Protocol == "" {
|
if MailService.Protocol == "" {
|
||||||
if strings.ContainsAny(MailService.SMTPAddr, "/\\") {
|
if strings.ContainsAny(MailService.SMTPAddr, "/\\") {
|
||||||
MailService.Protocol = "smtp+unix"
|
MailService.Protocol = "smtp+unix"
|
||||||
|
@ -131,7 +169,7 @@ func newMailService() {
|
||||||
case "465":
|
case "465":
|
||||||
MailService.Protocol = "smtps"
|
MailService.Protocol = "smtps"
|
||||||
case "587":
|
case "587":
|
||||||
MailService.Protocol = "smtp+startls"
|
MailService.Protocol = "smtp+starttls"
|
||||||
default:
|
default:
|
||||||
log.Error("unable to infer unspecified mailer.PROTOCOL from mailer.SMTP_PORT = %q, assume using smtps", MailService.SMTPPort)
|
log.Error("unable to infer unspecified mailer.PROTOCOL from mailer.SMTP_PORT = %q, assume using smtps", MailService.SMTPPort)
|
||||||
MailService.Protocol = "smtps"
|
MailService.Protocol = "smtps"
|
||||||
|
@ -151,42 +189,6 @@ func newMailService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
|
||||||
deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
|
|
||||||
if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
|
|
||||||
MailService.EnableHelo = !sec.Key("DISABLE_HELO").MustBool()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
|
||||||
deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
|
|
||||||
if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
|
|
||||||
MailService.ForceTrustServerCert = sec.Key("SKIP_VERIFY").MustBool()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
|
||||||
deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
|
|
||||||
if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
|
|
||||||
MailService.UseClientCert = sec.Key("USE_CLIENT_CERT").MustBool()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
|
||||||
deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
|
|
||||||
if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
|
|
||||||
MailService.ClientCertFile = sec.Key("CERT_FILE").String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
|
||||||
deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
|
|
||||||
if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
|
|
||||||
MailService.ClientKeyFile = sec.Key("KEY_FILE").String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: DEPRECATED to be removed in v1.19.0
|
|
||||||
deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
|
|
||||||
if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
|
|
||||||
MailService.SendAsPlainText = !sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if MailService.From != "" {
|
if MailService.From != "" {
|
||||||
parsed, err := mail.ParseAddress(MailService.From)
|
parsed, err := mail.ParseAddress(MailService.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -603,7 +603,7 @@ func LoadForTest(extraConfigs ...string) {
|
||||||
|
|
||||||
func deprecatedSetting(oldSection, oldKey, newSection, newKey string) {
|
func deprecatedSetting(oldSection, oldKey, newSection, newKey string) {
|
||||||
if Cfg.Section(oldSection).HasKey(oldKey) {
|
if Cfg.Section(oldSection).HasKey(oldKey) {
|
||||||
log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.18.0", oldSection, oldKey, newSection, newKey)
|
log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
var tlsconfig *tls.Config
|
var tlsconfig *tls.Config
|
||||||
if opts.Protocol == "smtps" || opts.Protocol == "smtp+startls" {
|
if opts.Protocol == "smtps" || opts.Protocol == "smtp+starttls" {
|
||||||
tlsconfig = &tls.Config{
|
tlsconfig = &tls.Config{
|
||||||
InsecureSkipVerify: opts.ForceTrustServerCert,
|
InsecureSkipVerify: opts.ForceTrustServerCert,
|
||||||
ServerName: opts.SMTPAddr,
|
ServerName: opts.SMTPAddr,
|
||||||
|
@ -208,7 +208,7 @@ func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Protocol == "smtp+startls" {
|
if opts.Protocol == "smtp+starttls" {
|
||||||
hasStartTLS, _ := client.Extension("STARTTLS")
|
hasStartTLS, _ := client.Extension("STARTTLS")
|
||||||
if hasStartTLS {
|
if hasStartTLS {
|
||||||
if err = client.StartTLS(tlsconfig); err != nil {
|
if err = client.StartTLS(tlsconfig); err != nil {
|
||||||
|
|
Reference in a new issue