package mailclient import ( "bytes" _ "embed" "fmt" "github.com/gofiber/fiber/v2" "github.com/themakers/hlog" "mime/multipart" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model" "strings" "text/template" ) type ClientDeps struct { Host string Port string Sender string Auth *PlainAuth ApiKey string FiberClient *fiber.Client Logger hlog.Logger } type Client struct { deps ClientDeps } type PlainAuth struct { Identity string Username string Password string } type EmailTemplateData struct { QuizConfig model.ResultInfo AnswerContent model.ResultContent AllAnswers []model.ResultAnswer QuestionsMap map[uint64]string AnswerTime string } func NewClient(deps ClientDeps) *Client { if deps.FiberClient == nil { deps.FiberClient = fiber.AcquireClient() } return &Client{ deps: deps, } } func (c *Client) SendMailWithAttachment(recipient, subject string, emailTemplate string, data EmailTemplateData, attachments []Attachment) error { text, err := generateTextFromTemplate(data, emailTemplate) if err != nil { c.deps.Logger.Module("Error generate text from template") return err } msg := &Message{ From: c.deps.Sender, To: []string{recipient}, Subject: subject, Body: text, Attachments: attachments, } return c.Send(msg) } func (c *Client) Send(msg *Message) error { url := "https://api.smtp.bz/v1/smtp/send" form := new(bytes.Buffer) writer := multipart.NewWriter(form) defer writer.Close() fields := map[string]string{ "from": msg.From, "to": strings.Join(msg.To, ","), "subject": msg.Subject, "html": msg.Body, } for key, value := range fields { if err := writer.WriteField(key, value); err != nil { c.deps.Logger.Module("Error creating form fields") return err } } for _, attachment := range msg.Attachments { part, err := writer.CreateFormFile("attachments", attachment.Name) if err != nil { c.deps.Logger.Module("Error creating form file for attachment") return err } _, err = part.Write(attachment.Data) if err != nil { c.deps.Logger.Module("Error writing attachment content") return err } } if err := writer.Close(); err != nil { c.deps.Logger.Module("Error closing writer for multipart form") return err } agent := c.deps.FiberClient.Post(url).Body(form.Bytes()).ContentType(writer.FormDataContentType()) if c.deps.ApiKey != "" { agent.Set("Authorization", c.deps.ApiKey) } statusCode, body, errs := agent.Bytes() if errs != nil { c.deps.Logger.Module("Error sending request") return errs[0] } if statusCode != fiber.StatusOK { return fmt.Errorf("SMTP service returned error: %d, Response body: %s", statusCode, body) } return nil } func generateTextFromTemplate(data EmailTemplateData, tpl string) (string, error) { t, err := template.New("email").Parse(tpl) if err != nil { return "", fmt.Errorf("error parsing template: %w", err) } var text bytes.Buffer if err := t.Execute(&text, EmailTemplateData{ QuizConfig: data.QuizConfig, AnswerContent: data.AnswerContent, AllAnswers: data.AllAnswers, QuestionsMap: data.QuestionsMap, AnswerTime: data.AnswerTime, }); err != nil { return "", fmt.Errorf("error executing template: %w", err) } return text.String(), nil }