grafana/pkg/setting/setting_smtp.go
owensmallwood d5b9602a79
Config: Can add static headers to email messages (#79365)
* Can add allowed custom headers to an email Message. WIP.

* adds slug as a custom email header to all outgoing emails

* Headers are static - declared as key/value pairs in config. All static headers get added to emails.

* updates comment

* adds tests for parsing smtp static headers

* updates test to assert static headers are included when building email

* updates test to use multiple static headers

* updates test names

* fixes linting issue with error

* ignore gocyclo for loading config

* updates email headers in tests to be formatted properly

* add static headers first

* updates tests to assert that regular headers like From cant be overwritten

* ensures only the header is in a valid format for smtp and not the value

* updates comment and error message wording

* adds to docs and ini sample files

* updates smtp.static_headers docs examples formatting

* removes lines commented with semi colons

* prettier:write

* renames var
2023-12-14 12:59:43 -06:00

78 lines
2.2 KiB
Go

package setting
import (
"fmt"
"regexp"
"github.com/grafana/grafana/pkg/util"
)
type SmtpSettings struct {
Enabled bool
Host string
User string
Password string
CertFile string
KeyFile string
FromAddress string
FromName string
EhloIdentity string
StartTLSPolicy string
SkipVerify bool
StaticHeaders map[string]string
SendWelcomeEmailOnSignUp bool
TemplatesPatterns []string
ContentTypes []string
}
// validates mail headers
var mailHeaderRegex = regexp.MustCompile(`^[A-Z][A-Za-z0-9]*(-[A-Z][A-Za-z0-9]*)*$`)
func (cfg *Cfg) readSmtpSettings() error {
sec := cfg.Raw.Section("smtp")
cfg.Smtp.Enabled = sec.Key("enabled").MustBool(false)
cfg.Smtp.Host = sec.Key("host").String()
cfg.Smtp.User = sec.Key("user").String()
cfg.Smtp.Password = sec.Key("password").String()
cfg.Smtp.CertFile = sec.Key("cert_file").String()
cfg.Smtp.KeyFile = sec.Key("key_file").String()
cfg.Smtp.FromAddress = sec.Key("from_address").String()
cfg.Smtp.FromName = sec.Key("from_name").String()
cfg.Smtp.EhloIdentity = sec.Key("ehlo_identity").String()
cfg.Smtp.StartTLSPolicy = sec.Key("startTLS_policy").String()
cfg.Smtp.SkipVerify = sec.Key("skip_verify").MustBool(false)
emails := cfg.Raw.Section("emails")
cfg.Smtp.SendWelcomeEmailOnSignUp = emails.Key("welcome_email_on_sign_up").MustBool(false)
cfg.Smtp.TemplatesPatterns = util.SplitString(emails.Key("templates_pattern").MustString("emails/*.html, emails/*.txt"))
cfg.Smtp.ContentTypes = util.SplitString(emails.Key("content_types").MustString("text/html"))
// populate static headers
if err := cfg.readGrafanaSmtpStaticHeaders(); err != nil {
return err
}
return nil
}
func validHeader(header string) bool {
return mailHeaderRegex.MatchString(header)
}
func (cfg *Cfg) readGrafanaSmtpStaticHeaders() error {
staticHeadersSection := cfg.Raw.Section("smtp.static_headers")
keys := staticHeadersSection.Keys()
cfg.Smtp.StaticHeaders = make(map[string]string, len(keys))
for _, key := range keys {
if !validHeader(key.Name()) {
return fmt.Errorf("header %q in [smtp.static_headers] configuration: must follow canonical MIME form", key.Name())
}
cfg.Smtp.StaticHeaders[key.Name()] = key.Value()
}
return nil
}