diff --git a/config/iris.go b/config/iris.go
index 8b4641b4..0180ea65 100644
--- a/config/iris.go
+++ b/config/iris.go
@@ -83,7 +83,10 @@ type (
// Render contains the configs for template and rest configuration
Render Render
+ // Websocket contains the configs for Websocket's server integration
Websocket Websocket
+ // Mail contains the config for the mail sender service
+ Mail Mail
}
// Render struct keeps organise all configuration about rendering, templates and rest currently.
@@ -121,6 +124,7 @@ func Default() Iris {
Sessions: DefaultSessions(),
Render: DefaultRender(),
Websocket: DefaultWebsocket(),
+ Mail: DefaultMail(),
}
}
diff --git a/config/logger.go b/config/logger.go
index 39d19aa4..1aa47584 100644
--- a/config/logger.go
+++ b/config/logger.go
@@ -38,7 +38,7 @@ func (c Logger) Merge(cfg []Logger) (config Logger) {
return
}
-// Merge MergeSingle the default with the given config and returns the result
+// MergeSingle merges the default with the given config and returns the result
func (c Logger) MergeSingle(cfg Logger) (config Logger) {
config = cfg
diff --git a/config/mail.go b/config/mail.go
new file mode 100644
index 00000000..72a2ce86
--- /dev/null
+++ b/config/mail.go
@@ -0,0 +1,19 @@
+package config
+
+// Mail keeps the configs for mail sender service
+type Mail struct {
+ // Host is the server mail host, IP or address
+ Host string
+ // Port is the listening port
+ Port int
+ // Username is the auth username@domain.com for the sender
+ Username string
+ // Password is the auth password for the sender
+ Password string
+}
+
+// DefaultMail returns the default configs for Mail
+// returns just an empty Mail struct
+func DefaultMail() Mail {
+ return Mail{}
+}
diff --git a/iris.go b/iris.go
index 6da1433c..5ba599b8 100644
--- a/iris.go
+++ b/iris.go
@@ -15,6 +15,7 @@ import (
"github.com/fatih/color"
"github.com/kataras/iris/config"
"github.com/kataras/iris/logger"
+ "github.com/kataras/iris/mail"
"github.com/kataras/iris/render/rest"
"github.com/kataras/iris/render/template"
"github.com/kataras/iris/server"
@@ -80,6 +81,7 @@ type (
templates *template.Template
sessionManager *sessions.Manager
websocketServer websocket.Server
+ mailService mail.Service
logger *logger.Logger
gzipWriterPool sync.Pool // this pool is used everywhere needed in the iris for example inside party-> StaticSimple
}
@@ -130,6 +132,15 @@ func (s *Iris) initWebsocketServer() {
}
}
+func (s *Iris) initMailService() {
+ if s.mailService == nil {
+ // enable mail sender service if configs are valid
+ if s.config.Mail.Host != "" && s.config.Mail.Username != "" && s.config.Mail.Password != "" {
+ s.mailService = mail.New(s.config.Mail)
+ }
+ }
+}
+
func (s *Iris) printBanner() {
c := color.New(color.FgHiBlue).Add(color.Bold)
printTicker := utils.NewTicker()
@@ -321,3 +332,9 @@ func (s *Iris) Websocket() websocket.Server {
s.initWebsocketServer() // for any case the user called .Websocket() before server's listen
return s.websocketServer
}
+
+// Mail returns the mail sender service
+func (s *Iris) Mail() mail.Service {
+ s.initMailService()
+ return s.mailService
+}
diff --git a/iris_singleton.go b/iris_singleton.go
index caaf7411..fac55cf1 100644
--- a/iris_singleton.go
+++ b/iris_singleton.go
@@ -3,6 +3,7 @@ package iris
import (
"github.com/kataras/iris/config"
"github.com/kataras/iris/logger"
+ "github.com/kataras/iris/mail"
"github.com/kataras/iris/render/rest"
"github.com/kataras/iris/render/template"
"github.com/kataras/iris/server"
@@ -393,3 +394,8 @@ func Templates() *template.Template {
func Websocket() websocket.Server {
return DefaultIris.Websocket()
}
+
+// Mail returns the mail sender service
+func Mail() mail.Service {
+ return DefaultIris.Mail()
+}
diff --git a/mail/service.go b/mail/service.go
new file mode 100644
index 00000000..a60dbfdb
--- /dev/null
+++ b/mail/service.go
@@ -0,0 +1,72 @@
+package mail
+
+import (
+ "fmt"
+ "net/smtp"
+ "strings"
+ "text/template"
+
+ "github.com/kataras/iris/config"
+ "github.com/kataras/iris/utils"
+)
+
+const tmpl = `From: {{.From}}
To: {{.To}}
Subject: {{.Subject}}
MIME-version: 1.0
Content-Type: text/html; charset="UTF-8"
{{.Body}}`
+
+var buf = utils.NewBufferPool(64)
+
+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(to []string, subject, body string) error
+ }
+
+ mailer struct {
+ config config.Mail
+ auth smtp.Auth
+ authenticated bool
+ }
+)
+
+// New creates and returns a new Service
+func New(cfg config.Mail) Service {
+ return &mailer{config: cfg}
+}
+
+func (m *mailer) authenticate() error {
+ if m.config.Username == "" || m.config.Password == "" || m.config.Host == "" {
+ return fmt.Errorf("Username, Password & Host cannot be empty!")
+ }
+ m.auth = smtp.PlainAuth("", m.config.Username, m.config.Password, m.config.Host)
+ m.authenticated = true
+ return nil
+}
+
+// Send sends a mail to recipients
+// the body can be html also
+func (m *mailer) Send(to []string, subject, body string) error {
+ buffer := buf.Get()
+ defer buf.Put(buffer)
+
+ if !m.authenticated {
+ if err := m.authenticate(); err != nil {
+ return err
+ }
+ }
+
+ mailArgs := map[string]string{"To": strings.Join(to, ","), "Subject": subject, "Body": body}
+ template := template.Must(template.New("mailTmpl").Parse(tmpl))
+
+ if err := template.Execute(buffer, mailArgs); err != nil {
+ return err
+ }
+
+ return smtp.SendMail(
+ fmt.Sprintf("%s:%d", m.config.Host, m.config.Port),
+ m.auth,
+ m.config.Username,
+ to,
+ buffer.Bytes(),
+ )
+}