diff options
author | zeripath <art27@cantab.net> | 2020-01-16 17:55:36 +0000 |
---|---|---|
committer | Antoine GIRARD <sapk@users.noreply.github.com> | 2020-01-16 18:55:36 +0100 |
commit | c76c70a16ce6c1d472059ea3e03206abb5ed884d (patch) | |
tree | 25902cbd062be6fdbefe9417ca33c96acab5809a /services | |
parent | 06cd3e03a24e23d2d838cda6eb1edd5e7474ad42 (diff) | |
download | gitea-c76c70a16ce6c1d472059ea3e03206abb5ed884d.tar.gz gitea-c76c70a16ce6c1d472059ea3e03206abb5ed884d.zip |
Move mailer to use a queue (#9789)
* Move mailer to use a queue
* Make sectionMap map[string]bool
* Ensure that Message is json encodable
Diffstat (limited to 'services')
-rw-r--r-- | services/mailer/mail.go | 2 | ||||
-rw-r--r-- | services/mailer/mail_test.go | 29 | ||||
-rw-r--r-- | services/mailer/mailer.go | 90 |
3 files changed, 75 insertions, 46 deletions
diff --git a/services/mailer/mail.go b/services/mailer/mail.go index 4b8e46715f..3241ae728d 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -51,7 +51,7 @@ func InitMailRender(subjectTpl *texttmpl.Template, bodyTpl *template.Template) { // SendTestMail sends a test mail func SendTestMail(email string) error { - return gomail.Send(Sender, NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message) + return gomail.Send(Sender, NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").ToMessage()) } // SendUserMail sends a mail to the user diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go index 43e99c635e..d7d02d9dee 100644 --- a/services/mailer/mail_test.go +++ b/services/mailer/mail_test.go @@ -61,11 +61,11 @@ func TestComposeIssueCommentMessage(t *testing.T) { msgs := composeIssueCommentMessages(&mailCommentContext{Issue: issue, Doer: doer, ActionType: models.ActionCommentIssue, Content: "test body", Comment: comment}, tos, false, "issue comment") assert.Len(t, msgs, 2) - - mailto := msgs[0].GetHeader("To") - subject := msgs[0].GetHeader("Subject") - inreplyTo := msgs[0].GetHeader("In-Reply-To") - references := msgs[0].GetHeader("References") + gomailMsg := msgs[0].ToMessage() + mailto := gomailMsg.GetHeader("To") + subject := gomailMsg.GetHeader("Subject") + inreplyTo := gomailMsg.GetHeader("In-Reply-To") + references := gomailMsg.GetHeader("References") assert.Len(t, mailto, 1, "exactly one recipient is expected in the To field") assert.Equal(t, "Re: ", subject[0][:4], "Comment reply subject should contain Re:") @@ -96,14 +96,15 @@ func TestComposeIssueMessage(t *testing.T) { Content: "test body"}, tos, false, "issue create") assert.Len(t, msgs, 2) - mailto := msgs[0].GetHeader("To") - subject := msgs[0].GetHeader("Subject") - messageID := msgs[0].GetHeader("Message-ID") + gomailMsg := msgs[0].ToMessage() + mailto := gomailMsg.GetHeader("To") + subject := gomailMsg.GetHeader("Subject") + messageID := gomailMsg.GetHeader("Message-ID") assert.Len(t, mailto, 1, "exactly one recipient is expected in the To field") assert.Equal(t, "[user2/repo1] @user2 #1 - issue1", subject[0]) - assert.Nil(t, msgs[0].GetHeader("In-Reply-To")) - assert.Nil(t, msgs[0].GetHeader("References")) + assert.Nil(t, gomailMsg.GetHeader("In-Reply-To")) + assert.Nil(t, gomailMsg.GetHeader("References")) assert.Equal(t, messageID[0], "<user2/repo1/issues/1@localhost>", "Message-ID header doesn't match") } @@ -134,9 +135,9 @@ func TestTemplateSelection(t *testing.T) { InitMailRender(stpl, btpl) expect := func(t *testing.T, msg *Message, expSubject, expBody string) { - subject := msg.GetHeader("Subject") + subject := msg.ToMessage().GetHeader("Subject") msgbuf := new(bytes.Buffer) - _, _ = msg.WriteTo(msgbuf) + _, _ = msg.ToMessage().WriteTo(msgbuf) wholemsg := msgbuf.String() assert.Equal(t, []string{expSubject}, subject) assert.Contains(t, wholemsg, expBody) @@ -188,9 +189,9 @@ func TestTemplateServices(t *testing.T) { msg := testComposeIssueCommentMessage(t, &mailCommentContext{Issue: issue, Doer: doer, ActionType: actionType, Content: "test body", Comment: comment}, tos, fromMention, "TestTemplateServices") - subject := msg.GetHeader("Subject") + subject := msg.ToMessage().GetHeader("Subject") msgbuf := new(bytes.Buffer) - _, _ = msg.WriteTo(msgbuf) + _, _ = msg.ToMessage().WriteTo(msgbuf) wholemsg := msgbuf.String() assert.Equal(t, []string{expSubject}, subject) diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 2e4aa8d71b..afcc7a7278 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -18,7 +18,9 @@ import ( "time" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" "github.com/jaytaylor/html2text" @@ -27,38 +29,63 @@ import ( // Message mail body and log info type Message struct { - Info string // Message information for log purpose. - *gomail.Message + Info string // Message information for log purpose. + FromAddress string + FromDisplayName string + To []string + Subject string + Date time.Time + Body string + Headers map[string][]string } -// 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) - +// ToMessage converts a Message to gomail.Message +func (m *Message) ToMessage() *gomail.Message { msg := gomail.NewMessage() - msg.SetAddressHeader("From", fromAddress, fromDisplayName) - msg.SetHeader("To", to...) + msg.SetAddressHeader("From", m.FromAddress, m.FromDisplayName) + msg.SetHeader("To", m.To...) + for header := range m.Headers { + msg.SetHeader(header, m.Headers[header]...) + } + if len(setting.MailService.SubjectPrefix) > 0 { - msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+subject) + msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject) } else { - msg.SetHeader("Subject", subject) + msg.SetHeader("Subject", m.Subject) } - msg.SetDateHeader("Date", time.Now()) + msg.SetDateHeader("Date", m.Date) msg.SetHeader("X-Auto-Response-Suppress", "All") - plainBody, err := html2text.FromString(body) + plainBody, err := html2text.FromString(m.Body) if err != nil || setting.MailService.SendAsPlainText { - if strings.Contains(base.TruncateString(body, 100), "<html>") { + if strings.Contains(base.TruncateString(m.Body, 100), "<html>") { log.Warn("Mail contains HTML but configured to send as plain text.") } msg.SetBody("text/plain", plainBody) } else { msg.SetBody("text/plain", plainBody) - msg.AddAlternative("text/html", body) + msg.AddAlternative("text/html", m.Body) } + return msg +} + +// SetHeader adds additional headers to a message +func (m *Message) SetHeader(field string, value ...string) { + m.Headers[field] = value +} + +// 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) return &Message{ - Message: msg, + FromAddress: fromAddress, + FromDisplayName: fromDisplayName, + To: to, + Subject: subject, + Date: time.Now(), + Body: body, + Headers: map[string][]string{}, } } @@ -257,18 +284,7 @@ func (s *dummySender) Send(from string, to []string, msg io.WriterTo) error { return nil } -func processMailQueue() { - for msg := range mailQueue { - log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info) - if err := gomail.Send(Sender, msg.Message); err != nil { - log.Error("Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err) - } else { - log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info) - } - } -} - -var mailQueue chan *Message +var mailQueue queue.Queue // Sender sender for sending mail synchronously var Sender gomail.Sender @@ -291,14 +307,26 @@ func NewContext() { Sender = &dummySender{} } - mailQueue = make(chan *Message, setting.MailService.QueueLength) - go processMailQueue() + mailQueue = queue.CreateQueue("mail", func(data ...queue.Data) { + for _, datum := range data { + msg := datum.(*Message) + gomailMsg := msg.ToMessage() + log.Trace("New e-mail sending request %s: %s", gomailMsg.GetHeader("To"), msg.Info) + if err := gomail.Send(Sender, gomailMsg); err != nil { + log.Error("Failed to send emails %s: %s - %v", gomailMsg.GetHeader("To"), msg.Info, err) + } else { + log.Trace("E-mails sent %s: %s", gomailMsg.GetHeader("To"), msg.Info) + } + } + }, &Message{}) + + go graceful.GetManager().RunWithShutdownFns(mailQueue.Run) } // SendAsync send mail asynchronously func SendAsync(msg *Message) { go func() { - mailQueue <- msg + _ = mailQueue.Push(msg) }() } @@ -306,7 +334,7 @@ func SendAsync(msg *Message) { func SendAsyncs(msgs []*Message) { go func() { for _, msg := range msgs { - mailQueue <- msg + _ = mailQueue.Push(msg) } }() } |