diff --git a/Makefile b/Makefile index 8eaa794ee..bb5840b22 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,10 @@ test.rbac: $(GOTEST) $(GOTEST) -covermode count -coverprofile .cover.out -v ./internal/rbac/... $(GO) tool cover -func=.cover.out | grep --color "^\|[^0-9]0.0%" +test.mail: $(GOTEST) + $(GOTEST) -covermode count -coverprofile .cover.out -v ./internal/mail/... + $(GO) tool cover -func=.cover.out | grep --color "^\|[^0-9]0.0%" + test.rbac.resources: $(GOTEST) $(GOTEST) -run Resources -covermode count -coverprofile .cover.out -v ./internal/rbac/... $(GO) tool cover -func=.cover.out | grep --color "^\|[^0-9]0.0%" diff --git a/internal/config/smtp.go b/internal/config/smtp.go new file mode 100644 index 000000000..039972c9f --- /dev/null +++ b/internal/config/smtp.go @@ -0,0 +1,54 @@ +package config + +import ( + "strconv" + "strings" + + "github.com/namsral/flag" + "github.com/pkg/errors" +) + +type ( + SMTP struct { + Host string + Port int + User string + Pass string + + From string + } +) + +var smtp *SMTP + +func (c *SMTP) Validate() error { + if c.Host == "" { + return errors.New("No hostname provided for SMTP") + } + // split host:port from host into .Host and .Port + if strings.Contains(c.Host, ":") { + parts := strings.SplitN(c.Host, ":", 2) + c.Port, _ = strconv.Atoi(parts[1]) + c.Host = parts[0] + } + if c.Port == 0 { + return errors.New("No port provided for SMTP") + } + if c.From == "" { + return errors.New("Sender for SMTP is not set") + } + return nil +} + +func (*SMTP) Init(prefix ...string) *SMTP { + if smtp != nil { + return smtp + } + smtp = new(SMTP) + flag.StringVar(&smtp.Host, "smtp-host", "", "SMTP hostname (may be host:port)") + flag.IntVar(&smtp.Port, "smtp-port", 0, "SMTP port number") + flag.StringVar(&smtp.User, "smtp-user", "", "SMTP server username") + flag.StringVar(&smtp.Pass, "smtp-pass", "", "SMTP server password") + flag.StringVar(&smtp.From, "smtp-from", "", "SMTP sender header") + return smtp +} diff --git a/internal/mail/flags.go b/internal/mail/flags.go new file mode 100644 index 000000000..ec460015a --- /dev/null +++ b/internal/mail/flags.go @@ -0,0 +1,17 @@ +package mail + +import ( + "fmt" + + "github.com/crusttech/crust/internal/config" +) + +var flags *config.SMTP + +func Flags(prefix ...string) { + flags = new(config.SMTP).Init(prefix...) +} + +func Debug() { + fmt.Printf("Debug SMTP flags: %#v", *flags) +} diff --git a/internal/mail/mail.go b/internal/mail/mail.go new file mode 100644 index 000000000..88605defd --- /dev/null +++ b/internal/mail/mail.go @@ -0,0 +1,22 @@ +package mail + +import ( + "github.com/pkg/errors" + gomail "gopkg.in/mail.v2" +) + +func New() *gomail.Message { + message := gomail.NewMessage() + message.SetHeader("From", flags.From) + return message +} + +func Send(message *gomail.Message) error { + dialer := gomail.NewDialer( + flags.Host, + flags.Port, + flags.User, + flags.Pass, + ) + return errors.WithStack(dialer.DialAndSend(message)) +} diff --git a/internal/mail/mail_test.go b/internal/mail/mail_test.go new file mode 100644 index 000000000..ff85b81ac --- /dev/null +++ b/internal/mail/mail_test.go @@ -0,0 +1,28 @@ +package mail + +import ( + "testing" + + "github.com/joho/godotenv" + "github.com/namsral/flag" +) + +func TestMailSend(t *testing.T) { + if !testing.Short() { + godotenv.Load("../../.env") + + Flags() + flag.Parse() + if err := flags.Validate(); err != nil { + t.Fatalf("Missing SMTP flags: %+v", err) + } + + message := New() + message.SetHeader("To", "black@scene-si.org") + message.SetHeader("Subject", "Hello from Crust tests!") + message.SetBody("text/html", "Lorem ipsum dolor sit amet!") + if err := Send(message); err != nil { + t.Fatalf("E-mail failed to send: %+v", err) + } + } +}