iris/mail/service.go

124 lines
3.0 KiB
Go
Raw Normal View History

2016-06-01 14:29:38 +02:00
package mail
import (
"encoding/base64"
2016-06-01 14:29:38 +02:00
"fmt"
"net/mail"
2016-06-01 14:29:38 +02:00
"net/smtp"
"strings"
"sync"
2016-06-01 14:29:38 +02:00
"github.com/kataras/iris/config"
"github.com/kataras/iris/utils"
)
var buf = utils.NewBufferPool(64)
var once sync.Once
2016-06-01 14:29:38 +02:00
type (
// Service is the interface which mail sender should implement
Service interface {
// Send sends a mail to recipients
// the body can be html also
Send(string, string, ...string) error
UpdateConfig(config.Mail)
2016-06-01 14:29:38 +02:00
}
mailer struct {
config *config.Mail
fromAddr mail.Address
2016-06-01 14:29:38 +02:00
auth smtp.Auth
authenticated bool
}
)
// New creates and returns a new Service
func New(cfg config.Mail) Service {
m := &mailer{config: &cfg}
if cfg.FromAlias == "" {
if !cfg.UseCommand && cfg.Username != "" && strings.Contains(cfg.Username, "@") {
m.fromAddr = mail.Address{Name: cfg.Username[0:strings.IndexByte(cfg.Username, '@')], Address: cfg.Username}
}
} else {
m.fromAddr = mail.Address{Name: cfg.FromAlias, Address: cfg.Username}
}
return m
2016-06-01 14:29:38 +02:00
}
func (m *mailer) UpdateConfig(cfg config.Mail) {
m.config = &cfg
}
2016-06-01 14:29:38 +02:00
// Send sends a mail to recipients
// the body can be html also
func (m *mailer) Send(subject string, body string, to ...string) error {
if m.config.UseCommand {
return m.sendCmd(subject, body, to)
}
return m.sendSMTP(subject, body, to)
}
func (m *mailer) sendSMTP(subject string, body string, to []string) error {
2016-06-01 14:29:38 +02:00
buffer := buf.Get()
defer buf.Put(buffer)
if !m.authenticated {
cfg := m.config
if cfg.Username == "" || cfg.Password == "" || cfg.Host == "" || cfg.Port <= 0 {
return fmt.Errorf("Username, Password, Host & Port cannot be empty when using SMTP!")
2016-06-01 14:29:38 +02:00
}
m.auth = smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host)
m.authenticated = true
2016-06-01 14:29:38 +02:00
}
fullhost := fmt.Sprintf("%s:%d", m.config.Host, m.config.Port)
header := make(map[string]string)
header["From"] = m.fromAddr.String()
header["To"] = strings.Join(to, ",")
header["Subject"] = subject
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/html; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
2016-06-01 14:29:38 +02:00
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\r\n", k, v)
2016-06-01 14:29:38 +02:00
}
message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
2016-06-01 14:29:38 +02:00
return smtp.SendMail(
fmt.Sprintf(fullhost),
2016-06-01 14:29:38 +02:00
m.auth,
m.config.Username,
to,
[]byte(message),
2016-06-01 14:29:38 +02:00
)
}
func (m *mailer) sendCmd(subject string, body string, to []string) error {
buffer := buf.Get()
defer buf.Put(buffer)
header := make(map[string]string)
header["To"] = strings.Join(to, ",")
header["Subject"] = subject
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/html; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
buffer.WriteString(message)
// fix by @qskousen
cmd := utils.CommandBuilder("sendmail", "-F", m.fromAddr.Name, "-f", m.fromAddr.Address, "-t")
cmd.Stdin = buffer
_, err := cmd.CombinedOutput()
return err
}