-
Notifications
You must be signed in to change notification settings - Fork 117
/
sender.go
108 lines (89 loc) · 2.43 KB
/
sender.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package email
import (
"fmt"
"net/mail"
"net/smtp"
"strconv"
"go.uber.org/zap"
)
type Sender interface {
Send(toEmail, toName, subject, body string) error
}
type SMTPOptions struct {
SMTPHost string
SMTPPort int
SMTPUsername string
SMTPPassword string
FromEmail string
FromName string
BCC string
}
type smtpSender struct {
opts *SMTPOptions
}
func NewSMTPSender(opts *SMTPOptions) (Sender, error) {
if opts.SMTPPassword == "" {
return nil, fmt.Errorf("SMTP server password is required")
}
_, err := mail.ParseAddress(opts.FromEmail)
if err != nil {
return nil, fmt.Errorf("invalid sender email address %q", opts.FromEmail)
}
if opts.BCC != "" {
_, err := mail.ParseAddress(opts.BCC)
if err != nil {
return nil, fmt.Errorf("invalid bcc email address %q", opts.BCC)
}
}
return &smtpSender{opts: opts}, nil
}
func (s *smtpSender) Send(toEmail, toName, subject, body string) error {
// Compose the email message
from := mail.Address{Name: s.opts.FromName, Address: s.opts.FromEmail}
to := mail.Address{Name: toName, Address: toEmail}
message := []byte("From: " + from.String() + "\r\n" +
"To: " + to.String() + "\r\n" +
"Subject: " + subject + "\r\n" +
"Content-Type: text/html; charset=utf-8\r\n" +
"\r\n" +
body + "\r\n",
)
// Build recipients list
recipients := []string{toEmail}
if s.opts.BCC != "" {
recipients = append(recipients, s.opts.BCC)
}
// Connect to the SMTP server
auth := smtp.PlainAuth("", s.opts.SMTPUsername, s.opts.SMTPPassword, s.opts.SMTPHost)
err := smtp.SendMail(s.opts.SMTPHost+":"+strconv.Itoa(s.opts.SMTPPort), auth, from.Address, recipients, message)
if err != nil {
return err
}
return nil
}
type consoleSender struct {
logger *zap.Logger
fromEmail string
fromName string
}
func NewConsoleSender(logger *zap.Logger, fromEmail, fromName string) (Sender, error) {
return &consoleSender{logger: logger, fromEmail: fromEmail, fromName: fromName}, nil
}
func (s *consoleSender) Send(toEmail, toName, subject, body string) error {
s.logger.Info("email sent",
zap.String("from_email", s.fromEmail),
zap.String("from_name", s.fromName),
zap.String("to_email", toEmail),
zap.String("to_name", toName),
zap.String("subject", subject),
zap.String("body", body),
)
return nil
}
type noopSender struct{}
func NewNoopSender() Sender {
return &noopSender{}
}
func (s *noopSender) Send(toEmail, toName, subject, body string) error {
return nil
}