github.com/seeker-insurance/kit@v0.0.13/mailman/mailman.go (about) 1 package mailman 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "path" 8 "strings" 9 "text/template" 10 11 "github.com/seeker-insurance/kit/assets" 12 "github.com/spf13/viper" 13 ) 14 15 type Address struct { 16 Name string 17 Email string 18 } 19 20 type Config struct { 21 From *Address 22 Domain string 23 } 24 25 type Mailer interface { 26 Config() *Config 27 Send(to *Address, content *Content, vars *MergeVars) error 28 } 29 30 type Template struct { 31 Subject *template.Template 32 HtmlBody *template.Template 33 PlainBody *template.Template 34 } 35 36 type Content struct { 37 Subject *bytes.Buffer 38 HtmlBody *bytes.Buffer 39 PlainBody *bytes.Buffer 40 } 41 42 type MergeVars struct { 43 SubjectVars map[string]string 44 BodyVars map[string]string 45 } 46 47 type mergeVars interface{} 48 49 var ( 50 TemplateDir string 51 Templates map[string]*Template 52 mailer Mailer 53 ) 54 55 func newTemplate(s string) (*template.Template, error) { 56 return template.New("").Parse(s) 57 } 58 59 func setDefaultTemplateDir() { 60 dir := path.Join("data", "bin", "mail") 61 62 if _, err := assets.Dir(dir); err == nil { 63 TemplateDir = dir 64 } 65 } 66 67 func Configure(m Mailer) { 68 setDefaultTemplateDir() 69 70 Templates = make(map[string]*Template) 71 mailer = m 72 } 73 74 func AddTemplate(key string, subject string, htmlBody string, plainBody string) error { 75 var s, h, p *template.Template 76 var err error 77 if s, err = newTemplate(subject); err != nil { 78 return err 79 } 80 if h, err = newTemplate(htmlBody); err != nil { 81 return err 82 } 83 if p, err = newTemplate(plainBody); err != nil { 84 return err 85 } 86 87 Templates[key] = &Template{s, h, p} 88 return nil 89 } 90 91 func readEmailTemplates(key string) ([][]byte, error) { 92 templates := make([][]byte, 3) 93 var err error 94 95 for i, part := range []string{"subject", "html", "plain"} { 96 fileName := fmt.Sprintf("%s_%s.tmpl", key, part) 97 p := path.Join(TemplateDir, fileName) 98 99 if templates[i], err = assets.Get(p); err != nil { 100 return templates, err 101 } 102 } 103 104 return templates, nil 105 } 106 107 func RegisterTemplate(keys ...string) error { 108 if len(TemplateDir) == 0 { 109 return errors.New("TemplateDir not set") 110 } 111 for _, key := range keys { 112 parts, err := readEmailTemplates(key) 113 if err != nil { 114 return err 115 } 116 if err := AddTemplate(key, string(parts[0]), string(parts[1]), string(parts[2])); err != nil { 117 return err 118 } 119 } 120 return nil 121 } 122 123 func Send(to *Address, templateKey string, vars *MergeVars) error { 124 substr := viper.GetString("email_whitelist_pattern") 125 if substr != "" && !strings.Contains(to.Email, substr) { 126 return nil 127 } 128 129 if mailer == nil { 130 return errors.New("Mail has not been configured") 131 } 132 133 template := Templates[templateKey] 134 if template == nil { 135 return fmt.Errorf("Template not found for key [%s]", templateKey) 136 } 137 138 content := &Content{ 139 new(bytes.Buffer), 140 new(bytes.Buffer), 141 new(bytes.Buffer), 142 } 143 144 if err := template.Subject.Execute(content.Subject, vars.SubjectVars); err != nil { 145 return err 146 } 147 if err := template.HtmlBody.Execute(content.HtmlBody, vars.BodyVars); err != nil { 148 return err 149 } 150 if err := template.PlainBody.Execute(content.PlainBody, vars.BodyVars); err != nil { 151 return err 152 } 153 154 return mailer.Send(to, content, vars) 155 }