Skip to content

Commit f6fd501

Browse files
authored
Correct the fallbacks for mailer configuration (go-gitea#21945)
Unfortunately the fallback configuration code for [mailer] that were added in go-gitea#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 go-gitea#21744 Signed-off-by: Andrew Thornton <[email protected]>
1 parent 32590db commit f6fd501

File tree

5 files changed

+96
-94
lines changed

5 files changed

+96
-94
lines changed

custom/conf/app.example.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,7 @@ ROUTER = console
15901590
;; Prefix displayed before subject in mail
15911591
;SUBJECT_PREFIX =
15921592
;;
1593-
;; Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy".
1593+
;; Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy".
15941594
;; - sendmail: use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
15951595
;; - dummy: send email messages to the log as a testing phase.
15961596
;; If your provider does not explicitly say which protocol it uses but does provide a port,

docs/content/doc/advanced/config-cheat-sheet.en-us.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ and
713713
[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)
714714

715715
- `ENABLED`: **false**: Enable to use a mail service.
716-
- `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`._
716+
- `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`._
717717
- 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.
718718
- **sendmail** Use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
719719
- **dummy** Send email messages to the log as a testing phase.

modules/setting/mailer.go

+91-89
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,33 @@ import (
1818
// Mailer represents mail service.
1919
type Mailer struct {
2020
// Mailer
21-
Name string
22-
From string
23-
EnvelopeFrom string
24-
OverrideEnvelopeFrom bool `ini:"-"`
25-
FromName string
26-
FromEmail string
27-
SendAsPlainText bool
28-
SubjectPrefix string
21+
Name string `ini:"NAME"`
22+
From string `ini:"FROM"`
23+
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
24+
OverrideEnvelopeFrom bool `ini:"-"`
25+
FromName string `ini:"-"`
26+
FromEmail string `ini:"-"`
27+
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
28+
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
2929

3030
// SMTP sender
31-
Protocol string
32-
SMTPAddr string
33-
SMTPPort string
34-
User, Passwd string
35-
EnableHelo bool
36-
HeloHostname string
37-
ForceTrustServerCert bool
38-
UseClientCert bool
39-
ClientCertFile string
40-
ClientKeyFile string
31+
Protocol string `ini:"PROTOCOL"`
32+
SMTPAddr string `ini:"SMTP_ADDR"`
33+
SMTPPort string `ini:"SMTP_PORT"`
34+
User string `ini:"USER"`
35+
Passwd string `ini:"PASSWD"`
36+
EnableHelo bool `ini:"ENABLE_HELO"`
37+
HeloHostname string `ini:"HELO_HOSTNAME"`
38+
ForceTrustServerCert bool `ini:"FORCE_TRUST_SERVER_CERT"`
39+
UseClientCert bool `ini:"USE_CLIENT_CERT"`
40+
ClientCertFile string `ini:"CLIENT_CERT_FILE"`
41+
ClientKeyFile string `ini:"CLIENT_KEY_FILE"`
4142

4243
// Sendmail sender
43-
SendmailPath string
44-
SendmailArgs []string
45-
SendmailTimeout time.Duration
46-
SendmailConvertCRLF bool
44+
SendmailPath string `ini:"SENDMAIL_PATH"`
45+
SendmailArgs []string `ini:"-"`
46+
SendmailTimeout time.Duration `ini:"SENDMAIL_TIMEOUT"`
47+
SendmailConvertCRLF bool `ini:"SENDMAIL_CONVERT_CRLF"`
4748
}
4849

4950
// MailService the global mailer
@@ -56,35 +57,12 @@ func newMailService() {
5657
return
5758
}
5859

59-
MailService = &Mailer{
60-
Name: sec.Key("NAME").MustString(AppName),
61-
SendAsPlainText: sec.Key("SEND_AS_PLAIN_TEXT").MustBool(false),
62-
63-
Protocol: sec.Key("PROTOCOL").In("", []string{"smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy"}),
64-
SMTPAddr: sec.Key("SMTP_ADDR").String(),
65-
SMTPPort: sec.Key("SMTP_PORT").String(),
66-
User: sec.Key("USER").String(),
67-
Passwd: sec.Key("PASSWD").String(),
68-
EnableHelo: sec.Key("ENABLE_HELO").MustBool(true),
69-
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
70-
ForceTrustServerCert: sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(false),
71-
UseClientCert: sec.Key("USE_CLIENT_CERT").MustBool(false),
72-
ClientCertFile: sec.Key("CLIENT_CERT_FILE").String(),
73-
ClientKeyFile: sec.Key("CLIENT_KEY_FILE").String(),
74-
SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString(""),
75-
76-
SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"),
77-
SendmailTimeout: sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute),
78-
SendmailConvertCRLF: sec.Key("SENDMAIL_CONVERT_CRLF").MustBool(true),
79-
}
80-
MailService.From = sec.Key("FROM").MustString(MailService.User)
81-
MailService.EnvelopeFrom = sec.Key("ENVELOPE_FROM").MustString("")
82-
60+
// Handle Deprecations and map on to new configuration
8361
// FIXME: DEPRECATED to be removed in v1.19.0
8462
deprecatedSetting("mailer", "MAILER_TYPE", "mailer", "PROTOCOL")
8563
if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") {
8664
if sec.Key("MAILER_TYPE").String() == "sendmail" {
87-
MailService.Protocol = "sendmail"
65+
sec.Key("PROTOCOL").MustString("sendmail")
8866
}
8967
}
9068

@@ -96,31 +74,91 @@ func newMailService() {
9674
if err != nil {
9775
log.Fatal("Invalid mailer.HOST (%s): %v", givenHost, err)
9876
}
99-
MailService.SMTPAddr = addr
100-
MailService.SMTPPort = port
77+
sec.Key("SMTP_ADDR").MustString(addr)
78+
sec.Key("SMTP_PORT").MustString(port)
10179
}
10280

10381
// FIXME: DEPRECATED to be removed in v1.19.0
10482
deprecatedSetting("mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL")
10583
if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") {
10684
if sec.Key("IS_TLS_ENABLED").MustBool() {
107-
MailService.Protocol = "smtps"
85+
sec.Key("PROTOCOL").MustString("smtps")
10886
} else {
109-
MailService.Protocol = "smtp+startls"
87+
sec.Key("PROTOCOL").MustString("smtp+starttls")
11088
}
11189
}
11290

91+
// FIXME: DEPRECATED to be removed in v1.19.0
92+
deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
93+
if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
94+
sec.Key("ENABLE_HELO").MustBool(!sec.Key("DISABLE_HELO").MustBool())
95+
}
96+
97+
// FIXME: DEPRECATED to be removed in v1.19.0
98+
deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
99+
if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
100+
sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(sec.Key("SKIP_VERIFY").MustBool())
101+
}
102+
103+
// FIXME: DEPRECATED to be removed in v1.19.0
104+
deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
105+
if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
106+
sec.Key("USE_CLIENT_CERT").MustBool(sec.Key("USE_CERTIFICATE").MustBool())
107+
}
108+
109+
// FIXME: DEPRECATED to be removed in v1.19.0
110+
deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
111+
if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
112+
sec.Key("CERT_FILE").MustString(sec.Key("CERT_FILE").String())
113+
}
114+
115+
// FIXME: DEPRECATED to be removed in v1.19.0
116+
deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
117+
if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
118+
sec.Key("KEY_FILE").MustString(sec.Key("KEY_FILE").String())
119+
}
120+
121+
// FIXME: DEPRECATED to be removed in v1.19.0
122+
deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
123+
if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
124+
sec.Key("SEND_AS_PLAIN_TEXT").MustBool(!sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false))
125+
}
126+
127+
if sec.HasKey("PROTOCOL") && sec.Key("PROTOCOL").String() == "smtp+startls" {
128+
log.Error("Deprecated fallback `[mailer]` `PROTOCOL = smtp+startls` present. Use `[mailer]` `PROTOCOL = smtp+starttls`` instead. This fallback will be removed in v1.19.0")
129+
sec.Key("PROTOCOL").SetValue("smtp+starttls")
130+
}
131+
132+
// Set default values & validate
133+
sec.Key("NAME").MustString(AppName)
134+
sec.Key("PROTOCOL").In("", []string{"smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy"})
135+
sec.Key("ENABLE_HELO").MustBool(true)
136+
sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(false)
137+
sec.Key("USE_CLIENT_CERT").MustBool(false)
138+
sec.Key("SENDMAIL_PATH").MustString("sendmail")
139+
sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute)
140+
sec.Key("SENDMAIL_CONVERT_CRLF").MustBool(true)
141+
sec.Key("FROM").MustString(sec.Key("USER").String())
142+
143+
// Now map the values on to the MailService
144+
MailService = &Mailer{}
145+
if err := sec.MapTo(MailService); err != nil {
146+
log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err)
147+
}
148+
149+
// Infer SMTPPort if not set
113150
if MailService.SMTPPort == "" {
114151
switch MailService.Protocol {
115152
case "smtp":
116153
MailService.SMTPPort = "25"
117154
case "smtps":
118155
MailService.SMTPPort = "465"
119-
case "smtp+startls":
156+
case "smtp+starttls":
120157
MailService.SMTPPort = "587"
121158
}
122159
}
123160

161+
// Infer Protocol
124162
if MailService.Protocol == "" {
125163
if strings.ContainsAny(MailService.SMTPAddr, "/\\") {
126164
MailService.Protocol = "smtp+unix"
@@ -131,7 +169,7 @@ func newMailService() {
131169
case "465":
132170
MailService.Protocol = "smtps"
133171
case "587":
134-
MailService.Protocol = "smtp+startls"
172+
MailService.Protocol = "smtp+starttls"
135173
default:
136174
log.Error("unable to infer unspecified mailer.PROTOCOL from mailer.SMTP_PORT = %q, assume using smtps", MailService.SMTPPort)
137175
MailService.Protocol = "smtps"
@@ -151,42 +189,6 @@ func newMailService() {
151189
}
152190
}
153191

154-
// FIXME: DEPRECATED to be removed in v1.19.0
155-
deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
156-
if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
157-
MailService.EnableHelo = !sec.Key("DISABLE_HELO").MustBool()
158-
}
159-
160-
// FIXME: DEPRECATED to be removed in v1.19.0
161-
deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
162-
if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
163-
MailService.ForceTrustServerCert = sec.Key("SKIP_VERIFY").MustBool()
164-
}
165-
166-
// FIXME: DEPRECATED to be removed in v1.19.0
167-
deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
168-
if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
169-
MailService.UseClientCert = sec.Key("USE_CLIENT_CERT").MustBool()
170-
}
171-
172-
// FIXME: DEPRECATED to be removed in v1.19.0
173-
deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
174-
if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
175-
MailService.ClientCertFile = sec.Key("CERT_FILE").String()
176-
}
177-
178-
// FIXME: DEPRECATED to be removed in v1.19.0
179-
deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
180-
if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
181-
MailService.ClientKeyFile = sec.Key("KEY_FILE").String()
182-
}
183-
184-
// FIXME: DEPRECATED to be removed in v1.19.0
185-
deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
186-
if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
187-
MailService.SendAsPlainText = !sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false)
188-
}
189-
190192
if MailService.From != "" {
191193
parsed, err := mail.ParseAddress(MailService.From)
192194
if err != nil {

modules/setting/setting.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ func LoadForTest(extraConfigs ...string) {
605605

606606
func deprecatedSetting(oldSection, oldKey, newSection, newKey string) {
607607
if Cfg.Section(oldSection).HasKey(oldKey) {
608-
log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.18.0", oldSection, oldKey, newSection, newKey)
608+
log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey)
609609
}
610610
}
611611

services/mailer/mailer.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
166166
defer conn.Close()
167167

168168
var tlsconfig *tls.Config
169-
if opts.Protocol == "smtps" || opts.Protocol == "smtp+startls" {
169+
if opts.Protocol == "smtps" || opts.Protocol == "smtp+starttls" {
170170
tlsconfig = &tls.Config{
171171
InsecureSkipVerify: opts.ForceTrustServerCert,
172172
ServerName: opts.SMTPAddr,
@@ -208,7 +208,7 @@ func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
208208
}
209209
}
210210

211-
if opts.Protocol == "smtp+startls" {
211+
if opts.Protocol == "smtp+starttls" {
212212
hasStartTLS, _ := client.Extension("STARTTLS")
213213
if hasStartTLS {
214214
if err = client.StartTLS(tlsconfig); err != nil {

0 commit comments

Comments
 (0)