read_content.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package smtp_server
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "github.com/mileusna/spf"
  6. log "github.com/sirupsen/logrus"
  7. "io"
  8. "net"
  9. "net/netip"
  10. "pmail/config"
  11. "pmail/db"
  12. "pmail/dto/parsemail"
  13. "pmail/hooks"
  14. "pmail/services/rule"
  15. "pmail/utils/async"
  16. "pmail/utils/context"
  17. "pmail/utils/id"
  18. "strings"
  19. "time"
  20. )
  21. func (s *Session) Data(r io.Reader) error {
  22. ctx := &context.Context{}
  23. ctx.SetValue(context.LogID, id.GenLogID())
  24. log.WithContext(ctx).Debugf("收到邮件")
  25. emailData, err := io.ReadAll(r)
  26. if err != nil {
  27. log.WithContext(ctx).Error("邮件内容无法读取", err)
  28. return err
  29. }
  30. as1 := async.New(ctx)
  31. for _, hook := range hooks.HookList {
  32. if hook == nil {
  33. continue
  34. }
  35. as1.WaitProcess(func(hk any) {
  36. hk.(hooks.EmailHook).ReceiveParseBefore(emailData)
  37. }, hook)
  38. }
  39. as1.Wait()
  40. log.WithContext(ctx).Infof("邮件原始内容: %s", emailData)
  41. var dkimStatus, SPFStatus bool
  42. // DKIM校验
  43. dkimStatus = parsemail.Check(bytes.NewReader(emailData))
  44. email := parsemail.NewEmailFromReader(bytes.NewReader(emailData))
  45. if err != nil {
  46. log.WithContext(ctx).Errorf("邮件内容解析失败! Error : %v \n", err)
  47. }
  48. SPFStatus = spfCheck(s.RemoteAddress.String(), email.Sender, email.Sender.EmailAddress)
  49. var dkimV, spfV int8
  50. if dkimStatus {
  51. dkimV = 1
  52. }
  53. if SPFStatus {
  54. spfV = 1
  55. }
  56. // 垃圾过滤
  57. if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus {
  58. log.WithContext(ctx).Infoln("垃圾邮件,拒信")
  59. return nil
  60. }
  61. if config.Instance.SpamFilterLevel == 2 && !SPFStatus {
  62. log.WithContext(ctx).Infoln("垃圾邮件,拒信")
  63. return nil
  64. }
  65. log.WithContext(ctx).Debugf("开始执行插件!")
  66. as2 := async.New(ctx)
  67. for _, hook := range hooks.HookList {
  68. if hook == nil {
  69. continue
  70. }
  71. as2.WaitProcess(func(hk any) {
  72. hk.(hooks.EmailHook).ReceiveParseAfter(email)
  73. }, hook)
  74. }
  75. as2.Wait()
  76. log.WithContext(ctx).Debugf("开始执行邮件规则!")
  77. // 执行邮件规则
  78. rs := rule.GetAllRules(ctx)
  79. for _, r := range rs {
  80. if rule.MatchRule(ctx, r, email) {
  81. rule.DoRule(ctx, r, email)
  82. }
  83. }
  84. log.WithContext(ctx).Debugf("开始入库!")
  85. if email == nil {
  86. return nil
  87. }
  88. sql := "INSERT INTO email (send_date, subject, reply_to, from_name, from_address, `to`, bcc, cc, text, html, sender, attachments,spf_check, dkim_check, create_time,is_read,status,group_id) VALUES (?,?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
  89. _, err = db.Instance.Exec(sql,
  90. email.Date,
  91. email.Subject,
  92. json2string(email.ReplyTo),
  93. email.From.Name,
  94. email.From.EmailAddress,
  95. json2string(email.To),
  96. json2string(email.Bcc),
  97. json2string(email.Cc),
  98. email.Text,
  99. email.HTML,
  100. json2string(email.Sender),
  101. json2string(email.Attachments),
  102. spfV,
  103. dkimV,
  104. time.Now(),
  105. email.IsRead,
  106. email.Status,
  107. email.GroupId,
  108. )
  109. if err != nil {
  110. log.WithContext(ctx).Println("mysql insert error:", err.Error())
  111. }
  112. return nil
  113. }
  114. func json2string(d any) string {
  115. by, _ := json.Marshal(d)
  116. return string(by)
  117. }
  118. func spfCheck(remoteAddress string, sender *parsemail.User, senderString string) bool {
  119. //spf校验
  120. ipAddress, _ := netip.ParseAddrPort(remoteAddress)
  121. ip := net.ParseIP(ipAddress.Addr().String())
  122. if ip.IsPrivate() {
  123. return true
  124. }
  125. tmp := strings.Split(sender.EmailAddress, "@")
  126. if len(tmp) < 2 {
  127. return false
  128. }
  129. res := spf.CheckHost(ip, tmp[1], senderString, "")
  130. if res == spf.None || res == spf.Pass {
  131. // spf校验通过
  132. return true
  133. }
  134. return false
  135. }