read_content.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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/errors"
  22. "pmail/utils/send"
  23. "strings"
  24. "time"
  25. . "xorm.io/builder"
  26. )
  27. func (s *Session) Data(r io.Reader) error {
  28. ctx := s.Ctx
  29. log.WithContext(ctx).Debugf("收到邮件")
  30. emailData, err := io.ReadAll(r)
  31. if err != nil {
  32. log.WithContext(ctx).Error("邮件内容无法读取", err)
  33. return err
  34. }
  35. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseBefore!")
  36. for _, hook := range hooks.HookList {
  37. if hook == nil {
  38. continue
  39. }
  40. hook.ReceiveParseBefore(ctx, &emailData)
  41. }
  42. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseBefore End!")
  43. log.WithContext(ctx).Infof("邮件原始内容: %s", emailData)
  44. email := parsemail.NewEmailFromReader(s.To, bytes.NewReader(emailData))
  45. if s.From != "" {
  46. from := parsemail.BuilderUser(s.From)
  47. if email.From == nil {
  48. email.From = from
  49. }
  50. if email.From.EmailAddress != from.EmailAddress {
  51. // 协议中的from和邮件内容中的from不匹配,当成垃圾邮件处理
  52. //log.WithContext(s.Ctx).Infof("垃圾邮件,拒信")
  53. //return nil
  54. }
  55. }
  56. // 判断是收信还是转发,只要是登陆了,都当成转发处理
  57. if s.Ctx.UserID > 0 {
  58. account, _ := email.From.GetDomainAccount()
  59. if account != ctx.UserAccount && !ctx.IsAdmin {
  60. return errors.New("No Auth")
  61. }
  62. log.WithContext(ctx).Debugf("开始执行插件SendBefore!")
  63. for _, hook := range hooks.HookList {
  64. if hook == nil {
  65. continue
  66. }
  67. hook.SendBefore(ctx, email)
  68. }
  69. log.WithContext(ctx).Debugf("开始执行插件SendBefore!End")
  70. if email == nil {
  71. return nil
  72. }
  73. // 转发
  74. _, err := saveEmail(ctx, len(emailData), email, s.Ctx.UserID, 1, true, true)
  75. if err != nil {
  76. log.WithContext(ctx).Errorf("Email Save Error %v", err)
  77. }
  78. errMsg := ""
  79. err, sendErr := send.Send(ctx, email)
  80. log.WithContext(ctx).Debugf("插件执行--SendAfter")
  81. as3 := async.New(ctx)
  82. for _, hook := range hooks.HookList {
  83. if hook == nil {
  84. continue
  85. }
  86. as3.WaitProcess(func(hk any) {
  87. hk.(framework.EmailHook).SendAfter(ctx, email, sendErr)
  88. }, hook)
  89. }
  90. as3.Wait()
  91. log.WithContext(ctx).Debugf("插件执行--SendAfter")
  92. if err != nil {
  93. errMsg = err.Error()
  94. _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =2 ,error=? where id = ? "), errMsg, email.MessageId)
  95. if err != nil {
  96. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  97. }
  98. _, err = db.Instance.Exec(db.WithContext(ctx, "update user_email set status =2 where email_id = ? "), email.MessageId)
  99. if err != nil {
  100. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  101. }
  102. } else {
  103. _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), email.MessageId)
  104. if err != nil {
  105. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  106. }
  107. _, err = db.Instance.Exec(db.WithContext(ctx, "update user_email set status =1 where email_id = ? "), email.MessageId)
  108. if err != nil {
  109. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  110. }
  111. }
  112. } else {
  113. // 收件
  114. var dkimStatus, SPFStatus bool
  115. // DKIM校验
  116. dkimStatus = parsemail.Check(bytes.NewReader(emailData))
  117. SPFStatus = spfCheck(s.RemoteAddress.String(), email.Sender, email.Sender.EmailAddress)
  118. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseAfter!")
  119. for _, hook := range hooks.HookList {
  120. if hook == nil {
  121. continue
  122. }
  123. hook.ReceiveParseAfter(ctx, email)
  124. }
  125. log.WithContext(ctx).Debugf("开始执行插件ReceiveParseAfter!End")
  126. // 垃圾过滤
  127. if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus {
  128. log.WithContext(ctx).Infoln("垃圾邮件,拒信")
  129. return nil
  130. }
  131. if config.Instance.SpamFilterLevel == 2 && !SPFStatus {
  132. log.WithContext(ctx).Infoln("垃圾邮件,拒信")
  133. return nil
  134. }
  135. users, _ := saveEmail(ctx, len(emailData), email, 0, 0, SPFStatus, dkimStatus)
  136. if email.MessageId > 0 {
  137. log.WithContext(ctx).Debugf("开始执行邮件规则!")
  138. for _, user := range users {
  139. // 执行邮件规则
  140. rs := rule.GetAllRules(ctx, user.ID)
  141. for _, r := range rs {
  142. if rule.MatchRule(ctx, r, email) {
  143. rule.DoRule(ctx, r, email)
  144. }
  145. }
  146. }
  147. }
  148. log.WithContext(ctx).Debugf("开始执行插件ReceiveSaveAfter!")
  149. var ue []*models.UserEmail
  150. err = db.Instance.Table(&models.UserEmail{}).Where("email_id=?", email.MessageId).Find(&ue)
  151. if err != nil {
  152. log.WithContext(ctx).Errorf("sql Error :%+v", err)
  153. }
  154. as3 := async.New(ctx)
  155. for _, hook := range hooks.HookList {
  156. if hook == nil {
  157. continue
  158. }
  159. as3.WaitProcess(func(hk any) {
  160. hk.(framework.EmailHook).ReceiveSaveAfter(ctx, email, ue)
  161. }, hook)
  162. }
  163. as3.Wait()
  164. log.WithContext(ctx).Debugf("开始执行插件ReceiveSaveAfter!End")
  165. }
  166. return nil
  167. }
  168. func saveEmail(ctx *context.Context, size int, email *parsemail.Email, sendUserID int, emailType int, SPFStatus, dkimStatus bool) ([]*models.User, error) {
  169. var dkimV, spfV int8
  170. if dkimStatus {
  171. dkimV = 1
  172. }
  173. if SPFStatus {
  174. spfV = 1
  175. }
  176. log.WithContext(ctx).Debugf("开始入库!")
  177. if email == nil {
  178. return nil, nil
  179. }
  180. modelEmail := models.Email{
  181. Type: cast.ToInt8(emailType),
  182. Subject: email.Subject,
  183. ReplyTo: json2string(email.ReplyTo),
  184. FromName: email.From.Name,
  185. FromAddress: email.From.EmailAddress,
  186. To: json2string(email.To),
  187. Bcc: json2string(email.Bcc),
  188. Cc: json2string(email.Cc),
  189. Text: sql.NullString{String: string(email.Text), Valid: true},
  190. Html: sql.NullString{String: string(email.HTML), Valid: true},
  191. Sender: json2string(email.Sender),
  192. Attachments: json2string(email.Attachments),
  193. SPFCheck: spfV,
  194. DKIMCheck: dkimV,
  195. SendUserID: sendUserID,
  196. SendDate: time.Now(),
  197. Status: cast.ToInt8(email.Status),
  198. CreateTime: time.Now(),
  199. }
  200. _, err := db.Instance.Insert(&modelEmail)
  201. if err != nil {
  202. log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
  203. }
  204. if modelEmail.Id > 0 {
  205. email.MessageId = cast.ToInt64(modelEmail.Id)
  206. }
  207. // 收信人信息
  208. var users []*models.User
  209. // 如果是收信
  210. if emailType == 0 {
  211. // 找到收信人id
  212. accounts := []string{}
  213. for _, user := range append(append(email.To, email.Cc...), email.Bcc...) {
  214. account, _ := user.GetDomainAccount()
  215. if account != "" {
  216. accounts = append(accounts, account)
  217. }
  218. }
  219. where, params, _ := ToSQL(In("account", accounts))
  220. err = db.Instance.Table(&models.User{}).Where(where, params...).Find(&users)
  221. if err != nil {
  222. log.WithContext(ctx).Errorf("db Select error:%+v", err.Error())
  223. }
  224. if len(users) > 0 {
  225. for _, user := range users {
  226. ue := models.UserEmail{EmailID: modelEmail.Id, UserID: user.ID}
  227. _, err = db.Instance.Insert(&ue)
  228. if err != nil {
  229. log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
  230. }
  231. }
  232. } else {
  233. users = append(users, &models.User{ID: 1})
  234. // 当邮件找不到收件人的时候,邮件全部丢给管理员账号
  235. // id = 1的账号直接当成管理员账号处理
  236. ue := models.UserEmail{EmailID: modelEmail.Id, UserID: 1}
  237. _, err = db.Instance.Insert(&ue)
  238. if err != nil {
  239. log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
  240. }
  241. }
  242. } else {
  243. ue := models.UserEmail{EmailID: modelEmail.Id, UserID: ctx.UserID}
  244. _, err = db.Instance.Insert(&ue)
  245. if err != nil {
  246. log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
  247. }
  248. }
  249. return users, nil
  250. }
  251. func json2string(d any) string {
  252. by, _ := json.Marshal(d)
  253. return string(by)
  254. }
  255. func spfCheck(remoteAddress string, sender *parsemail.User, senderString string) bool {
  256. //spf校验
  257. ipAddress, _ := netip.ParseAddrPort(remoteAddress)
  258. ip := net.ParseIP(ipAddress.Addr().String())
  259. if ip.IsPrivate() {
  260. return true
  261. }
  262. tmp := strings.Split(sender.EmailAddress, "@")
  263. if len(tmp) < 2 {
  264. return false
  265. }
  266. res := spf.CheckHost(ip, tmp[1], senderString, "")
  267. if res == spf.None || res == spf.Pass {
  268. // spf校验通过
  269. return true
  270. }
  271. return false
  272. }