read_content.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package smtp_server
  2. import (
  3. "bytes"
  4. "database/sql"
  5. "encoding/json"
  6. "github.com/mileusna/spf"
  7. log "github.com/sirupsen/logrus"
  8. "github.com/spf13/cast"
  9. "io"
  10. "net"
  11. "net/netip"
  12. "pmail/config"
  13. "pmail/db"
  14. "pmail/dto/parsemail"
  15. "pmail/hooks"
  16. "pmail/hooks/framework"
  17. "pmail/models"
  18. "pmail/services/rule"
  19. "pmail/utils/async"
  20. "pmail/utils/context"
  21. "pmail/utils/send"
  22. "strings"
  23. "time"
  24. )
  25. func (s *Session) Data(r io.Reader) error {
  26. ctx := s.Ctx
  27. log.WithContext(ctx).Debugf("收到邮件")
  28. emailData, err := io.ReadAll(r)
  29. if err != nil {
  30. log.WithContext(ctx).Error("邮件内容无法读取", err)
  31. return err
  32. }
  33. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseBefore!")
  34. as1 := async.New(ctx)
  35. for _, hook := range hooks.HookList {
  36. if hook == nil {
  37. continue
  38. }
  39. as1.WaitProcess(func(hk any) {
  40. hk.(framework.EmailHook).ReceiveParseBefore(ctx, &emailData)
  41. }, hook)
  42. }
  43. as1.Wait()
  44. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseBefore End!")
  45. log.WithContext(ctx).Infof("邮件原始内容: %s", emailData)
  46. email := parsemail.NewEmailFromReader(s.To, bytes.NewReader(emailData))
  47. if s.From != "" {
  48. from := parsemail.BuilderUser(s.From)
  49. if email.From == nil {
  50. email.From = from
  51. }
  52. if email.From.EmailAddress != from.EmailAddress {
  53. // 协议中的from和邮件内容中的from不匹配,当成垃圾邮件处理
  54. //log.WithContext(s.Ctx).Infof("垃圾邮件,拒信")
  55. //return nil
  56. }
  57. }
  58. // 判断是收信还是转发,只要是登陆了,都当成转发处理
  59. //account, domain := email.From.GetDomainAccount()
  60. if s.Ctx.UserID > 0 {
  61. log.WithContext(ctx).Debugf("开始执行插件SendBefore!")
  62. as2 := async.New(ctx)
  63. for _, hook := range hooks.HookList {
  64. if hook == nil {
  65. continue
  66. }
  67. as2.WaitProcess(func(hk any) {
  68. hk.(framework.EmailHook).SendBefore(ctx, email)
  69. }, hook)
  70. }
  71. as2.Wait()
  72. log.WithContext(ctx).Debugf("开始执行插件SendBefore!End")
  73. if email == nil {
  74. return nil
  75. }
  76. // 转发
  77. err := saveEmail(ctx, email, s.Ctx.UserID, 1, true, true)
  78. if err != nil {
  79. log.WithContext(ctx).Errorf("Email Save Error %v", err)
  80. }
  81. errMsg := ""
  82. err, sendErr := send.Send(ctx, email)
  83. log.WithContext(ctx).Debugf("插件执行--SendAfter")
  84. as3 := async.New(ctx)
  85. for _, hook := range hooks.HookList {
  86. if hook == nil {
  87. continue
  88. }
  89. as3.WaitProcess(func(hk any) {
  90. hk.(framework.EmailHook).SendAfter(ctx, email, sendErr)
  91. }, hook)
  92. }
  93. as3.Wait()
  94. log.WithContext(ctx).Debugf("插件执行--SendAfter")
  95. if err != nil {
  96. errMsg = err.Error()
  97. _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =2 ,error=? where id = ? "), errMsg, email.MessageId)
  98. if err != nil {
  99. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  100. }
  101. } else {
  102. _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), email.MessageId)
  103. if err != nil {
  104. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  105. }
  106. }
  107. } else {
  108. // 收件
  109. var dkimStatus, SPFStatus bool
  110. // DKIM校验
  111. dkimStatus = parsemail.Check(bytes.NewReader(emailData))
  112. if err != nil {
  113. log.WithContext(ctx).Errorf("邮件内容解析失败! Error : %v \n", err)
  114. }
  115. SPFStatus = spfCheck(s.RemoteAddress.String(), email.Sender, email.Sender.EmailAddress)
  116. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseAfter!")
  117. as2 := async.New(ctx)
  118. for _, hook := range hooks.HookList {
  119. if hook == nil {
  120. continue
  121. }
  122. as2.WaitProcess(func(hk any) {
  123. hk.(framework.EmailHook).ReceiveParseAfter(ctx, email)
  124. }, hook)
  125. }
  126. as2.Wait()
  127. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseAfter!End")
  128. if email == nil {
  129. return nil
  130. }
  131. // 垃圾过滤
  132. if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus {
  133. log.WithContext(ctx).Infoln("垃圾邮件,拒信")
  134. return nil
  135. }
  136. if config.Instance.SpamFilterLevel == 2 && !SPFStatus {
  137. log.WithContext(ctx).Infoln("垃圾邮件,拒信")
  138. return nil
  139. }
  140. saveEmail(ctx, email, 0, 0, SPFStatus, dkimStatus)
  141. if email.MessageId > 0 {
  142. log.WithContext(ctx).Debugf("开始执行邮件规则!")
  143. // 执行邮件规则
  144. rs := rule.GetAllRules(ctx)
  145. for _, r := range rs {
  146. if rule.MatchRule(ctx, r, email) {
  147. rule.DoRule(ctx, r, email)
  148. }
  149. }
  150. }
  151. log.WithContext(ctx).Debugf("开始执行插件ReceiveSaveAfter!")
  152. as3 := async.New(ctx)
  153. for _, hook := range hooks.HookList {
  154. if hook == nil {
  155. continue
  156. }
  157. as3.WaitProcess(func(hk any) {
  158. hk.(framework.EmailHook).ReceiveSaveAfter(ctx, email)
  159. }, hook)
  160. }
  161. as3.Wait()
  162. log.WithContext(ctx).Debugf("开始执行插件ReceiveSaveAfter!End")
  163. }
  164. return nil
  165. }
  166. func saveEmail(ctx *context.Context, email *parsemail.Email, sendUserID int, emailType int, SPFStatus, dkimStatus bool) error {
  167. var dkimV, spfV int8
  168. if dkimStatus {
  169. dkimV = 1
  170. }
  171. if SPFStatus {
  172. spfV = 1
  173. }
  174. log.WithContext(ctx).Debugf("开始入库!")
  175. if email == nil {
  176. return nil
  177. }
  178. modelEmail := models.Email{
  179. Type: cast.ToInt8(emailType),
  180. GroupId: email.GroupId,
  181. Subject: email.Subject,
  182. ReplyTo: json2string(email.ReplyTo),
  183. FromName: email.From.Name,
  184. FromAddress: email.From.EmailAddress,
  185. To: json2string(email.To),
  186. Bcc: json2string(email.Bcc),
  187. Cc: json2string(email.Cc),
  188. Text: sql.NullString{String: string(email.Text), Valid: true},
  189. Html: sql.NullString{String: string(email.HTML), Valid: true},
  190. Sender: json2string(email.Sender),
  191. Attachments: json2string(email.Attachments),
  192. SPFCheck: spfV,
  193. DKIMCheck: dkimV,
  194. SendUserID: sendUserID,
  195. SendDate: time.Now(),
  196. Status: cast.ToInt8(email.Status),
  197. CreateTime: time.Now(),
  198. }
  199. _, err := db.Instance.Insert(&modelEmail)
  200. if err != nil {
  201. log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
  202. }
  203. if modelEmail.Id > 0 {
  204. email.MessageId = cast.ToInt64(modelEmail.Id)
  205. }
  206. return nil
  207. }
  208. func json2string(d any) string {
  209. by, _ := json.Marshal(d)
  210. return string(by)
  211. }
  212. func spfCheck(remoteAddress string, sender *parsemail.User, senderString string) bool {
  213. //spf校验
  214. ipAddress, _ := netip.ParseAddrPort(remoteAddress)
  215. ip := net.ParseIP(ipAddress.Addr().String())
  216. if ip.IsPrivate() {
  217. return true
  218. }
  219. tmp := strings.Split(sender.EmailAddress, "@")
  220. if len(tmp) < 2 {
  221. return false
  222. }
  223. res := spf.CheckHost(ip, tmp[1], senderString, "")
  224. if res == spf.None || res == spf.Pass {
  225. // spf校验通过
  226. return true
  227. }
  228. return false
  229. }