From a89d29896459be75c29675c05356e09d6059b6f4 Mon Sep 17 00:00:00 2001 From: "m.huber" Date: Wed, 1 Nov 2023 05:32:21 +0100 Subject: [PATCH 01/20] mailer: add option to set Return-Path --- custom/conf/app.example.ini | 4 ++++ docs/content/administration/config-cheat-sheet.en-us.md | 1 + modules/setting/mailer.go | 1 + services/mailer/mailer.go | 5 ++++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 2209822ff0869..3e6d9a35818b7 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1578,6 +1578,10 @@ LEVEL = Info ;; Prefix displayed before subject in mail ;SUBJECT_PREFIX = ;; +;; Set the Return-Path header, to let mail clients reply to a different mail as it was send from. +;; If '<>' is set, it indicates has the same efect as if you would set a noreply address for FROM. +;RETURN_PATH = +;; ;; 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. ;; - dummy: send email messages to the log as a testing phase. diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 617715fbaa12e..e82c4164bc3a0 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -732,6 +732,7 @@ and - `ENABLE_HELO`: **true**: Enable HELO operation. - `HELO_HOSTNAME`: **(retrieved from system)**: HELO hostname. - `FROM`: **_empty_**: Mail from address, RFC 5322. This can be just an email address, or the "Name" \ format. +- `RETURN_PATH`: **_empty_**: Set the Return-Path header, to let mail clients reply to a different mail as it was send from. See [RFC 4021](https://www.rfc-editor.org/rfc/rfc4021#page-17) for more details. - `ENVELOPE_FROM`: **_empty_**: Address set as the From address on the SMTP mail envelope. Set to `<>` to send an empty address. - `SUBJECT_PREFIX`: **_empty_**: Prefix to be placed before e-mail subject lines. - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be command or full path). diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index a2bc2df444990..b97080041fe1b 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -26,6 +26,7 @@ type Mailer struct { FromEmail string `ini:"-"` SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"` SubjectPrefix string `ini:"SUBJECT_PREFIX"` + ReturnPath string `ini:"RETURN_PATH"` // SMTP sender Protocol string `ini:"PROTOCOL"` diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 5e8e3dbb38cd7..12de06d5e133d 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -57,11 +57,14 @@ func (m *Message) ToMessage() *gomail.Message { msg.SetHeader(header, m.Headers[header]...) } - if len(setting.MailService.SubjectPrefix) > 0 { + if setting.MailService.SubjectPrefix != "" { msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject) } else { msg.SetHeader("Subject", m.Subject) } + if setting.MailService.ReturnPath != "" { + msg.SetHeader("Return-Path", setting.MailService.ReturnPath) + } msg.SetDateHeader("Date", m.Date) msg.SetHeader("X-Auto-Response-Suppress", "All") From 89a29c60cf31ff9bc771897cf2aff16f4f9e7bbf Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 1 Nov 2023 17:42:55 +0100 Subject: [PATCH 02/20] Update custom/conf/app.example.ini Co-authored-by: silverwind --- custom/conf/app.example.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 3e6d9a35818b7..ff6f709e0a0e9 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1578,8 +1578,7 @@ LEVEL = Info ;; Prefix displayed before subject in mail ;SUBJECT_PREFIX = ;; -;; Set the Return-Path header, to let mail clients reply to a different mail as it was send from. -;; If '<>' is set, it indicates has the same efect as if you would set a noreply address for FROM. +;; Set the Return-Path header where bounced e-mails will be sent to. ;RETURN_PATH = ;; ;; Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy". From 30db9c32abe02ab90fb41879b85be0781b07dc20 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 1 Nov 2023 18:11:02 +0100 Subject: [PATCH 03/20] Update docs/content/administration/config-cheat-sheet.en-us.md --- docs/content/administration/config-cheat-sheet.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index e82c4164bc3a0..07986e7d5d9e3 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -732,7 +732,7 @@ and - `ENABLE_HELO`: **true**: Enable HELO operation. - `HELO_HOSTNAME`: **(retrieved from system)**: HELO hostname. - `FROM`: **_empty_**: Mail from address, RFC 5322. This can be just an email address, or the "Name" \ format. -- `RETURN_PATH`: **_empty_**: Set the Return-Path header, to let mail clients reply to a different mail as it was send from. See [RFC 4021](https://www.rfc-editor.org/rfc/rfc4021#page-17) for more details. +- `RETURN_PATH`: **_empty_**: Set the Return-Path header where bounced e-mails will be sent to. - `ENVELOPE_FROM`: **_empty_**: Address set as the From address on the SMTP mail envelope. Set to `<>` to send an empty address. - `SUBJECT_PREFIX`: **_empty_**: Prefix to be placed before e-mail subject lines. - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be command or full path). From 37073a408e52501e7394a9ac6109de234d6ced77 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 28 May 2024 23:24:20 +0200 Subject: [PATCH 04/20] use generic OverrideHeader --- custom/conf/app.example.ini | 9 ++++++++ .../config-cheat-sheet.en-us.md | 12 +++++++++- modules/setting/mailer.go | 23 +++++++++++-------- services/mailer/mailer.go | 10 +++++--- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 4bed79f05d0a2..a5821a3345dd4 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1690,6 +1690,15 @@ LEVEL = Info ;; convert \r\n to \n for Sendmail ;SENDMAIL_CONVERT_CRLF = true +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;[email.override_header] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; This is empyt by default, use it only if you know what you need it for. +;Reply-To = test@example.com,test2@example.com, +;Content-Type = text/plain + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[email.incoming] diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 1c535acb522d9..a3e0022489879 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -752,7 +752,6 @@ and - `ENABLE_HELO`: **true**: Enable HELO operation. - `HELO_HOSTNAME`: **(retrieved from system)**: HELO hostname. - `FROM`: **_empty_**: Mail from address, RFC 5322. This can be just an email address, or the "Name" \ format. -- `RETURN_PATH`: **_empty_**: Set the Return-Path header where bounced e-mails will be sent to. - `ENVELOPE_FROM`: **_empty_**: Address set as the From address on the SMTP mail envelope. Set to `<>` to send an empty address. - `SUBJECT_PREFIX`: **_empty_**: Prefix to be placed before e-mail subject lines. - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be command or full path). @@ -762,6 +761,17 @@ and - `SEND_BUFFER_LEN`: **100**: Buffer length of mailing queue. **DEPRECATED** use `LENGTH` in `[queue.mailer]` - `SEND_AS_PLAIN_TEXT`: **false**: Send mails only in plain text, without HTML alternative. +## Override Email Headers (`mailer.override_header`) + +⚠️ This is empyt by default, use it only if you know what you need it for. + +examples would be: +```ini +[email.override_header] +Reply-To = test@example.com +Content-Type = text/html, charset=utf-8 +``` + ## Incoming Email (`email.incoming`) - `ENABLED`: **false**: Enable handling of incoming emails. diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index b97080041fe1b..e12cda1773681 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -18,15 +18,15 @@ import ( // Mailer represents mail service. type Mailer struct { // Mailer - Name string `ini:"NAME"` - From string `ini:"FROM"` - EnvelopeFrom string `ini:"ENVELOPE_FROM"` - OverrideEnvelopeFrom bool `ini:"-"` - FromName string `ini:"-"` - FromEmail string `ini:"-"` - SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"` - SubjectPrefix string `ini:"SUBJECT_PREFIX"` - ReturnPath string `ini:"RETURN_PATH"` + Name string `ini:"NAME"` + From string `ini:"FROM"` + EnvelopeFrom string `ini:"ENVELOPE_FROM"` + OverrideEnvelopeFrom bool `ini:"-"` + FromName string `ini:"-"` + FromEmail string `ini:"-"` + SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"` + SubjectPrefix string `ini:"SUBJECT_PREFIX"` + OverrideHeader map[string][]string `ini:"-"` // SMTP sender Protocol string `ini:"PROTOCOL"` @@ -152,6 +152,11 @@ func loadMailerFrom(rootCfg ConfigProvider) { log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err) } + overrideHeader := rootCfg.Section("mailer.override_header").Keys() + for _, key := range overrideHeader { + MailService.OverrideHeader[key.Name()] = key.Strings(",") + } + // Infer SMTPPort if not set if MailService.SMTPPort == "" { switch MailService.Protocol { diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 12de06d5e133d..21612dd66b259 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -62,9 +62,6 @@ func (m *Message) ToMessage() *gomail.Message { } else { msg.SetHeader("Subject", m.Subject) } - if setting.MailService.ReturnPath != "" { - msg.SetHeader("Return-Path", setting.MailService.ReturnPath) - } msg.SetDateHeader("Date", m.Date) msg.SetHeader("X-Auto-Response-Suppress", "All") @@ -79,6 +76,13 @@ func (m *Message) ToMessage() *gomail.Message { msg.AddAlternative("text/html", m.Body) } + for k, v := range setting.MailService.OverrideHeader { + if len(msg.GetHeader(k)) != 0 { + log.Debug("Mailer override header '%s' as per config", k) + } + msg.SetHeader(k, v...) + } + if len(msg.GetHeader("Message-ID")) == 0 { msg.SetHeader("Message-ID", m.generateAutoMessageID()) } From 9e7653e63c5803cf30f6431661f003f64111a794 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:09:33 +0200 Subject: [PATCH 05/20] cleanup docs --- custom/conf/app.example.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5e0289b42c875..106824e58e93f 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1622,9 +1622,6 @@ LEVEL = Info ;; Prefix displayed before subject in mail ;SUBJECT_PREFIX = ;; -;; Set the Return-Path header where bounced e-mails will be sent to. -;RETURN_PATH = -;; ;; 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. ;; - dummy: send email messages to the log as a testing phase. From bcda0f3fa3424d9382b15aad87401cfd9c15f2c9 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:10:25 +0200 Subject: [PATCH 06/20] tewak docs --- custom/conf/app.example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 106824e58e93f..aa5fd152c0eca 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1694,7 +1694,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is empyt by default, use it only if you know what you need it for. ;Reply-To = test@example.com,test2@example.com, -;Content-Type = text/plain +;Content-Type = text/html, charset=utf-8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From b8d65d9f8b3f62d547ba264811226da586575063 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:11:15 +0200 Subject: [PATCH 07/20] cleanup --- custom/conf/app.example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index aa5fd152c0eca..f928cb429038a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1693,7 +1693,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is empyt by default, use it only if you know what you need it for. -;Reply-To = test@example.com,test2@example.com, +;Reply-To = test@example.com,test2@example.com ;Content-Type = text/html, charset=utf-8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From 2a625a313f5242f00ab9459ccba7bc1b9f1d78ca Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:12:06 +0200 Subject: [PATCH 08/20] init map --- modules/setting/mailer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index e12cda1773681..c7948a86c6c9b 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -153,6 +153,7 @@ func loadMailerFrom(rootCfg ConfigProvider) { } overrideHeader := rootCfg.Section("mailer.override_header").Keys() + MailService.OverrideHeader = map[string][]string{} for _, key := range overrideHeader { MailService.OverrideHeader[key.Name()] = key.Strings(",") } From 680f13af2c4f4eebd1553582a0eb91ab16d9e365 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:17:25 +0200 Subject: [PATCH 09/20] sanitize config input on parsing --- modules/setting/mailer.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index c7948a86c6c9b..6a87792c195b0 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -153,9 +153,19 @@ func loadMailerFrom(rootCfg ConfigProvider) { } overrideHeader := rootCfg.Section("mailer.override_header").Keys() - MailService.OverrideHeader = map[string][]string{} + MailService.OverrideHeader = make(map[string][]string) for _, key := range overrideHeader { - MailService.OverrideHeader[key.Name()] = key.Strings(",") + keyName := key.Name() + values := key.Strings(",") + if keyName != "" { + valuesToSet := make([]string, 0, len(values)) + for _, v := range values { + if v := strings.TrimSpace(v); v != "" { + valuesToSet = append(valuesToSet, v) + } + } + MailService.OverrideHeader[keyName] = valuesToSet + } } // Infer SMTPPort if not set From 15f21035ff3180c008dcf05f9e1da83013232549 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:36:47 +0200 Subject: [PATCH 10/20] fix docu and it works :D --- custom/conf/app.example.ini | 2 +- docs/content/administration/config-cheat-sheet.en-us.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index f928cb429038a..88f2e4e90c43a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1689,7 +1689,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[email.override_header] +;[mailer.override_header] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is empyt by default, use it only if you know what you need it for. diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 32f118291692a..b271a3b300439 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -767,7 +767,7 @@ and examples would be: ```ini -[email.override_header] +[mailer.override_header] Reply-To = test@example.com Content-Type = text/html, charset=utf-8 ``` From 1c65d9ab67841ee6431326695a26e04966da7b67 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:42:38 +0200 Subject: [PATCH 11/20] fix docu lint --- docs/content/administration/config-cheat-sheet.en-us.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index b271a3b300439..71e9b6a25678f 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -766,6 +766,7 @@ and ⚠️ This is empyt by default, use it only if you know what you need it for. examples would be: + ```ini [mailer.override_header] Reply-To = test@example.com From bc7ca47360b9756f0d84ef815364a6e21db8516b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:43:22 +0200 Subject: [PATCH 12/20] fix misspell Co-authored-by: silverwind --- custom/conf/app.example.ini | 2 +- docs/content/administration/config-cheat-sheet.en-us.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 88f2e4e90c43a..be4965624000a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1692,7 +1692,7 @@ LEVEL = Info ;[mailer.override_header] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; This is empyt by default, use it only if you know what you need it for. +;; This is empty by default, use it only if you know what you need it for. ;Reply-To = test@example.com,test2@example.com ;Content-Type = text/html, charset=utf-8 diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 71e9b6a25678f..78777b89bc76c 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -763,7 +763,7 @@ and ## Override Email Headers (`mailer.override_header`) -⚠️ This is empyt by default, use it only if you know what you need it for. +⚠️ This is empty by default, use it only if you know what you need it for. examples would be: From 117b702c2572561946ad2f9239cfc5e9ef6fb175 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:48:51 +0200 Subject: [PATCH 13/20] simple docs --- custom/conf/app.example.ini | 2 +- docs/content/administration/config-cheat-sheet.en-us.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index be4965624000a..9b816f4f29351 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1694,7 +1694,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is empty by default, use it only if you know what you need it for. ;Reply-To = test@example.com,test2@example.com -;Content-Type = text/html, charset=utf-8 +;Content-Type = text/html; charset=utf-8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 78777b89bc76c..fff2674b91a08 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -770,7 +770,7 @@ examples would be: ```ini [mailer.override_header] Reply-To = test@example.com -Content-Type = text/html, charset=utf-8 +Content-Type = text/html; charset=utf-8 ``` ## Incoming Email (`email.incoming`) From 261d6049c581b72711a666f6f273f3bc28ea569c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:54:13 +0200 Subject: [PATCH 14/20] Apply suggestions from code review --- docs/content/administration/config-cheat-sheet.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index fff2674b91a08..b150e35214ba1 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -769,7 +769,7 @@ examples would be: ```ini [mailer.override_header] -Reply-To = test@example.com +Reply-To = test@example.com,test2@example.com Content-Type = text/html; charset=utf-8 ``` From dc8f145a8ec8ca45a2caad77e0a5cad29e525ad8 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:54:48 +0200 Subject: [PATCH 15/20] Apply suggestions from code review --- custom/conf/app.example.ini | 2 +- docs/content/administration/config-cheat-sheet.en-us.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 9b816f4f29351..314b8aeaff84a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1693,7 +1693,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is empty by default, use it only if you know what you need it for. -;Reply-To = test@example.com,test2@example.com +;Reply-To = test@example.com, test2@example.com ;Content-Type = text/html; charset=utf-8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index b150e35214ba1..62764a8d837c4 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -769,7 +769,7 @@ examples would be: ```ini [mailer.override_header] -Reply-To = test@example.com,test2@example.com +Reply-To = test@example.com, test2@example.com Content-Type = text/html; charset=utf-8 ``` From 776c550ff22987b46c4ac4123cc608bf855380d2 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 00:59:18 +0200 Subject: [PATCH 16/20] migrate to docusaurus note --- docs/content/administration/config-cheat-sheet.en-us.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 62764a8d837c4..4f6c8cd896aa0 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -724,11 +724,13 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type ## Mailer (`mailer`) -⚠️ This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older, +:::note +This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older, please refer to [Gitea 1.17 app.ini example](https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini) 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) +::: - `ENABLED`: **false**: Enable to use a mail service. - `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`._ @@ -763,7 +765,9 @@ and ## Override Email Headers (`mailer.override_header`) -⚠️ This is empty by default, use it only if you know what you need it for. +:::note +This is empty by default, use it only if you know what you need it for. +::: examples would be: From f1b7ee2be7eedf9be93c3313366a2771f83d19be Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 01:23:17 +0200 Subject: [PATCH 17/20] simple passthrough config --- modules/setting/mailer.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index 6a87792c195b0..58bfd67bfb504 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -155,17 +155,7 @@ func loadMailerFrom(rootCfg ConfigProvider) { overrideHeader := rootCfg.Section("mailer.override_header").Keys() MailService.OverrideHeader = make(map[string][]string) for _, key := range overrideHeader { - keyName := key.Name() - values := key.Strings(",") - if keyName != "" { - valuesToSet := make([]string, 0, len(values)) - for _, v := range values { - if v := strings.TrimSpace(v); v != "" { - valuesToSet = append(valuesToSet, v) - } - } - MailService.OverrideHeader[keyName] = valuesToSet - } + MailService.OverrideHeader[key.Name()] = key.Strings(",") } // Infer SMTPPort if not set From 8204fac34ba5db921eb8666a9d103993ebffc347 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 29 May 2024 01:32:06 +0200 Subject: [PATCH 18/20] use warning and add example to delete an header --- custom/conf/app.example.ini | 1 + docs/content/administration/config-cheat-sheet.en-us.md | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 314b8aeaff84a..57a26c6442ce5 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1695,6 +1695,7 @@ LEVEL = Info ;; This is empty by default, use it only if you know what you need it for. ;Reply-To = test@example.com, test2@example.com ;Content-Type = text/html; charset=utf-8 +;In-Reply-To = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 4f6c8cd896aa0..7d23ec89914c2 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -724,7 +724,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type ## Mailer (`mailer`) -:::note +:::warning This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older, please refer to [Gitea 1.17 app.ini example](https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini) @@ -765,7 +765,7 @@ and ## Override Email Headers (`mailer.override_header`) -:::note +:::warning This is empty by default, use it only if you know what you need it for. ::: @@ -775,6 +775,7 @@ examples would be: [mailer.override_header] Reply-To = test@example.com, test2@example.com Content-Type = text/html; charset=utf-8 +In-Reply-To = ``` ## Incoming Email (`email.incoming`) From f433b1c95e1b610af1fd61422ac9b2512e3313cd Mon Sep 17 00:00:00 2001 From: "m.huber" Date: Mon, 3 Jun 2024 10:19:35 +0200 Subject: [PATCH 19/20] make explizite everything overridable --- services/mailer/mailer.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 21612dd66b259..c5846e6104d5b 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -76,6 +76,10 @@ func (m *Message) ToMessage() *gomail.Message { msg.AddAlternative("text/html", m.Body) } + if len(msg.GetHeader("Message-ID")) == 0 { + msg.SetHeader("Message-ID", m.generateAutoMessageID()) + } + for k, v := range setting.MailService.OverrideHeader { if len(msg.GetHeader(k)) != 0 { log.Debug("Mailer override header '%s' as per config", k) @@ -83,9 +87,6 @@ func (m *Message) ToMessage() *gomail.Message { msg.SetHeader(k, v...) } - if len(msg.GetHeader("Message-ID")) == 0 { - msg.SetHeader("Message-ID", m.generateAutoMessageID()) - } return msg } From 39352d9981934b48daa8b3c96d6e5b0d8b80f29a Mon Sep 17 00:00:00 2001 From: "m.huber" Date: Mon, 3 Jun 2024 10:41:37 +0200 Subject: [PATCH 20/20] Add test for mailer.ToMessage() --- services/mailer/mailer_test.go | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/services/mailer/mailer_test.go b/services/mailer/mailer_test.go index 375ca35daa328..6d7c44f40c044 100644 --- a/services/mailer/mailer_test.go +++ b/services/mailer/mailer_test.go @@ -4,6 +4,7 @@ package mailer import ( + "strings" "testing" "time" @@ -36,3 +37,78 @@ func TestGenerateMessageID(t *testing.T) { gm = m.ToMessage() assert.Equal(t, "", gm.GetHeader("Message-ID")[0]) } + +func TestToMessage(t *testing.T) { + oldConf := *setting.MailService + defer func() { + setting.MailService = &oldConf + }() + setting.MailService.From = "test@gitea.com" + + m1 := Message{ + Info: "info", + FromAddress: "test@gitea.com", + FromDisplayName: "Test Gitea", + To: "a@b.com", + Subject: "Issue X Closed", + Body: "Some Issue got closed by Y-Man", + } + + buf := &strings.Builder{} + _, err := m1.ToMessage().WriteTo(buf) + assert.NoError(t, err) + header, _ := extractMailHeaderAndContent(t, buf.String()) + assert.EqualValues(t, map[string]string{ + "Content-Type": "multipart/alternative;", + "Date": "Mon, 01 Jan 0001 00:00:00 +0000", + "From": "\"Test Gitea\" ", + "Message-ID": "", + "Mime-Version": "1.0", + "Subject": "Issue X Closed", + "To": "a@b.com", + "X-Auto-Response-Suppress": "All", + }, header) + + setting.MailService.OverrideHeader = map[string][]string{ + "Message-ID": {""}, // delete message id + "Auto-Submitted": {"auto-generated"}, // suppress auto replay + } + + buf = &strings.Builder{} + _, err = m1.ToMessage().WriteTo(buf) + assert.NoError(t, err) + header, _ = extractMailHeaderAndContent(t, buf.String()) + assert.EqualValues(t, map[string]string{ + "Content-Type": "multipart/alternative;", + "Date": "Mon, 01 Jan 0001 00:00:00 +0000", + "From": "\"Test Gitea\" ", + "Message-ID": "", + "Mime-Version": "1.0", + "Subject": "Issue X Closed", + "To": "a@b.com", + "X-Auto-Response-Suppress": "All", + "Auto-Submitted": "auto-generated", + }, header) +} + +func extractMailHeaderAndContent(t *testing.T, mail string) (map[string]string, string) { + header := make(map[string]string) + + parts := strings.SplitN(mail, "boundary=", 2) + if !assert.Len(t, parts, 2) { + return nil, "" + } + content := strings.TrimSpace("boundary=" + parts[1]) + + hParts := strings.Split(parts[0], "\n") + + for _, hPart := range hParts { + parts := strings.SplitN(hPart, ":", 2) + hk := strings.TrimSpace(parts[0]) + if hk != "" { + header[hk] = strings.TrimSpace(parts[1]) + } + } + + return header, content +}