// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package mailer import ( "context" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" sender_service "code.gitea.io/gitea/services/mailer/sender" notify_service "code.gitea.io/gitea/services/notify" ) var mailQueue *queue.WorkerPoolQueue[*sender_service.Message] // sender sender for sending mail synchronously var sender sender_service.Sender // NewContext start mail queue service func NewContext(ctx context.Context) { // Need to check if mailQueue is nil because in during reinstall (user had installed // before but switched install lock off), this function will be called again // while mail queue is already processing tasks, and produces a race condition. if setting.MailService == nil || mailQueue != nil { return } if setting.Service.EnableNotifyMail { notify_service.RegisterNotifier(NewNotifier()) } switch setting.MailService.Protocol { case "sendmail": sender = &sender_service.SendmailSender{} case "dummy": sender = &sender_service.DummySender{} default: sender = &sender_service.SMTPSender{} } subjectTemplates, bodyTemplates = templates.Mailer(ctx) mailQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "mail", func(items ...*sender_service.Message) []*sender_service.Message { for _, msg := range items { gomailMsg := msg.ToMessage() log.Trace("New e-mail sending request %s: %s", gomailMsg.GetGenHeader("To"), msg.Info) if err := sender_service.Send(sender, msg); err != nil { log.Error("Failed to send emails %s: %s - %v", gomailMsg.GetGenHeader("To"), msg.Info, err) } else { log.Trace("E-mails sent %s: %s", gomailMsg.GetGenHeader("To"), msg.Info) } } return nil }) if mailQueue == nil { log.Fatal("Unable to create mail queue") } go graceful.GetManager().RunWithCancel(mailQueue) } // SendAsync send emails asynchronously (make it mockable) var SendAsync = sendAsync func sendAsync(msgs ...*sender_service.Message) { if setting.MailService == nil { log.Error("Mailer: SendAsync is being invoked but mail service hasn't been initialized") return } go func() { for _, msg := range msgs { _ = mailQueue.Push(msg) } }() }