diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 8900a58342..0c29932d92 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -649,6 +649,8 @@ MAILER_TYPE = smtp SENDMAIL_PATH = sendmail ; Specify any extra sendmail arguments SENDMAIL_ARGS = +; Timeout for Sendmail +SENDMAIL_TIMEOUT = 5m [cache] ; if the cache enabled diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 000b65f5a1..f9bc05acbb 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -410,6 +410,7 @@ set name for unique queues. Individual queues will default to - Enabling dummy will ignore all settings except `ENABLED`, `SUBJECT_PREFIX` and `FROM`. - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be command or full path). +- `SENDMAIL_TIMEOUT`: **5m**: default timeout for sending email through sendmail - ``IS_TLS_ENABLED`` : **false** : Decide if SMTP connections should use TLS. ## Cache (`cache`) diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index c692e0fe14..a2228e938b 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -6,6 +6,7 @@ package setting import ( "net/mail" + "time" "code.gitea.io/gitea/modules/log" @@ -35,8 +36,9 @@ type Mailer struct { IsTLSEnabled bool // Sendmail sender - SendmailPath string - SendmailArgs []string + SendmailPath string + SendmailArgs []string + SendmailTimeout time.Duration } var ( @@ -69,7 +71,8 @@ func newMailService() { IsTLSEnabled: sec.Key("IS_TLS_ENABLED").MustBool(), SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString(""), - SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"), + SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"), + SendmailTimeout: sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute), } MailService.From = sec.Key("FROM").MustString(MailService.User) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a6c5d41978..fe68573529 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2119,6 +2119,7 @@ config.mailer_user = User config.mailer_use_sendmail = Use Sendmail config.mailer_sendmail_path = Sendmail Path config.mailer_sendmail_args = Extra Arguments to Sendmail +config.mailer_sendmail_timeout = Sendmail Timeout config.send_test_mail = Send Testing Email config.test_mail_failed = Failed to send a testing email to '%s': %v config.test_mail_sent = A testing email has been sent to '%s'. diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 9ff1729104..2e7beffa15 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -7,6 +7,7 @@ package mailer import ( "bytes" + "context" "crypto/tls" "fmt" "io" @@ -20,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" @@ -244,7 +246,14 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error { args = append(args, setting.MailService.SendmailArgs...) args = append(args, to...) log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args) - cmd := exec.Command(setting.MailService.SendmailPath, args...) + + pm := process.GetManager() + desc := fmt.Sprintf("SendMail: %s %v", setting.MailService.SendmailPath, args) + + ctx, cancel := context.WithTimeout(graceful.GetManager().HammerContext(), setting.MailService.SendmailTimeout) + defer cancel() + + cmd := exec.CommandContext(ctx, setting.MailService.SendmailPath, args...) pipe, err := cmd.StdinPipe() if err != nil { @@ -255,12 +264,15 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error { return err } + pid := pm.Add(desc, cancel) + _, err = msg.WriteTo(pipe) // we MUST close the pipe or sendmail will hang waiting for more of the message // Also we should wait on our sendmail command even if something fails closeError = pipe.Close() waitError = cmd.Wait() + pm.Remove(pid) if err != nil { return err } else if closeError != nil { diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 27a47505b5..1b553230b7 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -228,6 +228,8 @@