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  }