Skip to content

Commit d4924d4

Browse files
coulingbkcsoft
authored andcommitted
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
1 parent 8de8ec0 commit d4924d4

File tree

4 files changed

+73
-10
lines changed

4 files changed

+73
-10
lines changed

conf/app.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ USER =
226226
PASSWD =
227227
; Use text/html as alternative format of content
228228
ENABLE_HTML_ALTERNATIVE = false
229+
; Enable sendmail (override SMTP)
230+
USE_SENDMAIL = false
231+
; Specifiy an alternative sendmail binary
232+
SENDMAIL_PATH = sendmail
229233

230234
[cache]
231235
; Either "memory", "redis", or "memcache", default is "memory"

models/mail.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func InitMailRender(tmpls *template.Template) {
4040

4141
// SendTestMail sends a test mail
4242
func SendTestMail(email string) error {
43-
return gomail.Send(&mailer.Sender{}, mailer.NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message)
43+
return gomail.Send(mailer.Sender, mailer.NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message)
4444
}
4545

4646
// SendUserMail sends a mail to the user

modules/mailer/mailer.go

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"net"
1212
"net/smtp"
1313
"os"
14+
"os/exec"
1415
"strings"
1516
"time"
1617

@@ -87,12 +88,12 @@ func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
8788
return nil, nil
8889
}
8990

90-
// Sender mail sender
91-
type Sender struct {
91+
// Sender SMTP mail sender
92+
type smtpSender struct {
9293
}
9394

9495
// Send send email
95-
func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
96+
func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
9697
opts := setting.MailService
9798

9899
host, port, err := net.SplitHostPort(opts.Host)
@@ -195,14 +196,51 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
195196
return client.Quit()
196197
}
197198

198-
func processMailQueue() {
199-
sender := &Sender{}
199+
// Sender sendmail mail sender
200+
type sendmailSender struct {
201+
}
202+
203+
// Send send email
204+
func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
205+
var err error
206+
var closeError error
207+
var waitError error
208+
209+
args := []string{"-F", from, "-i"}
210+
args = append(args, to...)
211+
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
212+
cmd := exec.Command(setting.MailService.SendmailPath, args...)
213+
pipe, err := cmd.StdinPipe()
214+
215+
if err != nil {
216+
return err
217+
}
218+
219+
if err = cmd.Start(); err != nil {
220+
return err
221+
}
222+
223+
_,err = msg.WriteTo(pipe)
200224

225+
// we MUST close the pipe or sendmail will hang waiting for more of the message
226+
// Also we should wait on our sendmail command even if something fails
227+
closeError = pipe.Close()
228+
waitError = cmd.Wait()
229+
if err != nil {
230+
return err
231+
} else if closeError != nil {
232+
return closeError
233+
} else {
234+
return waitError
235+
}
236+
}
237+
238+
func processMailQueue() {
201239
for {
202240
select {
203241
case msg := <-mailQueue:
204242
log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info)
205-
if err := gomail.Send(sender, msg.Message); err != nil {
243+
if err := gomail.Send(Sender, msg.Message); err != nil {
206244
log.Error(3, "Fail to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err)
207245
} else {
208246
log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info)
@@ -213,6 +251,9 @@ func processMailQueue() {
213251

214252
var mailQueue chan *Message
215253

254+
// Sender sender for sending mail synchronously
255+
var Sender gomail.Sender
256+
216257
// NewContext start mail queue service
217258
func NewContext() {
218259
// Need to check if mailQueue is nil because in during reinstall (user had installed
@@ -222,6 +263,13 @@ func NewContext() {
222263
return
223264
}
224265

266+
267+
if setting.MailService.UseSendmail {
268+
Sender = &sendmailSender{}
269+
} else {
270+
Sender = &smtpSender{}
271+
}
272+
225273
mailQueue = make(chan *Message, setting.MailService.QueueLength)
226274
go processMailQueue()
227275
}

modules/setting/setting.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -858,18 +858,25 @@ func newSessionService() {
858858

859859
// Mailer represents mail service.
860860
type Mailer struct {
861+
// Mailer
861862
QueueLength int
862863
Name string
863-
Host string
864864
From string
865865
FromEmail string
866+
EnableHTMLAlternative bool
867+
868+
// SMTP sender
869+
Host string
866870
User, Passwd string
867871
DisableHelo bool
868872
HeloHostname string
869873
SkipVerify bool
870874
UseCertificate bool
871875
CertFile, KeyFile string
872-
EnableHTMLAlternative bool
876+
877+
// Sendmail sender
878+
UseSendmail bool
879+
SendmailPath string
873880
}
874881

875882
var (
@@ -887,6 +894,8 @@ func newMailService() {
887894
MailService = &Mailer{
888895
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
889896
Name: sec.Key("NAME").MustString(AppName),
897+
EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
898+
890899
Host: sec.Key("HOST").String(),
891900
User: sec.Key("USER").String(),
892901
Passwd: sec.Key("PASSWD").String(),
@@ -896,7 +905,9 @@ func newMailService() {
896905
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
897906
CertFile: sec.Key("CERT_FILE").String(),
898907
KeyFile: sec.Key("KEY_FILE").String(),
899-
EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
908+
909+
UseSendmail: sec.Key("USE_SENDMAIL").MustBool(),
910+
SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"),
900911
}
901912
MailService.From = sec.Key("FROM").MustString(MailService.User)
902913

0 commit comments

Comments
 (0)