gte/pkg/msend/smtp.go

128 lines
2.7 KiB
Go
Raw Normal View History

2021-05-13 08:15:14 +02:00
package msend
import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/mail"
"net/smtp"
)
var (
ErrSMTPInvalidConfig = errors.New("invalid smtp configuration")
ErrSMTPConnectionFailed = errors.New("connection to smtp server failed")
ErrSendMessageFailed = errors.New("could not send message")
)
type SSLSMTPConfig struct {
URL string
Username string
Password string
From string
To string
}
func (ssc *SSLSMTPConfig) Valid() bool {
if _, _, err := net.SplitHostPort(ssc.URL); err != nil {
return false
}
return ssc.Username != "" && ssc.Password != "" && ssc.To != "" && ssc.From != ""
}
type SSLSMTP struct {
config *SSLSMTPConfig
client *smtp.Client
connected bool
}
func NewSSLSMTP(config *SSLSMTPConfig) *SSLSMTP {
return &SSLSMTP{
config: config,
}
}
func (s *SSLSMTP) Connect() error {
if !s.config.Valid() {
return ErrSMTPInvalidConfig
}
host, _, _ := net.SplitHostPort(s.config.URL)
auth := smtp.PlainAuth("", s.config.Username, s.config.Password, host)
conn, err := tls.Dial("tcp", s.config.URL, &tls.Config{ServerName: host})
if err != nil {
return fmt.Errorf("%w: %v", ErrSMTPConnectionFailed, err)
}
client, err := smtp.NewClient(conn, host)
if err != nil {
return fmt.Errorf("%w: %v", ErrSMTPConnectionFailed, err)
}
if err := client.Auth(auth); err != nil {
return fmt.Errorf("%w: %v", ErrSMTPConnectionFailed, err)
}
s.client = client
s.connected = true
return nil
}
func (s *SSLSMTP) Close() error {
if !s.connected {
return nil
}
if err := s.client.Quit(); err != nil {
return fmt.Errorf("%w: %v", ErrSMTPConnectionFailed, err)
}
s.connected = false
return nil
}
func (s *SSLSMTP) Send(msg *Message) error {
if err := s.Connect(); err != nil {
return err
}
defer s.Close()
from := mail.Address{
Name: "gte",
Address: s.config.From,
}
to := mail.Address{
Name: "todo",
Address: s.config.To,
}
headers := make(map[string]string)
headers["From"] = from.String()
headers["To"] = to.String()
headers["Subject"] = msg.Subject
message := ""
for k, v := range headers {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += fmt.Sprintf("\r\n%s", msg.Body)
if err := s.client.Mail(s.config.From); err != nil {
return fmt.Errorf("%w: %v", ErrSendMessageFailed, err)
}
if err := s.client.Rcpt(s.config.To); err != nil {
return fmt.Errorf("%w: %v", ErrSendMessageFailed, err)
}
wc, err := s.client.Data()
if err != nil {
return fmt.Errorf("%w: %v", ErrSendMessageFailed, err)
}
if _, err := wc.Write([]byte(message)); err != nil {
return fmt.Errorf("%w: %v", ErrSendMessageFailed, err)
}
if err := wc.Close(); err != nil {
return fmt.Errorf("%w: %v", ErrSendMessageFailed, err)
}
return nil
}