feat: implemented smtp service;
feat: implemented registration emails; fix: config variables for password length used the same env variable; refactor: all available config variables added to docker-compose.yml
This commit is contained in:
@@ -17,10 +17,21 @@
|
||||
|
||||
package services
|
||||
|
||||
import "go.uber.org/zap"
|
||||
import (
|
||||
"crypto/tls"
|
||||
"easywish/config"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
errs "easywish/internal/errors"
|
||||
)
|
||||
|
||||
type SmtpService interface {
|
||||
SendEmail(to string, content string)
|
||||
SendEmail(to string, subject, body string) error
|
||||
}
|
||||
|
||||
type smtpServiceImpl struct {
|
||||
@@ -31,7 +42,102 @@ func NewSmtpService(_log *zap.Logger) SmtpService {
|
||||
return &smtpServiceImpl{log: _log}
|
||||
}
|
||||
|
||||
func (s *smtpServiceImpl) SendEmail(to string, content string) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
func (s *smtpServiceImpl) SendEmail(to string, subject, body string) error {
|
||||
cfg := config.GetConfig()
|
||||
|
||||
if !cfg.SmtpEnabled {
|
||||
s.log.Error("Attempted to send an email with SMTP disabled in the config")
|
||||
return errs.ErrSmtpDisabled
|
||||
}
|
||||
|
||||
if cfg.SmtpServer == "" || cfg.SmtpPort == 0 || cfg.SmtpFrom == "" {
|
||||
s.log.Error("SMTP service settings or the SMTP From paramater are not set")
|
||||
return errs.ErrSmtpMissingConfiguration
|
||||
}
|
||||
|
||||
toSlice := []string{to}
|
||||
|
||||
headers := map[string]string{
|
||||
"From": cfg.SmtpFrom,
|
||||
"To": strings.Join(toSlice, ", "),
|
||||
"Subject": subject,
|
||||
"MIME-Version": "1.0",
|
||||
"Content-Type": "text/html; charset=UTF-8",
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
for k, v := range headers {
|
||||
sb.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
|
||||
}
|
||||
sb.WriteString("\r\n" + body)
|
||||
message := []byte(sb.String())
|
||||
|
||||
hostPort := fmt.Sprintf("%s:%d", cfg.SmtpServer, cfg.SmtpPort)
|
||||
var conn net.Conn
|
||||
var err error
|
||||
|
||||
if cfg.SmtpUseSSL {
|
||||
tlsConfig := &tls.Config{ServerName: cfg.SmtpServer}
|
||||
conn, err = tls.Dial("tcp", hostPort, tlsConfig)
|
||||
} else {
|
||||
timeout := time.Duration(cfg.SmtpTimeout) * time.Second
|
||||
conn, err = net.DialTimeout("tcp", hostPort, timeout)
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Error("SMTP connection failure", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client, err := smtp.NewClient(conn, cfg.SmtpServer)
|
||||
if err != nil {
|
||||
s.log.Error("SMTP client creation failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if !cfg.SmtpUseSSL && cfg.SmtpUseTLS {
|
||||
tlsConfig := &tls.Config{ServerName: cfg.SmtpServer}
|
||||
if err = client.StartTLS(tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate if credentials exist
|
||||
if cfg.SmtpUser != "" && cfg.SmtpPassword != "" {
|
||||
auth := smtp.PlainAuth("", cfg.SmtpUser, cfg.SmtpPassword, cfg.SmtpServer)
|
||||
if err = client.Auth(auth); err != nil {
|
||||
s.log.Error("SMTP authentication failure", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = client.Mail(cfg.SmtpFrom); err != nil {
|
||||
s.log.Error("SMTP sender set failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
for _, recipient := range to {
|
||||
if err = client.Rcpt(string(recipient)); err != nil {
|
||||
s.log.Error("SMTP recipient set failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Send email body
|
||||
w, err := client.Data()
|
||||
if err != nil {
|
||||
s.log.Error("SMTP data command failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if _, err = w.Write(message); err != nil {
|
||||
s.log.Error("SMTP message write failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if err = w.Close(); err != nil {
|
||||
s.log.Error("SMTP message close failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
return client.Quit()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user