mirror of
https://github.com/go-gitea/gitea
synced 2024-11-17 15:31:06 +01:00
Add option for mailer to override mail headers (#27860)
Add option to override headers of mails, gitea send out --- *Sponsored by Kithara Software GmbH*
This commit is contained in:
parent
8c68c5e436
commit
aace3bccc3
5 changed files with 128 additions and 10 deletions
|
@ -1687,6 +1687,16 @@ LEVEL = Info
|
||||||
;; convert \r\n to \n for Sendmail
|
;; convert \r\n to \n for Sendmail
|
||||||
;SENDMAIL_CONVERT_CRLF = true
|
;SENDMAIL_CONVERT_CRLF = true
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;[mailer.override_header]
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; 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 =
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;[email.incoming]
|
;[email.incoming]
|
||||||
|
|
|
@ -724,11 +724,13 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
|
||||||
|
|
||||||
## Mailer (`mailer`)
|
## Mailer (`mailer`)
|
||||||
|
|
||||||
⚠️ This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older,
|
:::warning
|
||||||
|
This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older,
|
||||||
please refer to
|
please refer to
|
||||||
[Gitea 1.17 app.ini example](https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini)
|
[Gitea 1.17 app.ini example](https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini)
|
||||||
and
|
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+starttls", "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`._
|
||||||
|
@ -761,6 +763,21 @@ and
|
||||||
- `SEND_BUFFER_LEN`: **100**: Buffer length of mailing queue. **DEPRECATED** use `LENGTH` in `[queue.mailer]`
|
- `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.
|
- `SEND_AS_PLAIN_TEXT`: **false**: Send mails only in plain text, without HTML alternative.
|
||||||
|
|
||||||
|
## Override Email Headers (`mailer.override_header`)
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
This is empty 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, test2@example.com
|
||||||
|
Content-Type = text/html; charset=utf-8
|
||||||
|
In-Reply-To =
|
||||||
|
```
|
||||||
|
|
||||||
## Incoming Email (`email.incoming`)
|
## Incoming Email (`email.incoming`)
|
||||||
|
|
||||||
- `ENABLED`: **false**: Enable handling of incoming emails.
|
- `ENABLED`: **false**: Enable handling of incoming emails.
|
||||||
|
|
|
@ -18,14 +18,15 @@ import (
|
||||||
// Mailer represents mail service.
|
// Mailer represents mail service.
|
||||||
type Mailer struct {
|
type Mailer struct {
|
||||||
// Mailer
|
// Mailer
|
||||||
Name string `ini:"NAME"`
|
Name string `ini:"NAME"`
|
||||||
From string `ini:"FROM"`
|
From string `ini:"FROM"`
|
||||||
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
|
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
|
||||||
OverrideEnvelopeFrom bool `ini:"-"`
|
OverrideEnvelopeFrom bool `ini:"-"`
|
||||||
FromName string `ini:"-"`
|
FromName string `ini:"-"`
|
||||||
FromEmail string `ini:"-"`
|
FromEmail string `ini:"-"`
|
||||||
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
|
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
|
||||||
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
|
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
|
||||||
|
OverrideHeader map[string][]string `ini:"-"`
|
||||||
|
|
||||||
// SMTP sender
|
// SMTP sender
|
||||||
Protocol string `ini:"PROTOCOL"`
|
Protocol string `ini:"PROTOCOL"`
|
||||||
|
@ -151,6 +152,12 @@ func loadMailerFrom(rootCfg ConfigProvider) {
|
||||||
log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err)
|
log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overrideHeader := rootCfg.Section("mailer.override_header").Keys()
|
||||||
|
MailService.OverrideHeader = make(map[string][]string)
|
||||||
|
for _, key := range overrideHeader {
|
||||||
|
MailService.OverrideHeader[key.Name()] = key.Strings(",")
|
||||||
|
}
|
||||||
|
|
||||||
// Infer SMTPPort if not set
|
// Infer SMTPPort if not set
|
||||||
if MailService.SMTPPort == "" {
|
if MailService.SMTPPort == "" {
|
||||||
switch MailService.Protocol {
|
switch MailService.Protocol {
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (m *Message) ToMessage() *gomail.Message {
|
||||||
msg.SetHeader(header, m.Headers[header]...)
|
msg.SetHeader(header, m.Headers[header]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(setting.MailService.SubjectPrefix) > 0 {
|
if setting.MailService.SubjectPrefix != "" {
|
||||||
msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject)
|
msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject)
|
||||||
} else {
|
} else {
|
||||||
msg.SetHeader("Subject", m.Subject)
|
msg.SetHeader("Subject", m.Subject)
|
||||||
|
@ -79,6 +79,14 @@ func (m *Message) ToMessage() *gomail.Message {
|
||||||
if len(msg.GetHeader("Message-ID")) == 0 {
|
if len(msg.GetHeader("Message-ID")) == 0 {
|
||||||
msg.SetHeader("Message-ID", m.generateAutoMessageID())
|
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)
|
||||||
|
}
|
||||||
|
msg.SetHeader(k, v...)
|
||||||
|
}
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package mailer
|
package mailer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -36,3 +37,78 @@ func TestGenerateMessageID(t *testing.T) {
|
||||||
gm = m.ToMessage()
|
gm = m.ToMessage()
|
||||||
assert.Equal(t, "<msg-d@domain.com>", gm.GetHeader("Message-ID")[0])
|
assert.Equal(t, "<msg-d@domain.com>", 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\" <test@gitea.com>",
|
||||||
|
"Message-ID": "<autogen--6795364578871-69c000786adc60dc@localhost>",
|
||||||
|
"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\" <test@gitea.com>",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue