package common_email import ( "github.com/wneessen/go-mail" "encoding/json" "context" "log" "github.com/redis/go-redis/v9" "github.com/yuin/goldmark" "MY/webapp/config" "path/filepath" "text/template" "os" "strings" ) func NewSender(ctx context.Context) (Sender){ client := redis.NewClient(&redis.Options{ Addr: config.Settings.Redis.HostPort, Password: config.Settings.Redis.Password, DB: config.Settings.Redis.DB, }) return Sender{client, ctx} } func NewRouter(ctx context.Context) (Router, error) { var router Router var err error router.ctx = ctx router.redis_client = redis.NewClient(&redis.Options{ Addr: config.Settings.Redis.HostPort, Password: config.Settings.Redis.Password, DB: config.Settings.Redis.DB, }) router.smtp_client, err = mail.NewClient(config.Settings.Email.Host, mail.WithPort(config.Settings.Email.Port), mail.WithTLSPolicy(mail.NoTLS)) return router, err } func (router *Router) Close() { router.redis_client.Close() router.smtp_client.Close() } func (sender *Sender) Close() { sender.redis_client.Close() } func (router *Router) Render(tmpl_path string, data any) (string, string, error) { tmpl_path = filepath.Join(config.Settings.Email.Templates, tmpl_path) // load the markdown file md_file, err := os.ReadFile(tmpl_path) if err != nil { return "", "", err } // template it tmpl, err := template.New(tmpl_path).Parse(string(md_file)) if err != nil { return "", "", err } out := new(strings.Builder) err = tmpl.Execute(out, data) if err != nil { return "", "", err } text_out := out.String() // convert to html out.Reset() err = goldmark.Convert([]byte(text_out), out) if err != nil { return "", "", err } html_out := out.String() // return the template .md as plain text and .html as html return string(text_out), string(html_out), nil } func (router *Router) DeliverEmail(msg EmailMessage) error { email_msg := mail.NewMsg() err := email_msg.From(msg.From) if err != nil { return err } err = email_msg.To(msg.To) if err != nil { return err } email_msg.Subject(msg.Subject) if config.Settings.Email.XMailer != "" { email_msg.SetGenHeader(mail.HeaderXMailer, config.Settings.Email.XMailer) } if config.Settings.Email.UserAgent != "" { email_msg.SetGenHeader(mail.HeaderUserAgent, config.Settings.Email.UserAgent) } text, html, err := router.Render(msg.Template, nil) if err != nil { return err } email_msg.SetBodyString(mail.TypeTextHTML, html) email_msg.AddAlternativeString(mail.TypeTextPlain, text) err = router.smtp_client.DialAndSendWithContext(router.ctx, email_msg) if err != nil { return err } return nil } func (router *Router) ReceiveEmail() (EmailMessage, error) { var msg EmailMessage result, err := router.redis_client.BRPop( router.ctx, 0, config.Settings.Email.RedisQueue).Result() if err != nil { return msg, err } // NOTE: 0=queue name, 1=message err = json.Unmarshal([]byte(result[1]), &msg) if err != nil { return msg, err } return msg, nil } func (router *Router) HandleEmailRequest() error { msg, err := router.ReceiveEmail() if err != nil { return err } err = router.DeliverEmail(msg) if err != nil { return err } return nil } func (sender *Sender) QueueEmail(msg EmailMessage) error { msg_json, err := json.Marshal(msg) if err != nil { return err } _, err = sender.redis_client.LPush( sender.ctx, config.Settings.Email.RedisQueue, string(msg_json)).Result() if err != nil { return err } return nil } func OneShotSend(msg EmailMessage) { ctx := context.Background() sender := NewSender(ctx) defer sender.Close() err := sender.QueueEmail(msg) if err != nil { log.Print(err) } }