Dima 6 months ago
parent
commit
9c1adbc48f
3 changed files with 143 additions and 0 deletions
  1. 37 0
      smtp/auth.go
  2. 52 0
      smtp/smtp.go
  3. 54 0
      smtp/smtp_config.go

+ 37 - 0
smtp/auth.go

@@ -0,0 +1,37 @@
+package smtp
+
+import (
+	"fmt"
+	"net/smtp"
+	"strings"
+)
+
+type auth struct {
+	username string
+	password string
+}
+
+func (a auth) Start(_ *smtp.ServerInfo) (string, []byte, error) {
+	return "LOGIN", nil, nil
+}
+
+func (a auth) Next(req []byte, more bool) ([]byte, error) {
+	command := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(string(req)), ":"))
+
+	if more {
+		if command == "username" {
+			return []byte(fmt.Sprintf("%s", a.username)), nil
+		}
+		if command == "password" {
+			return []byte(fmt.Sprintf("%s", a.password)), nil
+		}
+
+		return nil, fmt.Errorf("unexpected server challenge: %s", command)
+	}
+
+	return nil, nil
+}
+
+func getAuth(username, password string) smtp.Auth {
+	return &auth{username, password}
+}

+ 52 - 0
smtp/smtp.go

@@ -0,0 +1,52 @@
+package smtp
+
+import (
+	"errors"
+	"fmt"
+	"net/smtp"
+)
+
+type SMTP struct {
+	config Config
+}
+
+func NewSMTP(c Config) (*SMTP, error) {
+	if len(c.username) == 0 {
+		return nil, errors.New("empty username")
+	}
+
+	if len(c.password) == 0 {
+		return nil, errors.New("empty password")
+	}
+
+	if len(c.host) == 0 {
+		c.host = defaultHost
+	}
+
+	if c.port == 0 {
+		c.port = defaultPort
+	}
+
+	return &SMTP{config: c}, nil
+}
+
+func (s SMTP) Send(recipient string, subject string, content string, html bool) error {
+	contentType := "text/plain"
+	if html {
+		contentType = "text/html"
+	}
+
+	msg := []byte("To: " + recipient + "\r\n" +
+		"From: " + s.config.username + "\r\n" +
+		"Subject: " + subject + "\r\n" +
+		"Content-Type: " + contentType + "; charset=\"UTF-8\"" + "\n\r\n" +
+		content + "\r\n")
+
+	return smtp.SendMail(
+		fmt.Sprintf("%s:%d", s.config.host, s.config.port),
+		getAuth(s.config.username, s.config.password),
+		s.config.username,
+		[]string{recipient},
+		msg,
+	)
+}

+ 54 - 0
smtp/smtp_config.go

@@ -0,0 +1,54 @@
+package smtp
+
+const (
+	defaultHost = "localhost"
+	defaultPort = 587
+)
+
+type Config struct {
+	host     string
+	port     uint16
+	username string
+	password string
+}
+
+type ConfigOption func(*Config)
+
+type ConfigOptions []ConfigOption
+
+func (s *ConfigOptions) Add(option ConfigOption) {
+	*s = append(*s, option)
+}
+
+func NewConfig(opts ...ConfigOption) Config {
+	c := &Config{}
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	return *c
+}
+
+func WithUsername(username string) ConfigOption {
+	return func(s *Config) {
+		s.username = username
+	}
+}
+
+func WithPassword(password string) ConfigOption {
+	return func(s *Config) {
+		s.password = password
+	}
+}
+
+func WithHost(host string) ConfigOption {
+	return func(s *Config) {
+		s.host = host
+	}
+}
+
+func WithPort(port uint16) ConfigOption {
+	return func(s *Config) {
+		s.port = port
+	}
+}