Change the mailer interface to prevent leaking of possible hidden email addresses when sending to multiple recipients. Co-authored-by: Gusted <williamzijl7@hotmail.com>tags/v1.19.0-rc0
func sendEmail(ctx *context.PrivateContext, subject, message string, to []string) { | func sendEmail(ctx *context.PrivateContext, subject, message string, to []string) { | ||||
for _, email := range to { | for _, email := range to { | ||||
msg := mailer.NewMessage([]string{email}, subject, message) | |||||
msg := mailer.NewMessage(email, subject, message) | |||||
mailer.SendAsync(msg) | mailer.SendAsync(msg) | ||||
} | } | ||||
// No mail service configured | // No mail service configured | ||||
return nil | return nil | ||||
} | } | ||||
return gomail.Send(Sender, NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").ToMessage()) | |||||
return gomail.Send(Sender, NewMessage(email, "Gitea Test Email!", "Gitea Test Email!").ToMessage()) | |||||
} | } | ||||
// sendUserMail sends a mail to the user | // sendUserMail sends a mail to the user | ||||
return | return | ||||
} | } | ||||
msg := NewMessage([]string{u.Email}, subject, content.String()) | |||||
msg := NewMessage(u.Email, subject, content.String()) | |||||
msg.Info = fmt.Sprintf("UID: %d, %s", u.ID, info) | msg.Info = fmt.Sprintf("UID: %d, %s", u.ID, info) | ||||
SendAsync(msg) | SendAsync(msg) | ||||
return | return | ||||
} | } | ||||
msg := NewMessage([]string{email.Email}, locale.Tr("mail.activate_email"), content.String()) | |||||
msg := NewMessage(email.Email, locale.Tr("mail.activate_email"), content.String()) | |||||
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID) | msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID) | ||||
SendAsync(msg) | SendAsync(msg) | ||||
return | return | ||||
} | } | ||||
msg := NewMessage([]string{u.Email}, locale.Tr("mail.register_notify"), content.String()) | |||||
msg := NewMessage(u.Email, locale.Tr("mail.register_notify"), content.String()) | |||||
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID) | msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID) | ||||
SendAsync(msg) | SendAsync(msg) | ||||
return | return | ||||
} | } | ||||
msg := NewMessage([]string{u.Email}, subject, content.String()) | |||||
msg := NewMessage(u.Email, subject, content.String()) | |||||
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID) | msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID) | ||||
SendAsync(msg) | SendAsync(msg) | ||||
msgs := make([]*Message, 0, len(recipients)) | msgs := make([]*Message, 0, len(recipients)) | ||||
for _, recipient := range recipients { | for _, recipient := range recipients { | ||||
msg := NewMessageFrom([]string{recipient.Email}, ctx.Doer.DisplayName(), setting.MailService.FromEmail, subject, mailBody.String()) | |||||
msg := NewMessageFrom(recipient.Email, ctx.Doer.DisplayName(), setting.MailService.FromEmail, subject, mailBody.String()) | |||||
msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info) | msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info) | ||||
msg.SetHeader("Message-ID", msgID) | msg.SetHeader("Message-ID", msgID) |
publisherName := rel.Publisher.DisplayName() | publisherName := rel.Publisher.DisplayName() | ||||
relURL := "<" + rel.HTMLURL() + ">" | relURL := "<" + rel.HTMLURL() + ">" | ||||
for _, to := range tos { | for _, to := range tos { | ||||
msg := NewMessageFrom([]string{to}, publisherName, setting.MailService.FromEmail, subject, mailBody.String()) | |||||
msg := NewMessageFrom(to, publisherName, setting.MailService.FromEmail, subject, mailBody.String()) | |||||
msg.Info = subject | msg.Info = subject | ||||
msg.SetHeader("Message-ID", relURL) | msg.SetHeader("Message-ID", relURL) | ||||
msgs = append(msgs, msg) | msgs = append(msgs, msg) |
return err | return err | ||||
} | } | ||||
msg := NewMessage(emails, subject, content.String()) | |||||
msg.Info = fmt.Sprintf("UID: %d, repository pending transfer notification", newOwner.ID) | |||||
for _, to := range emails { | |||||
msg := NewMessage(to, subject, content.String()) | |||||
msg.Info = fmt.Sprintf("UID: %d, repository pending transfer notification", newOwner.ID) | |||||
SendAsync(msg) | |||||
} | |||||
SendAsync(msg) | |||||
return nil | return nil | ||||
} | } |
return err | return err | ||||
} | } | ||||
msg := NewMessage([]string{invite.Email}, subject, mailBody.String()) | |||||
msg := NewMessage(invite.Email, subject, mailBody.String()) | |||||
msg.Info = subject | msg.Info = subject | ||||
SendAsync(msg) | SendAsync(msg) |
Info string // Message information for log purpose. | Info string // Message information for log purpose. | ||||
FromAddress string | FromAddress string | ||||
FromDisplayName string | FromDisplayName string | ||||
To []string | |||||
To string // Use only one recipient to prevent leaking of addresses | |||||
ReplyTo string | ReplyTo string | ||||
Subject string | Subject string | ||||
Date time.Time | Date time.Time | ||||
func (m *Message) ToMessage() *gomail.Message { | func (m *Message) ToMessage() *gomail.Message { | ||||
msg := gomail.NewMessage() | msg := gomail.NewMessage() | ||||
msg.SetAddressHeader("From", m.FromAddress, m.FromDisplayName) | msg.SetAddressHeader("From", m.FromAddress, m.FromDisplayName) | ||||
msg.SetHeader("To", m.To...) | |||||
msg.SetHeader("To", m.To) | |||||
if m.ReplyTo != "" { | if m.ReplyTo != "" { | ||||
msg.SetHeader("Reply-To", m.ReplyTo) | msg.SetHeader("Reply-To", m.ReplyTo) | ||||
} | } | ||||
dateMs := m.Date.UnixNano() / 1e6 | dateMs := m.Date.UnixNano() / 1e6 | ||||
h := fnv.New64() | h := fnv.New64() | ||||
if len(m.To) > 0 { | if len(m.To) > 0 { | ||||
_, _ = h.Write([]byte(m.To[0])) | |||||
_, _ = h.Write([]byte(m.To)) | |||||
} | } | ||||
_, _ = h.Write([]byte(m.Subject)) | _, _ = h.Write([]byte(m.Subject)) | ||||
_, _ = h.Write([]byte(m.Body)) | _, _ = h.Write([]byte(m.Body)) | ||||
} | } | ||||
// NewMessageFrom creates new mail message object with custom From header. | // NewMessageFrom creates new mail message object with custom From header. | ||||
func NewMessageFrom(to []string, fromDisplayName, fromAddress, subject, body string) *Message { | |||||
func NewMessageFrom(to, fromDisplayName, fromAddress, subject, body string) *Message { | |||||
log.Trace("NewMessageFrom (body):\n%s", body) | log.Trace("NewMessageFrom (body):\n%s", body) | ||||
return &Message{ | return &Message{ | ||||
} | } | ||||
// NewMessage creates new mail message object with default From header. | // NewMessage creates new mail message object with default From header. | ||||
func NewMessage(to []string, subject, body string) *Message { | |||||
func NewMessage(to, subject, body string) *Message { | |||||
return NewMessageFrom(to, setting.MailService.FromName, setting.MailService.FromEmail, subject, body) | return NewMessageFrom(to, setting.MailService.FromName, setting.MailService.FromEmail, subject, body) | ||||
} | } | ||||
setting.Domain = "localhost" | setting.Domain = "localhost" | ||||
date := time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC) | date := time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC) | ||||
m := NewMessageFrom(nil, "display-name", "from-address", "subject", "body") | |||||
m := NewMessageFrom("", "display-name", "from-address", "subject", "body") | |||||
m.Date = date | m.Date = date | ||||
gm := m.ToMessage() | gm := m.ToMessage() | ||||
assert.Equal(t, "<autogen-946782245000-41e8fc54a8ad3a3f@localhost>", gm.GetHeader("Message-ID")[0]) | assert.Equal(t, "<autogen-946782245000-41e8fc54a8ad3a3f@localhost>", gm.GetHeader("Message-ID")[0]) | ||||
m = NewMessageFrom([]string{"a@b.com"}, "display-name", "from-address", "subject", "body") | |||||
m = NewMessageFrom("a@b.com", "display-name", "from-address", "subject", "body") | |||||
m.Date = date | m.Date = date | ||||
gm = m.ToMessage() | gm = m.ToMessage() | ||||
assert.Equal(t, "<autogen-946782245000-cc88ce3cfe9bd04f@localhost>", gm.GetHeader("Message-ID")[0]) | assert.Equal(t, "<autogen-946782245000-cc88ce3cfe9bd04f@localhost>", gm.GetHeader("Message-ID")[0]) | ||||
m = NewMessageFrom([]string{"a@b.com"}, "display-name", "from-address", "subject", "body") | |||||
m = NewMessageFrom("a@b.com", "display-name", "from-address", "subject", "body") | |||||
m.SetHeader("Message-ID", "<msg-d@domain.com>") | m.SetHeader("Message-ID", "<msg-d@domain.com>") | ||||
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]) |