Skip to content

Commit

Permalink
MF-1059 - Add TLS support for email (#1560)
Browse files Browse the repository at this point in the history
* Use gomail package for sending emails

Signed-off-by: Ivan Milosevic <iva@blokovi.com>

* remove print err

Signed-off-by: Ivan Milosevic <iva@blokovi.com>

* Add vendor

Signed-off-by: Ivan Milosevic <iva@blokovi.com>

* Rename email structure
remove logger

Signed-off-by: Ivan Milosevic <iva@blokovi.com>

* typo in var name

Signed-off-by: Ivan Milosevic <iva@blokovi.com>

* rename var

Signed-off-by: Ivan Milosevic <iva@blokovi.com>

* remove MF_EMAIL_SECRET

Signed-off-by: Ivan Milosevic <iva@blokovi.com>
  • Loading branch information
blokovi authored Feb 7, 2022
1 parent 9e0947a commit 1f8a221
Show file tree
Hide file tree
Showing 29 changed files with 1,895 additions and 38 deletions.
3 changes: 0 additions & 3 deletions cmd/smtp-notifier/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ const (
defEmailPort = "25"
defEmailUsername = "root"
defEmailPassword = ""
defEmailSecret = ""
defEmailFromAddress = ""
defEmailFromName = ""
defEmailTemplate = "email.tmpl"
Expand Down Expand Up @@ -91,7 +90,6 @@ const (
envEmailPort = "MF_EMAIL_PORT"
envEmailUsername = "MF_EMAIL_USERNAME"
envEmailPassword = "MF_EMAIL_PASSWORD"
envEmailSecret = "MF_EMAIL_SECRET"
envEmailFromAddress = "MF_EMAIL_FROM_ADDRESS"
envEmailFromName = "MF_EMAIL_FROM_NAME"
envEmailTemplate = "MF_SMTP_NOTIFIER_TEMPLATE"
Expand Down Expand Up @@ -200,7 +198,6 @@ func loadConfig() config {
Port: mainflux.Env(envEmailPort, defEmailPort),
Username: mainflux.Env(envEmailUsername, defEmailUsername),
Password: mainflux.Env(envEmailPassword, defEmailPassword),
Secret: mainflux.Env(envEmailSecret, defEmailSecret),
Template: mainflux.Env(envEmailTemplate, defEmailTemplate),
}

Expand Down
3 changes: 0 additions & 3 deletions cmd/users/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ const (
defEmailPort = "25"
defEmailUsername = "root"
defEmailPassword = ""
defEmailSecret = ""
defEmailFromAddress = ""
defEmailFromName = ""
defEmailTemplate = "email.tmpl"
Expand Down Expand Up @@ -100,7 +99,6 @@ const (
envEmailPort = "MF_EMAIL_PORT"
envEmailUsername = "MF_EMAIL_USERNAME"
envEmailPassword = "MF_EMAIL_PASSWORD"
envEmailSecret = "MF_EMAIL_SECRET"
envEmailFromAddress = "MF_EMAIL_FROM_ADDRESS"
envEmailFromName = "MF_EMAIL_FROM_NAME"
envEmailLogLevel = "MF_EMAIL_LOG_LEVEL"
Expand Down Expand Up @@ -214,7 +212,6 @@ func loadConfig() config {
Port: mainflux.Env(envEmailPort, defEmailPort),
Username: mainflux.Env(envEmailUsername, defEmailUsername),
Password: mainflux.Env(envEmailPassword, defEmailPassword),
Secret: mainflux.Env(envEmailSecret, defEmailSecret),
Template: mainflux.Env(envEmailTemplate, defEmailTemplate),
}

Expand Down
3 changes: 1 addition & 2 deletions consumers/notifiers/smtp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ default values.
| MF_EMAIL_HOST | Mail server host | localhost |
| MF_EMAIL_PORT | Mail server port | 25 |
| MF_EMAIL_USERNAME | Mail server username | |
| MF_EMAIL_PASSWORD | Mail server password for Basic authentication | |
| MF_EMAIL_SECRET | Mail server secret for CRAM-MD5 authentication | |
| MF_EMAIL_PASSWORD | Mail server password | |
| MF_EMAIL_FROM_ADDRESS | Email "from" address | |
| MF_EMAIL_FROM_NAME | Email "from" name | |
| MF_EMAIL_TEMPLATE | Email template for sending notification emails | email.tmpl |
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d
gonum.org/v1/gonum v0.9.3
google.golang.org/grpc v1.43.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)

require (
Expand Down Expand Up @@ -142,6 +143,7 @@ require (
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gorp.v1 v1.7.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2019,6 +2019,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand All @@ -2030,6 +2032,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/gorp.v1 v1.7.1/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw=
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
Expand Down
9 changes: 2 additions & 7 deletions internal/email/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,10 @@ Mainflux Email Agent is configured using the following configuration parameters:
| MF_EMAIL_HOST | Mail server host |
| MF_EMAIL_PORT | Mail server port |
| MF_EMAIL_USERNAME | Mail server username |
| MF_EMAIL_PASSWORD | Mail server password for Basic authentication |
| MF_EMAIL_SECRET | Mail server secret for CRAM-MD5 authentication |
| MF_EMAIL_PASSWORD | Mail server password |
| MF_EMAIL_FROM_ADDRESS | Email "from" address |
| MF_EMAIL_FROM_NAME | Email "from" name |
| MF_EMAIL_TEMPLATE | Email template for sending notification emails |

There are two authentication methods supported: Basic Auth and CRAM-MD5.
`MF_EMAIL_SECRET` indicates that `CRAM-MD5` authentication will be used.
`MF_EMAIL_PASSWORD` indicates that `Basic` authentication will be used.
If both `MF_EMAIL_SECRET` and `MF_EMAIL_PASSWORD` are present, `CRAM-MD5` authentication will be used.
If `MF_EMAIL_USERNAME` is empty or both `MF_EMAIL_SECRET` and `MF_EMAIL_PASSWORD` are empty,
no authentication will be used.
If `MF_EMAIL_USERNAME` is empty, no authentication will be used.
41 changes: 20 additions & 21 deletions internal/email/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ package email

import (
"bytes"
"fmt"
"net/mail"
"net/smtp"
"strconv"
"text/template"

"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"gopkg.in/gomail.v2"
)

var (
Expand All @@ -22,7 +21,7 @@ var (
errSendMail = errors.New("Sending e-mail failed")
)

type emailTemplate struct {
type email struct {
To []string
From string
Subject string
Expand All @@ -37,7 +36,6 @@ type Config struct {
Port string
Username string
Password string
Secret string
FromAddress string
FromName string
Template string
Expand All @@ -46,25 +44,20 @@ type Config struct {
// Agent for mailing
type Agent struct {
conf *Config
auth smtp.Auth
addr string
log logger.Logger
tmpl *template.Template
dial *gomail.Dialer
}

// New creates new email agent
func New(c *Config) (*Agent, error) {
a := &Agent{}
a.conf = c
if c.Username != "" {
switch {
case c.Secret != "":
a.auth = smtp.CRAMMD5Auth(c.Username, c.Secret)
case c.Password != "":
a.auth = smtp.PlainAuth("", c.Username, c.Password, c.Host)
}
port, err := strconv.Atoi(c.Port)
if err != nil {
return a, err
}
a.addr = fmt.Sprintf("%s:%s", c.Host, c.Port)
d := gomail.NewDialer(c.Host, port, c.Username, c.Password)
a.dial = d

tmpl, err := template.ParseFiles(c.Template)
if err != nil {
Expand All @@ -80,8 +73,8 @@ func (a *Agent) Send(To []string, From, Subject, Header, Content, Footer string)
return errMissingEmailTemplate
}

email := new(bytes.Buffer)
tmpl := emailTemplate{
buff := new(bytes.Buffer)
e := email{
To: To,
From: From,
Subject: Subject,
Expand All @@ -91,14 +84,20 @@ func (a *Agent) Send(To []string, From, Subject, Header, Content, Footer string)
}
if From == "" {
from := mail.Address{Name: a.conf.FromName, Address: a.conf.FromAddress}
tmpl.From = from.String()
e.From = from.String()
}

if err := a.tmpl.Execute(email, tmpl); err != nil {
if err := a.tmpl.Execute(buff, e); err != nil {
return errors.Wrap(errExecTemplate, err)
}

if err := smtp.SendMail(a.addr, a.auth, a.conf.FromAddress, To, email.Bytes()); err != nil {
m := gomail.NewMessage()
m.SetHeader("From", e.From)
m.SetHeader("To", To...)
m.SetHeader("Subject", Subject)
m.SetBody("text/plain", buff.String())

if err := a.dial.DialAndSend(m); err != nil {
return errors.Wrap(errSendMail, err)
}

Expand Down
3 changes: 1 addition & 2 deletions users/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ default values.
| MF_EMAIL_HOST | Mail server host | localhost |
| MF_EMAIL_PORT | Mail server port | 25 |
| MF_EMAIL_USERNAME | Mail server username | |
| MF_EMAIL_PASSWORD | Mail server password for Basic authentication | |
| MF_EMAIL_SECRET | Mail server secret for CRAM-MD5 authentication | |
| MF_EMAIL_PASSWORD | Mail server password | |
| MF_EMAIL_FROM_ADDRESS | Email "from" address | |
| MF_EMAIL_FROM_NAME | Email "from" name | |
| MF_EMAIL_TEMPLATE | Email template for sending emails with password reset link | email.tmpl |
Expand Down
20 changes: 20 additions & 0 deletions vendor/gopkg.in/alexcesaro/quotedprintable.v3/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions vendor/gopkg.in/alexcesaro/quotedprintable.v3/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1f8a221

Please sign in to comment.