package webutility // TODO(markO): test test test test test (and open source?) import ( "crypto/tls" "errors" "fmt" "net/smtp" "strings" ) type Email struct { To []string From string Subject string Body string config *EmailConfig } func NewEmail() *Email { return &Email{ To: nil, From: "", Subject: "", Body: "", config: nil, } } func (e *Email) Config(cfg *EmailConfig) { e.config = cfg } func (e *Email) SetFrom(from string) { e.From = from } func (e *Email) SetTo(to []string) { e.To = to } func (e *Email) SetSubject(sub string) { e.Subject = sub } func (e *Email) SetBody(body string) { e.Body = body } func (e *Email) String() string { var str strings.Builder str.WriteString("From:" + e.From + "\r\n") str.WriteString("To:") for i, _ := range e.To { if i > 0 { str.WriteString(",") } str.WriteString(e.To[i]) } str.WriteString("\r\n") str.WriteString("Subject:" + e.Subject + "\r\n") // body str.WriteString("\r\n" + e.Body + "\r\n") return str.String() } func (e *Email) Bytes() []byte { return []byte(e.String()) } func (email *Email) Send() error { if email.config == nil { return errors.New("email configuration not provided") } conf := email.config c, err := smtp.Dial(conf.ServerName) if err != nil { return err } defer c.Close() // not sure if this is needed //if err = c.Hello(conf.ServerName); err != nil { // return err //} if ok, _ := c.Extension("STARTTLS"); ok { // disable stupid tls check for self-signed certificates config := &tls.Config{ ServerName: conf.ServerName, InsecureSkipVerify: true, } // for golang testing //if testHookStartTLS != nil { // testHookStartTLS(config) //} if err = c.StartTLS(config); err != nil { return err } } /* // don't know what to do with this if a != nil && c.ext != nil { if _, ok := c.ext["AUTH"]; !ok { return errors.New("smtp: server doesn't support AUTH") } if err = c.Auth(a); err != nil { return err } } */ // Set up authentication information. auth := smtp.PlainAuth(conf.Identity, conf.Username, conf.Password, conf.Host) if err = c.Auth(auth); err != nil { return err } if err = c.Mail(email.From); err != nil { return err } for _, addr := range email.To { if err = c.Rcpt(addr); err != nil { return err } } w, err := c.Data() if err != nil { return err } _, err = w.Write(email.Bytes()) if err != nil { return err } err = w.Close() if err != nil { return err } return c.Quit() } type EmailConfig struct { ServerName string `json:"-"` Identity string `json:"-"` Username string `json:"username"` Password string `json:"password"` Host string `json:"host"` Port int `json:"port"` } func NewEmailConfig(ident, uname, pword, host string, port int) *EmailConfig { return &EmailConfig{ ServerName: host + fmt.Sprintf(":%d", port), Identity: ident, Username: uname, Password: pword, Host: host, Port: port, } }