package mail import ( "errors" "eta/eta_email_analysis/global" "eta/eta_email_analysis/models/report" "fmt" "github.com/emersion/go-imap" "github.com/emersion/go-imap/client" "github.com/emersion/go-message" "github.com/emersion/go-message/mail" "log" "strings" "time" ) func ListenMailV2(c *client.Client, to uint32) (err error) { // 收件箱 obj := new(report.OutsideEmailBaseInfo) // 创建一个序列集,用于批量读取邮件 seqSet := new(imap.SeqSet) var isStopFor bool step := uint32(1) for i := to; i >= 1; { start := i - step + 1 if start < 0 { start = 1 } //fmt.Printf("当前剩余%d封邮件待处理\n", i-minIndex+1) seqSet.Clear() seqSet.AddRange(start, i) // 添加指定范围内的邮件编号 // 获取整个消息正文 // imap.FetchEnvelope:请求获取邮件的信封数据(例如发件人、收件人、主题等元数据)。 // imap.FetchRFC822:请求获取完整的邮件内容,包括所有头部和正文。 items := []imap.FetchItem{imap.FetchFlags, imap.FetchEnvelope, imap.FetchRFC822} // 获取邮件内容 Start messages := make(chan *imap.Message, global.CONFIG.Email.ReadBatchSize) // 创建一个通道,用于接收邮件消息 fetchDone := make(chan error, 1) // 创建一个通道,用于接收错误消息 go func() { // Fetch方法用于从服务器获取邮件数据,这里请求了邮件的信封和完整内容 fetchDone <- c.Fetch(seqSet, items, messages) }() err = <-fetchDone if err != nil { global.LOG.Errorf("获取邮件信息出现错误:%v \n", err) return } // 获取邮件内容 End //log.Println("开始读取邮件内容") for msg := range messages { // 如果需要终止,那么就不处理了 if isStopFor { continue } emailMessage, isRead, tmpErr := readEveryMsgV2(msg) if tmpErr != nil { continue } if !isRead { continue } // 记录邮件信息 { outEmail, _ := obj.GetByEmailMessageIdAndFolder(emailMessage.Uid, emailMessage.Folder) if outEmail == nil || outEmail.EmailMessageUid <= 0 { outsideEmail := &report.OutsideEmailBaseInfo{ Id: 0, Folder: emailMessage.Folder, EmailMessageUid: emailMessage.Uid, Title: emailMessage.Title, FromAddress: emailMessage.FromAddress, From: emailMessage.From, DeliveryTime: emailMessage.Date, CreateTime: time.Now(), } tmpErr := obj.Add(outsideEmail) if tmpErr != nil { fmt.Println("保存邮件基础信息失败:" + tmpErr.Error()) } } } } if isStopFor { // 已经找到了最小的邮件id,那么就退出循环了 } //time.Sleep(time.Second * 5) // 休眠10秒 i = i - step } log.Println("读取了所有邮件,完毕!") return } // document link: https://github.com/emersion/go-imap/wiki/Fetching-messages func readEveryMsgV2(msg *imap.Message) (emailMessage MailMessage, ok bool, err error) { emailMessage = MailMessage{} message.CharsetReader = myCharsetReader emailMessage.Resources = make(map[string]string) // 内嵌资源 emailMessage.Attachment = make(map[string]string) // 附件 emailMessage.Uid = msg.Uid emailMessage.Folder = global.CONFIG.Email.Folder if IsHandleMessageIdMap != nil { if _, has := IsHandleMessageIdMap[int(emailMessage.Uid)]; has { fmt.Println("邮件已处理,邮件下标:", emailMessage.Uid) return } } //log.Printf("当前邮件的消息序列号 %+v \n", msg.SeqNum) //log.Println("-------------------------") // 获取邮件正文 r := msg.GetBody(&imap.BodySectionName{}) if r == nil { global.FILE_LOG.Info("服务器没有返回消息内容") } mr, err := mail.CreateReader(r) if err != nil { //log.Fatalf("邮件读取时出现错误: %v \n", err) err = errors.New(fmt.Sprintf("邮件读取时出现错误:%v \n", err)) return } // 收件时间 { date, err := mr.Header.Date() if err != nil { log.Println("收件时间 异常:", err.Error()) } emailMessage.Date = date //log.Println("收件时间 Date:", date) } // 发件人 { fromStr := mr.Header.Get("From") //fmt.Println(fromStr) // 处理无效地址的情况 if !strings.Contains(fromStr, "@") { emailMessage.FromAddress = fromStr emailMessage.From = fromStr } else { from, tmpErr := mr.Header.AddressList("From") if tmpErr != nil { log.Println("发件人 异常:", err.Error()) } if len(from) > 0 { emailMessage.FromAddress = from[0].Address emailMessage.From = from[0].Name //mailMessage.From = from[0].String() //log.Println("发件人 From:", from) } } } //if to, err := mr.Header.AddressList("To"); err == nil { // log.Println("收件人 To:", to) //} //log.Printf("抄送 Cc: %+v \n", msg.Envelope.Cc) // 邮件标题 subject, err := mr.Header.Subject() if err != nil { log.Println("邮件主题 Subject ERR:", err) } else { //log.Println("邮件主题 Subject:", subject) } emailMessage.Title = subject // 过滤 if isIgnore(emailMessage) { ok = false return } ok = true return }