126 lines
3.4 KiB
Go
126 lines
3.4 KiB
Go
package service
|
||
|
||
import (
|
||
"bytes"
|
||
"embed"
|
||
"encoding/base64"
|
||
"fmt"
|
||
"html/template"
|
||
"log"
|
||
"math/rand"
|
||
"time"
|
||
|
||
"gopkg.in/gomail.v2"
|
||
)
|
||
|
||
type MailService interface {
|
||
SendEmail(to, subject, body string) error
|
||
SendTemplateEmail(to, subject string, templateName string, data interface{}) error
|
||
SendConfirmationEmail(to, token string) error
|
||
SendPasswordResetEmail(to, token string) error
|
||
SendRecoveryEmail(value string, str string, address string, agent string) interface{}
|
||
SendSessionConfirmation(email string, token string, address string, agent string) error
|
||
}
|
||
|
||
type mailService struct {
|
||
from string
|
||
smtpHost string
|
||
smtpPort int
|
||
smtpUser string
|
||
smtpPass string
|
||
templates *template.Template
|
||
appURL string
|
||
}
|
||
|
||
func (s *mailService) SendSessionConfirmation(email string, token string, address string, agent string) error {
|
||
//TODO implement me
|
||
panic("implement me")
|
||
}
|
||
|
||
func (s *mailService) SendRecoveryEmail(value string, str string, address string, agent string) interface{} {
|
||
//TODO implement me
|
||
panic("implement me")
|
||
}
|
||
|
||
//go:embed templates/*
|
||
var templateFS embed.FS
|
||
|
||
func NewMailService(from, smtpHost string, smtpPort int, smtpUser, smtpPass, appURL string) (MailService, error) {
|
||
// Загружаем шаблоны писем
|
||
templates, err := template.ParseFS(templateFS, "templates/*.html")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to parse email templates: %w", err)
|
||
}
|
||
|
||
return &mailService{
|
||
from: from,
|
||
smtpHost: smtpHost,
|
||
smtpPort: smtpPort,
|
||
smtpUser: smtpUser,
|
||
smtpPass: smtpPass,
|
||
templates: templates,
|
||
appURL: appURL,
|
||
}, nil
|
||
}
|
||
|
||
func (s *mailService) SendEmail(to, subject, body string) error {
|
||
mail := gomail.NewMessage()
|
||
mail.SetHeader("From", s.from)
|
||
mail.SetHeader("To", to)
|
||
mail.SetHeader("Subject", encodeSubject(subject))
|
||
mail.SetHeader("Message-ID", fmt.Sprintf(generateMessageID()))
|
||
mail.SetBody("text/html; charset=UTF-8", body)
|
||
mail.SetHeader("Contens-Transfer-Encoding", "base64")
|
||
|
||
dialer := gomail.NewDialer(s.smtpHost, s.smtpPort, s.smtpUser, s.smtpPass)
|
||
log.Printf("SendEmail dialer: %v", dialer)
|
||
return dialer.DialAndSend(mail)
|
||
}
|
||
func encodeSubject(subject string) string {
|
||
return fmt.Sprintf("=?UTF-8?B?%s?=", base64.StdEncoding.EncodeToString([]byte(subject)))
|
||
}
|
||
func generateMessageID() string {
|
||
b := make([]byte, 16)
|
||
rand.Read(b)
|
||
return fmt.Sprintf("<%x.%x@tailly.ru>", time.Now().UnixNano(), b)
|
||
}
|
||
|
||
func (s *mailService) SendTemplateEmail(to, subject string, templateName string, data interface{}) error {
|
||
var body bytes.Buffer
|
||
if err := s.templates.ExecuteTemplate(&body, templateName+".html", data); err != nil {
|
||
return fmt.Errorf("failed to execute template: %w", err)
|
||
}
|
||
log.Printf("SendTemplateEmail : %v", to, subject, body.String())
|
||
return s.SendEmail(to, subject, body.String())
|
||
}
|
||
|
||
func (s *mailService) SendConfirmationEmail(to, token string) error {
|
||
data := struct {
|
||
Email string
|
||
Token string
|
||
Year int
|
||
AppURL string
|
||
}{
|
||
Email: to,
|
||
Token: token,
|
||
Year: time.Now().Year(),
|
||
AppURL: s.appURL,
|
||
}
|
||
log.Printf("SendConfirmationEmail data: %v", data)
|
||
return s.SendTemplateEmail(to, "Подтверждение email", "confirmation", data)
|
||
}
|
||
|
||
func (s *mailService) SendPasswordResetEmail(to, token string) error {
|
||
data := struct {
|
||
Email string
|
||
Token string
|
||
Year int
|
||
}{
|
||
Email: to,
|
||
Token: token,
|
||
Year: time.Now().Year(),
|
||
}
|
||
|
||
return s.SendTemplateEmail(to, "Сброс пароля", "password_reset", data)
|
||
}
|