2015-08-18 05:57:27 +05:30
|
|
|
package email
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2015-09-22 02:12:37 +05:30
|
|
|
"expvar"
|
2015-08-18 05:57:27 +05:30
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
FakeEmailerType = "fake"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2015-09-22 02:12:37 +05:30
|
|
|
counterEmailSendErr = expvar.NewInt("email.send.err")
|
|
|
|
ErrorNoTemplate = errors.New("No HTML or Text template found for template name.")
|
2015-08-18 05:57:27 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
RegisterEmailerConfigType(FakeEmailerType, func() EmailerConfig { return &FakeEmailerConfig{} })
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emailer is an object that sends emails.
|
|
|
|
type Emailer interface {
|
|
|
|
// SendMail queues an email to be sent to 1 or more recipients.
|
|
|
|
// At least one of "text" or "html" must not be blank. If text is blank, but
|
|
|
|
// html is not, then an html-only email should be sent and vice-versal.
|
2016-06-28 12:04:55 +05:30
|
|
|
SendMail(subject, text, html string, to ...string) error
|
2015-08-18 05:57:27 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
//go:generate genconfig -o config.go email Emailer
|
|
|
|
type EmailerConfig interface {
|
|
|
|
EmailerID() string
|
|
|
|
EmailerType() string
|
2016-06-28 12:04:55 +05:30
|
|
|
|
|
|
|
// Because emailers can either be configured through command line flags or through
|
|
|
|
// JSON configs, we need a way to set the fromAddr when initializing the emailer.
|
|
|
|
//
|
|
|
|
// Values passed in the JSON config should override this value. Supplying neither
|
|
|
|
// should result in an error.
|
|
|
|
Emailer(fromAddress string) (Emailer, error)
|
2015-08-18 05:57:27 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func newEmailerConfigFromReader(r io.Reader) (EmailerConfig, error) {
|
|
|
|
var m map[string]interface{}
|
|
|
|
if err := json.NewDecoder(r).Decode(&m); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cfg, err := newEmailerConfigFromMap(m)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cfg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewEmailerConfigFromFile(loc string) (EmailerConfig, error) {
|
|
|
|
cf, err := os.Open(loc)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer cf.Close()
|
|
|
|
|
|
|
|
cfg, err := newEmailerConfigFromReader(cf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cfg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type FakeEmailerConfig struct {
|
2016-06-28 12:04:55 +05:30
|
|
|
FromAddr string `json:"from"`
|
2015-08-18 05:57:27 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func (cfg FakeEmailerConfig) EmailerType() string {
|
|
|
|
return FakeEmailerType
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cfg FakeEmailerConfig) EmailerID() string {
|
2015-09-22 04:09:29 +05:30
|
|
|
return FakeEmailerType
|
2015-08-18 05:57:27 +05:30
|
|
|
}
|
|
|
|
|
2016-06-28 12:04:55 +05:30
|
|
|
func (cfg FakeEmailerConfig) Emailer(fromAddr string) (Emailer, error) {
|
|
|
|
from := cfg.FromAddr
|
|
|
|
if from == "" {
|
|
|
|
from = fromAddr
|
|
|
|
}
|
|
|
|
if from == "" {
|
|
|
|
// Since the emailer just prints to stdout, the actual value doesn't matter.
|
|
|
|
from = "noreply@example.com"
|
|
|
|
}
|
|
|
|
|
|
|
|
return FakeEmailer{from}, nil
|
2015-08-18 05:57:27 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// FakeEmailer is an Emailer that writes emails to stdout. Should only be used in development.
|
2016-06-28 12:04:55 +05:30
|
|
|
type FakeEmailer struct {
|
|
|
|
from string
|
|
|
|
}
|
2015-08-18 05:57:27 +05:30
|
|
|
|
2016-06-28 12:04:55 +05:30
|
|
|
func (f FakeEmailer) SendMail(subject, text, html string, to ...string) error {
|
|
|
|
fmt.Printf("From: %v\n", f.from)
|
2015-08-18 05:57:27 +05:30
|
|
|
fmt.Printf("Subject: %v\n", subject)
|
|
|
|
fmt.Printf("To: %v\n", strings.Join(to, ","))
|
|
|
|
fmt.Printf("Body(text): %v\n", text)
|
|
|
|
fmt.Printf("Body(html): %v\n", html)
|
|
|
|
return nil
|
|
|
|
}
|