mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-27 06:03:51 +03:00
Add option to change mail from user display name (#31528)
Make it posible to let mails show e.g.: `Max Musternam (via gitea.kithara.com) <gitea@kithara.com>` Docs: https://gitea.com/gitea/docs/pulls/23 --- *Sponsored by Kithara Software GmbH* (cherry picked from commit 0f533241829d0d48aa16a91e7dc0614fe50bc317) Conflicts: - services/mailer/mail_release.go services/mailer/mail_test.go In both cases, applied the changes manually.
This commit is contained in:
parent
54f2dcff9d
commit
004cc6dc0a
6 changed files with 86 additions and 3 deletions
|
@ -1727,6 +1727,10 @@ LEVEL = Info
|
|||
;; Sometimes it is helpful to use a different address on the envelope. Set this to use ENVELOPE_FROM as the from on the envelope. Set to `<>` to send an empty address.
|
||||
;ENVELOPE_FROM =
|
||||
;;
|
||||
;; If gitea sends mails on behave of users, it will just use the name also displayed in the WebUI. If you want e.g. `Mister X (by CodeIt) <gitea@codeit.net>`,
|
||||
;; set it to `{{ .DisplayName }} (by {{ .AppName }})`. Available Variables: `.DisplayName`, `.AppName` and `.Domain`.
|
||||
;FROM_DISPLAY_NAME_FORMAT = {{ .DisplayName }}
|
||||
;;
|
||||
;; Mailer user name and password, if required by provider.
|
||||
;USER =
|
||||
;;
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
@ -46,6 +47,10 @@ type Mailer struct {
|
|||
SendmailArgs []string `ini:"-"`
|
||||
SendmailTimeout time.Duration `ini:"SENDMAIL_TIMEOUT"`
|
||||
SendmailConvertCRLF bool `ini:"SENDMAIL_CONVERT_CRLF"`
|
||||
|
||||
// Customization
|
||||
FromDisplayNameFormat string `ini:"FROM_DISPLAY_NAME_FORMAT"`
|
||||
FromDisplayNameFormatTemplate *template.Template `ini:"-"`
|
||||
}
|
||||
|
||||
// MailService the global mailer
|
||||
|
@ -234,6 +239,16 @@ func loadMailerFrom(rootCfg ConfigProvider) {
|
|||
log.Error("no mailer.FROM provided, email system may not work.")
|
||||
}
|
||||
|
||||
MailService.FromDisplayNameFormatTemplate, _ = template.New("mailFrom").Parse("{{ .DisplayName }}")
|
||||
if MailService.FromDisplayNameFormat != "" {
|
||||
template, err := template.New("mailFrom").Parse(MailService.FromDisplayNameFormat)
|
||||
if err != nil {
|
||||
log.Error("mailer.FROM_DISPLAY_NAME_FORMAT is no valid template: %v", err)
|
||||
} else {
|
||||
MailService.FromDisplayNameFormatTemplate = template
|
||||
}
|
||||
}
|
||||
|
||||
switch MailService.EnvelopeFrom {
|
||||
case "":
|
||||
MailService.OverrideEnvelopeFrom = false
|
||||
|
|
|
@ -313,7 +313,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
|
|||
for _, recipient := range recipients {
|
||||
msg := NewMessageFrom(
|
||||
recipient.Email,
|
||||
ctx.Doer.GetCompleteName(),
|
||||
fromDisplayName(ctx.Doer),
|
||||
setting.MailService.FromEmail,
|
||||
subject,
|
||||
mailBody.String(),
|
||||
|
@ -545,3 +545,19 @@ func actionToTemplate(issue *issues_model.Issue, actionType activities_model.Act
|
|||
}
|
||||
return typeName, name, template
|
||||
}
|
||||
|
||||
func fromDisplayName(u *user_model.User) string {
|
||||
if setting.MailService.FromDisplayNameFormatTemplate != nil {
|
||||
var ctx bytes.Buffer
|
||||
err := setting.MailService.FromDisplayNameFormatTemplate.Execute(&ctx, map[string]any{
|
||||
"DisplayName": u.DisplayName(),
|
||||
"AppName": setting.AppName,
|
||||
"Domain": setting.Domain,
|
||||
})
|
||||
if err == nil {
|
||||
return mime.QEncoding.Encode("utf-8", ctx.String())
|
||||
}
|
||||
log.Error("fromDisplayName: %w", err)
|
||||
}
|
||||
return u.GetCompleteName()
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []*user_model.User, re
|
|||
}
|
||||
|
||||
msgs := make([]*Message, 0, len(tos))
|
||||
publisherName := rel.Publisher.DisplayName()
|
||||
publisherName := fromDisplayName(rel.Publisher)
|
||||
msgID := createMessageIDForRelease(rel)
|
||||
for _, to := range tos {
|
||||
msg := NewMessageFrom(to.EmailTo(), publisherName, setting.MailService.FromEmail, subject, mailBody.String())
|
||||
|
|
|
@ -79,7 +79,7 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
|
|||
}
|
||||
|
||||
for _, to := range emailTos {
|
||||
msg := NewMessage(to.EmailTo(), subject, content.String())
|
||||
msg := NewMessageFrom(to.EmailTo(), fromDisplayName(doer), setting.MailService.FromEmail, subject, content.String())
|
||||
msg.Info = fmt.Sprintf("UID: %d, repository pending transfer notification", newOwner.ID)
|
||||
|
||||
SendAsync(msg)
|
||||
|
|
|
@ -489,3 +489,51 @@ func Test_createReference(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromDisplayName(t *testing.T) {
|
||||
template, err := texttmpl.New("mailFrom").Parse("{{ .DisplayName }}")
|
||||
assert.NoError(t, err)
|
||||
setting.MailService = &setting.Mailer{FromDisplayNameFormatTemplate: template}
|
||||
defer func() { setting.MailService = nil }()
|
||||
|
||||
tests := []struct {
|
||||
userDisplayName string
|
||||
fromDisplayName string
|
||||
}{{
|
||||
userDisplayName: "test",
|
||||
fromDisplayName: "test",
|
||||
}, {
|
||||
userDisplayName: "Hi Its <Mee>",
|
||||
fromDisplayName: "Hi Its <Mee>",
|
||||
}, {
|
||||
userDisplayName: "Æsir",
|
||||
fromDisplayName: "=?utf-8?q?=C3=86sir?=",
|
||||
}, {
|
||||
userDisplayName: "new😀user",
|
||||
fromDisplayName: "=?utf-8?q?new=F0=9F=98=80user?=",
|
||||
}}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.userDisplayName, func(t *testing.T) {
|
||||
user := &user_model.User{FullName: tc.userDisplayName, Name: "tmp"}
|
||||
got := fromDisplayName(user)
|
||||
assert.EqualValues(t, tc.fromDisplayName, got)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("template with all available vars", func(t *testing.T) {
|
||||
template, err = texttmpl.New("mailFrom").Parse("{{ .DisplayName }} (by {{ .AppName }} on [{{ .Domain }}])")
|
||||
assert.NoError(t, err)
|
||||
setting.MailService = &setting.Mailer{FromDisplayNameFormatTemplate: template}
|
||||
oldAppName := setting.AppName
|
||||
setting.AppName = "Code IT"
|
||||
oldDomain := setting.Domain
|
||||
setting.Domain = "code.it"
|
||||
defer func() {
|
||||
setting.AppName = oldAppName
|
||||
setting.Domain = oldDomain
|
||||
}()
|
||||
|
||||
assert.EqualValues(t, "Mister X (by Code IT on [code.it])", fromDisplayName(&user_model.User{FullName: "Mister X", Name: "tmp"}))
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue