package main import ( "encoding/base64" "fmt" "net/smtp" "sort" "strings" "sync" "time" log "github.com/sirupsen/logrus" ) type Email struct { startTime time.Time items []string mx sync.Mutex } type EmailConfig struct { SmtpHost string `json:"smtp"` FromEmail string `json:"email_from"` ToEmail []string `json:"email_to"` } func NewEmail(now time.Time) *Email { log.WithFields(log.Fields{"now": now}).Debugf("starting") defer log.WithFields(log.Fields{"now": now}).Debugf("done") return &Email{startTime: now, items: make([]string, 0)} } func (e *Email) AddItem(item string) { log.WithFields(log.Fields{"item": item}).Debugf("starting") defer log.WithFields(log.Fields{"item": item}).Debugf("done") e.items = append(e.items, item) } func (e *Email) Send() error { log.WithFields(log.Fields{}).Debugf("starting") defer log.WithFields(log.Fields{}).Debugf("done") if len(e.items) == 0 { return nil } sort.Slice(e.items, func(i, j int) bool { return e.items[i] < e.items[j] }) body := e.items[0] for _, item := range e.items[1:] { body = body + "\r\n" + item } subject := fmt.Sprintf("Autobackup report (%s)", e.startTime) if err := SendMail(cfg.Email.SmtpHost, cfg.Email.FromEmail, subject, body, cfg.Email.ToEmail); err != nil { log.WithFields(log.Fields{"addr": cfg.Email.SmtpHost, "from": cfg.Email.FromEmail, "subject": subject, "call": "SendMail", "error": err}).Errorf("") return err } return nil } func SendMail(addr, from, subject, body string, to []string) error { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject}).Debugf("starting") defer log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject}).Debugf("done") r := strings.NewReplacer("\r\n", "", "\r", "", "\n", "", "%0a", "", "%0d", "") c, err := smtp.Dial(addr) if err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "smtp.Dial", "error": err}).Errorf("") return err } defer c.Close() if err = c.Mail(r.Replace(from)); err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "client.Mail", "error": err}).Errorf("") return err } for i := range to { to[i] = r.Replace(to[i]) if err = c.Rcpt(to[i]); err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "client.Rcpt", "attr": to[i], "error": err}).Errorf("") return err } } w, err := c.Data() if err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "client.Date", "error": err}).Errorf("") return err } msg := "Date: " + time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700") + "\r\n" + "To: " + strings.Join(to, ",") + "\r\n" + "From: " + from + "\r\n" + "Subject: " + subject + "\r\n" + "Content-Type: text/plain; charset=\"UTF-8\"\r\n" + "Content-Transfer-Encoding: base64\r\n" + "\r\n" + base64.StdEncoding.EncodeToString([]byte(body)) _, err = w.Write([]byte(msg)) if err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "writer.Write", "error": err}).Errorf("") return err } err = w.Close() if err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "writer.Close", "error": err}).Errorf("") return err } if err = c.Quit(); err != nil { log.WithFields(log.Fields{"addr": addr, "from": from, "subject": subject, "call": "client.Quit", "error": err}).Errorf("") return err } return nil }