Implement sendmail (#355)

* Implemented sendmail. This piggybacks on existing configuration to keep the change simple

* Changed privicy of new sendSMTP and sendSendmail functions

* Fixed Lint errors

* Seperated SMTP and sendmail into their own senders

* Making new structs private as they should not be used externally now

* Added sendmail setting to ini file

* Minor code cleanup
release/v1.15
Philip Couling 2016-12-25 13:55:22 +00:00 committed by Kim "BKC" Carlbäcker
parent 8de8ec027d
commit d4924d45d6
4 changed files with 73 additions and 10 deletions

View File

@ -226,6 +226,10 @@ USER =
PASSWD =
; Use text/html as alternative format of content
ENABLE_HTML_ALTERNATIVE = false
; Enable sendmail (override SMTP)
USE_SENDMAIL = false
; Specifiy an alternative sendmail binary
SENDMAIL_PATH = sendmail
[cache]
; Either "memory", "redis", or "memcache", default is "memory"

View File

@ -40,7 +40,7 @@ func InitMailRender(tmpls *template.Template) {
// SendTestMail sends a test mail
func SendTestMail(email string) error {
return gomail.Send(&mailer.Sender{}, mailer.NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message)
return gomail.Send(mailer.Sender, mailer.NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message)
}
// SendUserMail sends a mail to the user

View File

@ -11,6 +11,7 @@ import (
"net"
"net/smtp"
"os"
"os/exec"
"strings"
"time"
@ -87,12 +88,12 @@ func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
return nil, nil
}
// Sender mail sender
type Sender struct {
// Sender SMTP mail sender
type smtpSender struct {
}
// Send send email
func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
opts := setting.MailService
host, port, err := net.SplitHostPort(opts.Host)
@ -195,14 +196,51 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
return client.Quit()
}
func processMailQueue() {
sender := &Sender{}
// Sender sendmail mail sender
type sendmailSender struct {
}
// Send send email
func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
var err error
var closeError error
var waitError error
args := []string{"-F", from, "-i"}
args = append(args, to...)
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
cmd := exec.Command(setting.MailService.SendmailPath, args...)
pipe, err := cmd.StdinPipe()
if err != nil {
return err
}
if err = cmd.Start(); err != nil {
return err
}
_,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()
if err != nil {
return err
} else if closeError != nil {
return closeError
} else {
return waitError
}
}
func processMailQueue() {
for {
select {
case msg := <-mailQueue:
log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info)
if err := gomail.Send(sender, msg.Message); err != nil {
if err := gomail.Send(Sender, msg.Message); err != nil {
log.Error(3, "Fail 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)
@ -213,6 +251,9 @@ func processMailQueue() {
var mailQueue chan *Message
// Sender sender for sending mail synchronously
var Sender gomail.Sender
// NewContext start mail queue service
func NewContext() {
// Need to check if mailQueue is nil because in during reinstall (user had installed
@ -222,6 +263,13 @@ func NewContext() {
return
}
if setting.MailService.UseSendmail {
Sender = &sendmailSender{}
} else {
Sender = &smtpSender{}
}
mailQueue = make(chan *Message, setting.MailService.QueueLength)
go processMailQueue()
}

View File

@ -858,18 +858,25 @@ func newSessionService() {
// Mailer represents mail service.
type Mailer struct {
// Mailer
QueueLength int
Name string
Host string
From string
FromEmail string
EnableHTMLAlternative bool
// SMTP sender
Host string
User, Passwd string
DisableHelo bool
HeloHostname string
SkipVerify bool
UseCertificate bool
CertFile, KeyFile string
EnableHTMLAlternative bool
// Sendmail sender
UseSendmail bool
SendmailPath string
}
var (
@ -887,6 +894,8 @@ func newMailService() {
MailService = &Mailer{
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
Name: sec.Key("NAME").MustString(AppName),
EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
Host: sec.Key("HOST").String(),
User: sec.Key("USER").String(),
Passwd: sec.Key("PASSWD").String(),
@ -896,7 +905,9 @@ func newMailService() {
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
CertFile: sec.Key("CERT_FILE").String(),
KeyFile: sec.Key("KEY_FILE").String(),
EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
UseSendmail: sec.Key("USE_SENDMAIL").MustBool(),
SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"),
}
MailService.From = sec.Key("FROM").MustString(MailService.User)