summaryrefslogtreecommitdiffstats
path: root/services/mailer/mailer.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/mailer/mailer.go')
-rw-r--r--services/mailer/mailer.go95
1 files changed, 56 insertions, 39 deletions
diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go
index f4bc2ddc63..c86c54c748 100644
--- a/services/mailer/mailer.go
+++ b/services/mailer/mailer.go
@@ -147,65 +147,82 @@ type smtpSender struct{}
func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
opts := setting.MailService
- host, port, err := net.SplitHostPort(opts.Host)
- if err != nil {
- return err
+ var network string
+ var address string
+ if opts.Protocol == "smtp+unix" {
+ network = "unix"
+ address = opts.SMTPAddr
+ } else {
+ network = "tcp"
+ address = net.JoinHostPort(opts.SMTPAddr, opts.SMTPPort)
}
- tlsconfig := &tls.Config{
- InsecureSkipVerify: opts.SkipVerify,
- ServerName: host,
+ conn, err := net.Dial(network, address)
+ if err != nil {
+ return fmt.Errorf("failed to establish network connection to SMTP server: %v", err)
}
+ defer conn.Close()
- if opts.UseCertificate {
- cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)
- if err != nil {
- return err
+ var tlsconfig *tls.Config
+ if opts.Protocol == "smtps" || opts.Protocol == "smtp+startls" {
+ tlsconfig = &tls.Config{
+ InsecureSkipVerify: opts.ForceTrustServerCert,
+ ServerName: opts.SMTPAddr,
}
- tlsconfig.Certificates = []tls.Certificate{cert}
- }
- conn, err := net.Dial("tcp", net.JoinHostPort(host, port))
- if err != nil {
- return err
+ if opts.UseClientCert {
+ cert, err := tls.LoadX509KeyPair(opts.ClientCertFile, opts.ClientKeyFile)
+ if err != nil {
+ return fmt.Errorf("could not load SMTP client certificate: %v", err)
+ }
+ tlsconfig.Certificates = []tls.Certificate{cert}
+ }
}
- defer conn.Close()
- isSecureConn := opts.IsTLSEnabled || (strings.HasSuffix(port, "465"))
- // Start TLS directly if the port ends with 465 (SMTPS protocol)
- if isSecureConn {
+ if opts.Protocol == "smtps" {
conn = tls.Client(conn, tlsconfig)
}
+ host := "localhost"
+ if opts.Protocol == "smtp+unix" {
+ host = opts.SMTPAddr
+ }
client, err := smtp.NewClient(conn, host)
if err != nil {
- return fmt.Errorf("NewClient: %v", err)
+ return fmt.Errorf("could not initiate SMTP session: %v", err)
}
- if !opts.DisableHelo {
+ if opts.EnableHelo {
hostname := opts.HeloHostname
if len(hostname) == 0 {
hostname, err = os.Hostname()
if err != nil {
- return err
+ return fmt.Errorf("could not retrieve system hostname: %v", err)
}
}
if err = client.Hello(hostname); err != nil {
- return fmt.Errorf("Hello: %v", err)
+ return fmt.Errorf("failed to issue HELO command: %v", err)
}
}
- // If not using SMTPS, always use STARTTLS if available
- hasStartTLS, _ := client.Extension("STARTTLS")
- if !isSecureConn && hasStartTLS {
- if err = client.StartTLS(tlsconfig); err != nil {
- return fmt.Errorf("StartTLS: %v", err)
+ if opts.Protocol == "smtp+startls" {
+ hasStartTLS, _ := client.Extension("STARTTLS")
+ if hasStartTLS {
+ if err = client.StartTLS(tlsconfig); err != nil {
+ return fmt.Errorf("failed to start TLS connection: %v", err)
+ }
+ } else {
+ log.Warn("StartTLS requested, but SMTP server does not support it; falling back to regular SMTP")
}
}
canAuth, options := client.Extension("AUTH")
- if canAuth && len(opts.User) > 0 {
+ if len(opts.User) > 0 {
+ if !canAuth {
+ return fmt.Errorf("SMTP server does not support AUTH, but credentials provided")
+ }
+
var auth smtp.Auth
if strings.Contains(options, "CRAM-MD5") {
@@ -219,34 +236,34 @@ func (s *smtpSender) Send(from string, to []string, msg io.WriterTo) error {
if auth != nil {
if err = client.Auth(auth); err != nil {
- return fmt.Errorf("Auth: %v", err)
+ return fmt.Errorf("failed to authenticate SMTP: %v", err)
}
}
}
if opts.OverrideEnvelopeFrom {
if err = client.Mail(opts.EnvelopeFrom); err != nil {
- return fmt.Errorf("Mail: %v", err)
+ return fmt.Errorf("failed to issue MAIL command: %v", err)
}
} else {
if err = client.Mail(from); err != nil {
- return fmt.Errorf("Mail: %v", err)
+ return fmt.Errorf("failed to issue MAIL command: %v", err)
}
}
for _, rec := range to {
if err = client.Rcpt(rec); err != nil {
- return fmt.Errorf("Rcpt: %v", err)
+ return fmt.Errorf("failed to issue RCPT command: %v", err)
}
}
w, err := client.Data()
if err != nil {
- return fmt.Errorf("Data: %v", err)
+ return fmt.Errorf("failed to issue DATA command: %v", err)
} else if _, err = msg.WriteTo(w); err != nil {
- return fmt.Errorf("WriteTo: %v", err)
+ return fmt.Errorf("SMTP write failed: %v", err)
} else if err = w.Close(); err != nil {
- return fmt.Errorf("Close: %v", err)
+ return fmt.Errorf("SMTP close failed: %v", err)
}
return client.Quit()
@@ -338,13 +355,13 @@ func NewContext() {
return
}
- switch setting.MailService.MailerType {
- case "smtp":
- Sender = &smtpSender{}
+ switch setting.MailService.Protocol {
case "sendmail":
Sender = &sendmailSender{}
case "dummy":
Sender = &dummySender{}
+ default:
+ Sender = &smtpSender{}
}
mailQueue = queue.CreateQueue("mail", func(data ...queue.Data) []queue.Data {