From b59875aa123f2cc3a5026d30ac557e99c05603a6 Mon Sep 17 00:00:00 2001 From: Garionion Date: Wed, 8 Dec 2021 08:34:23 +0100 Subject: [PATCH] allways set a message-id on mails (#17900) * allways set a message-id on mails * Add unit tests for mailer & Message-ID Co-authored-by: wxiaoguang Co-authored-by: Lunny Xiao --- modules/setting/setting.go | 16 +++++++++----- services/mailer/mailer.go | 16 ++++++++++++++ services/mailer/mailer_test.go | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 services/mailer/mailer_test.go diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 8b67a45175..83904080de 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -548,17 +548,17 @@ func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string) // LoadFromExisting initializes setting options from an existing config file (app.ini) func LoadFromExisting() { - loadFromConf(false) + loadFromConf(false, "") } // LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist func LoadAllowEmpty() { - loadFromConf(true) + loadFromConf(true, "") } // LoadForTest initializes setting options for tests -func LoadForTest() { - loadFromConf(true) +func LoadForTest(extraConfigs ...string) { + loadFromConf(true, strings.Join(extraConfigs, "\n")) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } @@ -566,7 +566,7 @@ func LoadForTest() { // loadFromConf initializes configuration context. // NOTE: do not print any log except error. -func loadFromConf(allowEmpty bool) { +func loadFromConf(allowEmpty bool, extraConfig string) { Cfg = ini.Empty() if WritePIDFile && len(PIDFile) > 0 { @@ -585,6 +585,12 @@ func loadFromConf(allowEmpty bool) { log.Fatal("Unable to find configuration file: %q.\nEnsure you are running in the correct environment or set the correct configuration file with -c.", CustomConf) } // else: no config file, a config file might be created at CustomConf later (might not) + if extraConfig != "" { + if err = Cfg.Append([]byte(extraConfig)); err != nil { + log.Fatal("Unable to append more config: %v", err) + } + } + Cfg.NameMapper = ini.SnackCase homeDir, err := com.HomeDir() diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 4b1492df0b..eac2b15c3c 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -9,6 +9,7 @@ import ( "bytes" "crypto/tls" "fmt" + "hash/fnv" "io" "net" "net/smtp" @@ -67,6 +68,10 @@ func (m *Message) ToMessage() *gomail.Message { msg.SetBody("text/plain", plainBody) msg.AddAlternative("text/html", m.Body) } + + if len(msg.GetHeader("Message-ID")) == 0 { + msg.SetHeader("Message-ID", m.generateAutoMessageID()) + } return msg } @@ -75,6 +80,17 @@ func (m *Message) SetHeader(field string, value ...string) { m.Headers[field] = value } +func (m *Message) generateAutoMessageID() string { + dateMs := m.Date.UnixNano() / 1e6 + h := fnv.New64() + if len(m.To) > 0 { + _, _ = h.Write([]byte(m.To[0])) + } + _, _ = h.Write([]byte(m.Subject)) + _, _ = h.Write([]byte(m.Body)) + return fmt.Sprintf("", dateMs, h.Sum64(), setting.Domain) +} + // NewMessageFrom creates new mail message object with custom From header. func NewMessageFrom(to []string, fromDisplayName, fromAddress, subject, body string) *Message { log.Trace("NewMessageFrom (body):\n%s", body) diff --git a/services/mailer/mailer_test.go b/services/mailer/mailer_test.go new file mode 100644 index 0000000000..8505803d22 --- /dev/null +++ b/services/mailer/mailer_test.go @@ -0,0 +1,39 @@ +// Copyright 2021 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package mailer + +import ( + "testing" + "time" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestGenerateMessageID(t *testing.T) { + setting.LoadForTest(` +[mailer] +ENABLED = true +FROM = test@domain.com +`) + setting.NewServices() + + date := time.Date(2000, 01, 02, 03, 04, 05, 06, time.UTC) + m := NewMessageFrom(nil, "display-name", "from-address", "subject", "body") + m.Date = date + gm := m.ToMessage() + assert.Equal(t, "", gm.GetHeader("Message-ID")[0]) + + m = NewMessageFrom([]string{"a@b.com"}, "display-name", "from-address", "subject", "body") + m.Date = date + gm = m.ToMessage() + assert.Equal(t, "", gm.GetHeader("Message-ID")[0]) + + m = NewMessageFrom([]string{"a@b.com"}, "display-name", "from-address", "subject", "body") + m.SetHeader("Message-ID", "") + gm = m.ToMessage() + assert.Equal(t, "", gm.GetHeader("Message-ID")[0]) +}