Sendmail should create a process on the gitea system and have a default timeout (#11256)

* Make sure that sendmail processes register with the process manager
* Provide a timeout for these (initially of 5 minutes)
* Add configurable value and tie in to documentation
* Tie in to the admin config page.

Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
zeripath 2020-05-03 00:04:31 +01:00 committed by GitHub
parent 319eb83112
commit 4f9d59be17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 25 additions and 4 deletions

View file

@ -649,6 +649,8 @@ MAILER_TYPE = smtp
SENDMAIL_PATH = sendmail SENDMAIL_PATH = sendmail
; Specify any extra sendmail arguments ; Specify any extra sendmail arguments
SENDMAIL_ARGS = SENDMAIL_ARGS =
; Timeout for Sendmail
SENDMAIL_TIMEOUT = 5m
[cache] [cache]
; if the cache enabled ; if the cache enabled

View file

@ -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`. - 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 - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be
command or full path). 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. - ``IS_TLS_ENABLED`` : **false** : Decide if SMTP connections should use TLS.
## Cache (`cache`) ## Cache (`cache`)

View file

@ -6,6 +6,7 @@ package setting
import ( import (
"net/mail" "net/mail"
"time"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -35,8 +36,9 @@ type Mailer struct {
IsTLSEnabled bool IsTLSEnabled bool
// Sendmail sender // Sendmail sender
SendmailPath string SendmailPath string
SendmailArgs []string SendmailArgs []string
SendmailTimeout time.Duration
} }
var ( var (
@ -69,7 +71,8 @@ func newMailService() {
IsTLSEnabled: sec.Key("IS_TLS_ENABLED").MustBool(), IsTLSEnabled: sec.Key("IS_TLS_ENABLED").MustBool(),
SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString(""), 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) MailService.From = sec.Key("FROM").MustString(MailService.User)

View file

@ -2119,6 +2119,7 @@ config.mailer_user = User
config.mailer_use_sendmail = Use Sendmail config.mailer_use_sendmail = Use Sendmail
config.mailer_sendmail_path = Sendmail Path config.mailer_sendmail_path = Sendmail Path
config.mailer_sendmail_args = Extra Arguments to Sendmail config.mailer_sendmail_args = Extra Arguments to Sendmail
config.mailer_sendmail_timeout = Sendmail Timeout
config.send_test_mail = Send Testing Email config.send_test_mail = Send Testing Email
config.test_mail_failed = Failed to send a testing email to '%s': %v 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'. config.test_mail_sent = A testing email has been sent to '%s'.

View file

@ -7,6 +7,7 @@ package mailer
import ( import (
"bytes" "bytes"
"context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io" "io"
@ -20,6 +21,7 @@ import (
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting" "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, setting.MailService.SendmailArgs...)
args = append(args, to...) args = append(args, to...)
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args) 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() pipe, err := cmd.StdinPipe()
if err != nil { if err != nil {
@ -255,12 +264,15 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
return err return err
} }
pid := pm.Add(desc, cancel)
_, err = msg.WriteTo(pipe) _, err = msg.WriteTo(pipe)
// we MUST close the pipe or sendmail will hang waiting for more of the message // 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 // Also we should wait on our sendmail command even if something fails
closeError = pipe.Close() closeError = pipe.Close()
waitError = cmd.Wait() waitError = cmd.Wait()
pm.Remove(pid)
if err != nil { if err != nil {
return err return err
} else if closeError != nil { } else if closeError != nil {

View file

@ -228,6 +228,8 @@
<dd>{{.Mailer.SendmailPath}}</dd> <dd>{{.Mailer.SendmailPath}}</dd>
<dt>{{.i18n.Tr "admin.config.mailer_sendmail_args"}}</dt> <dt>{{.i18n.Tr "admin.config.mailer_sendmail_args"}}</dt>
<dd>{{.Mailer.SendmailArgs}}</dd> <dd>{{.Mailer.SendmailArgs}}</dd>
<dt>{{.i18n.Tr "admin.config.mailer_sendmail_timeout"}}</dt>
<dd>{{.Mailer.SendmailTimeout}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
{{end}} {{end}}
<dt>{{.i18n.Tr "admin.config.mailer_user"}}</dt> <dt>{{.i18n.Tr "admin.config.mailer_user"}}</dt>
<dd>{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}</dd><br> <dd>{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}</dd><br>