server and web app
This commit is contained in:
67
apps/server/internal/email/sender.go
Normal file
67
apps/server/internal/email/sender.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/smtp"
|
||||
|
||||
"github.com/tim/cairnquire/apps/server/internal/config"
|
||||
)
|
||||
|
||||
type Sender interface {
|
||||
Send(ctx context.Context, to []string, subject, body string) error
|
||||
}
|
||||
|
||||
type SMTPConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
From string
|
||||
}
|
||||
|
||||
type SMTPSender struct {
|
||||
cfg SMTPConfig
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewSMTPSender(cfg config.EmailConfig, logger *slog.Logger) *SMTPSender {
|
||||
return &SMTPSender{
|
||||
cfg: SMTPConfig{
|
||||
Host: cfg.SMTPHost,
|
||||
Port: cfg.SMTPPort,
|
||||
From: cfg.From,
|
||||
},
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SMTPSender) Send(ctx context.Context, to []string, subject, body string) error {
|
||||
if s.cfg.Host == "" {
|
||||
return fmt.Errorf("email host not configured")
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", s.cfg.Host, s.cfg.Port)
|
||||
msg := []byte(fmt.Sprintf("To: %s\r\nSubject: %s\r\n\r\n%s\r\n", to[0], subject, body))
|
||||
|
||||
s.logger.Info("sending email", "to", to, "subject", subject, "addr", addr)
|
||||
|
||||
// Use SMTP without auth for local testing (Mailpit/MailHog)
|
||||
var auth smtp.Auth
|
||||
err := smtp.SendMail(addr, auth, s.cfg.From, to, msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("send email: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NoOpSender struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewNoOpSender(logger *slog.Logger) *NoOpSender {
|
||||
return &NoOpSender{logger: logger}
|
||||
}
|
||||
|
||||
func (n *NoOpSender) Send(ctx context.Context, to []string, subject, body string) error {
|
||||
n.logger.Info("email noop", "to", to, "subject", subject, "body_len", len(body))
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user