github.com/infraboard/keyauth@v0.8.1/apps/system/notify/mail.go (about) 1 package notify 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "net/textproto" 8 "time" 9 10 "github.com/go-playground/validator/v10" 11 ) 12 13 // use a single instance of Validate, it caches struct info 14 var ( 15 validate = validator.New() 16 ) 17 18 // MailSender 投递消息器 19 type MailSender interface { 20 Send(*SendMailRequest) error 21 } 22 23 // NewSendMailRequest todo 24 func NewSendMailRequest() *SendMailRequest { 25 return &SendMailRequest{ 26 buffer: bytes.NewBuffer([]byte{}), 27 } 28 } 29 30 // SendMailRequest todo 31 type SendMailRequest struct { 32 To string `json:"to,omitempty" validate:"required"` 33 Cc string `json:"cc,omitempty"` 34 Subject string `json:"subject,omitempty" validate:"required"` 35 Content string `json:"content,omitempty" validate:"required"` 36 37 buffer *bytes.Buffer `json:"-"` 38 } 39 40 // Validate todo 41 func (req *SendMailRequest) Validate() error { 42 return validate.Struct(req) 43 } 44 45 // PrepareBody todo 46 func (req *SendMailRequest) PrepareBody(from string) ([]byte, error) { 47 // 设置邮件Header 48 headers := textproto.MIMEHeader{} 49 headers.Set("From", from) 50 headers.Set("To", req.To) 51 headers.Set("Cc", req.Cc) 52 53 headers.Set("Subject", req.Subject) 54 headers.Set("Date", time.Now().Format(time.RFC1123Z)) 55 headers.Set("MIME-Version", "1.0") 56 headers.Set("Content-Type", "text/html; charset=UTF-8;") 57 if err := headerToBytesSeq(req.buffer, headers); err != nil { 58 return nil, fmt.Errorf("Failed to render message headers: %s", err) 59 } 60 req.buffer.WriteString("\r\n") 61 req.buffer.WriteString(req.Content) 62 return req.buffer.Bytes(), nil 63 } 64 65 // hack here 原来的headerToBytes有个严重bug,textproto.MIMEHeader是个map,for range出来是无序的 66 func headerToBytesSeq(w io.Writer, t textproto.MIMEHeader) (err error) { 67 var seq = []string{`From`, `To`, `Cc`, `Subject`, `Disposition-Notification-To`, `Date`, `MIME-Version`, `Content-Type`} 68 for _, mapKey := range seq { 69 // Write the header key 70 if `` == t.Get(mapKey) { 71 continue 72 } 73 _, err = fmt.Fprintf(w, "%s:", mapKey) 74 if err != nil { 75 return err 76 } 77 _, err = fmt.Fprintf(w, " %s\r\n", t.Get(mapKey)) 78 if err != nil { 79 return err 80 } 81 } 82 return nil 83 }