119 lines
2.8 KiB
Go
119 lines
2.8 KiB
Go
package emailing
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"html/template"
|
|
|
|
"github.com/spf13/viper"
|
|
"github.com/wneessen/go-mail"
|
|
)
|
|
|
|
type Mailer struct {
|
|
TemplatesDir string
|
|
TemplatesConfig *viper.Viper
|
|
SMTPConfig
|
|
}
|
|
|
|
type SMTPConfig struct {
|
|
Host string
|
|
Port int
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
type Option func(*mail.Msg, []mail.Option) ([]mail.Option, error)
|
|
|
|
func NewMailer(templates_dir string, tplcfg *viper.Viper, smtpconfig *viper.Viper) (*Mailer, error) {
|
|
return &Mailer{
|
|
TemplatesDir: templates_dir,
|
|
TemplatesConfig: tplcfg,
|
|
SMTPConfig: SMTPConfig{
|
|
Host: smtpconfig.GetString("host"),
|
|
Port: smtpconfig.GetInt("port"),
|
|
Username: smtpconfig.GetString("username"),
|
|
Password: smtpconfig.GetString("password"),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *Mailer) Send(emailcfg string, to string, data any, opts ...Option) error {
|
|
cfg := m.TemplatesConfig.Sub(emailcfg)
|
|
|
|
files := cfg.GetStringSlice("files")
|
|
prefixed_files := []string{}
|
|
for _, f := range files {
|
|
prefixed_files = append(prefixed_files, m.TemplatesDir+f)
|
|
}
|
|
t := template.New("email").Funcs(
|
|
template.FuncMap{
|
|
"unescapeHTML": UnescapeHTML,
|
|
},
|
|
)
|
|
t = template.Must(t.ParseFiles(prefixed_files...))
|
|
buf := new(bytes.Buffer)
|
|
if err := t.ExecuteTemplate(buf, "main", data); err != nil {
|
|
return fmt.Errorf("failed execute mail template : %w", err)
|
|
}
|
|
body := buf.String()
|
|
|
|
message := mail.NewMsg()
|
|
if err := message.From(m.SMTPConfig.Username); err != nil {
|
|
return fmt.Errorf("failed to set From header : %w", err)
|
|
}
|
|
if err := message.To(to); err != nil {
|
|
return fmt.Errorf("failed to set To header : %w", err)
|
|
}
|
|
message.Subject(cfg.GetString("subject"))
|
|
message.SetBodyString(mail.TypeTextHTML, body)
|
|
|
|
dialOptions := []mail.Option{
|
|
//mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
|
|
mail.WithSMTPAuth(mail.SMTPAuthNoAuth),
|
|
mail.WithUsername(m.SMTPConfig.Username),
|
|
mail.WithPassword(m.SMTPConfig.Password),
|
|
}
|
|
|
|
fmt.Println(dialOptions)
|
|
|
|
for _, opt := range opts {
|
|
no, err := opt(message, dialOptions)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to set option : %w", err)
|
|
}
|
|
dialOptions = no
|
|
}
|
|
|
|
fmt.Println(dialOptions)
|
|
|
|
client, err := mail.NewClient(m.SMTPConfig.Host, dialOptions...)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create mail client : %w", err)
|
|
}
|
|
|
|
if err := client.DialAndSend(message); err != nil {
|
|
return fmt.Errorf("failed to send message : %w", err)
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func WithReplyTo(email string) Option {
|
|
return func(m *mail.Msg, opts []mail.Option) ([]mail.Option, error) {
|
|
return opts, m.ReplyTo(email)
|
|
}
|
|
}
|
|
|
|
func WithTLSOpportunistic() Option {
|
|
return func(m *mail.Msg, opts []mail.Option) ([]mail.Option, error) {
|
|
opts = append(opts, mail.WithTLSPolicy(mail.TLSOpportunistic))
|
|
return opts, nil
|
|
}
|
|
}
|
|
|
|
func UnescapeHTML(s string) template.HTML {
|
|
return template.HTML(s)
|
|
}
|
|
|