prompt 4
This commit is contained in:
102
internal/mailer/smtp.go
Normal file
102
internal/mailer/smtp.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package mailer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"trustcontact/internal/config"
|
||||
)
|
||||
|
||||
type SMTPMailer struct {
|
||||
host string
|
||||
port int
|
||||
username string
|
||||
password string
|
||||
from string
|
||||
fromName string
|
||||
}
|
||||
|
||||
func NewSMTPMailer(cfg *config.Config) (*SMTPMailer, error) {
|
||||
if strings.TrimSpace(cfg.SMTP.Host) == "" {
|
||||
return nil, fmt.Errorf("smtp host is required")
|
||||
}
|
||||
if cfg.SMTP.Port <= 0 {
|
||||
return nil, fmt.Errorf("smtp port must be > 0")
|
||||
}
|
||||
if strings.TrimSpace(cfg.SMTP.From) == "" {
|
||||
return nil, fmt.Errorf("smtp from is required")
|
||||
}
|
||||
|
||||
return &SMTPMailer{
|
||||
host: cfg.SMTP.Host,
|
||||
port: cfg.SMTP.Port,
|
||||
username: cfg.SMTP.Username,
|
||||
password: cfg.SMTP.Password,
|
||||
from: cfg.SMTP.From,
|
||||
fromName: cfg.SMTP.FromName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *SMTPMailer) Send(ctx context.Context, to, subject, htmlBody, textBody string) error {
|
||||
if ctx != nil {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(m.host, strconv.Itoa(m.port))
|
||||
msg := m.buildMessage(to, subject, htmlBody, textBody)
|
||||
|
||||
var auth smtp.Auth
|
||||
if m.username != "" {
|
||||
auth = smtp.PlainAuth("", m.username, m.password, m.host)
|
||||
}
|
||||
|
||||
if err := smtp.SendMail(addr, auth, m.from, []string{to}, []byte(msg)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx != nil {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SMTPMailer) buildMessage(to, subject, htmlBody, textBody string) string {
|
||||
boundary := fmt.Sprintf("mixed-%d", time.Now().UTC().UnixNano())
|
||||
fromAddr := (&mail.Address{Name: m.fromName, Address: m.from}).String()
|
||||
toAddr := (&mail.Address{Address: to}).String()
|
||||
|
||||
headers := []string{
|
||||
fmt.Sprintf("From: %s", fromAddr),
|
||||
fmt.Sprintf("To: %s", toAddr),
|
||||
fmt.Sprintf("Subject: %s", subject),
|
||||
"MIME-Version: 1.0",
|
||||
fmt.Sprintf("Content-Type: multipart/alternative; boundary=%q", boundary),
|
||||
"",
|
||||
}
|
||||
|
||||
parts := []string{
|
||||
fmt.Sprintf("--%s", boundary),
|
||||
"Content-Type: text/plain; charset=UTF-8",
|
||||
"",
|
||||
textBody,
|
||||
fmt.Sprintf("--%s", boundary),
|
||||
"Content-Type: text/html; charset=UTF-8",
|
||||
"",
|
||||
htmlBody,
|
||||
fmt.Sprintf("--%s--", boundary),
|
||||
"",
|
||||
}
|
||||
|
||||
return strings.Join(append(headers, parts...), "\r\n")
|
||||
}
|
||||
Reference in New Issue
Block a user