summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip Couling <couling@gmail.com>2016-12-25 13:55:22 +0000
committerKim "BKC" Carlbäcker <kim.carlbacker@gmail.com>2016-12-25 14:55:22 +0100
commitd4924d45d6d4e991240d207a834d8d6709781449 (patch)
treebdf6c450d7712ba17c2b06fba45cdeb0579090ec
parent8de8ec027d1ca44f889b89a69b26c3a9b599bbb6 (diff)
downloadgitea-d4924d45d6d4e991240d207a834d8d6709781449.tar.gz
gitea-d4924d45d6d4e991240d207a834d8d6709781449.zip
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
-rw-r--r--conf/app.ini4
-rw-r--r--models/mail.go2
-rw-r--r--modules/mailer/mailer.go60
-rw-r--r--modules/setting/setting.go17
4 files changed, 73 insertions, 10 deletions
diff --git a/conf/app.ini b/conf/app.ini
index c46d52f2d5..cef7ae6d5b 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -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"
diff --git a/models/mail.go b/models/mail.go
index 8f54d6651f..e66e316ba0 100644
--- a/models/mail.go
+++ b/models/mail.go
@@ -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
diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go
index 3dc2c4e531..3201075f3f 100644
--- a/modules/mailer/mailer.go
+++ b/modules/mailer/mailer.go
@@ -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()
}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index fad884ae1e..81fcb4b150 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -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)