Skip to content

Commit cd49370

Browse files
committed
Limit mail processing to new recent messages
1 parent 13bae7f commit cd49370

3 files changed

Lines changed: 68 additions & 19 deletions

File tree

globals.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var (
2222
accountChecking sync.Map // 防止同一个账号的 IMAP 检查并发
2323
processingMutex sync.Mutex // 防止并发处理待发送消息
2424
httpClient = &http.Client{Timeout: 15 * time.Second} // 全局 Webhook 请求带超时的客户端
25+
serviceStartedAt = time.Now() // 只处理服务启动后收到的邮件,避免重启后转发历史未读
2526
)
2627

2728
const (

mail.go

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,51 @@ func displaySubject(subject string) string {
179179
return subject
180180
}
181181

182+
func messageDateForFilter(msg *imap.Message) time.Time {
183+
if msg == nil {
184+
return time.Time{}
185+
}
186+
if msg.Envelope != nil && !msg.Envelope.Date.IsZero() {
187+
return msg.Envelope.Date
188+
}
189+
return msg.InternalDate
190+
}
191+
192+
func messageDateForStore(msg *imap.Message) time.Time {
193+
if msg == nil || msg.Envelope == nil || msg.Envelope.Date.IsZero() {
194+
return time.Time{}
195+
}
196+
return msg.Envelope.Date
197+
}
198+
199+
func displayMessageDate(date time.Time) string {
200+
if date.IsZero() {
201+
return "无发送时间"
202+
}
203+
utc8 := time.FixedZone("UTC+8", 8*60*60)
204+
return date.In(utc8).Format("2006-01-02 15:04:05")
205+
}
206+
207+
func fetchFirstMessage(c *client.Client, seqSet *imap.SeqSet, items []imap.FetchItem) (*imap.Message, error) {
208+
messages := make(chan *imap.Message, 1)
209+
fetchDone := make(chan error, 1)
210+
211+
go func() {
212+
fetchDone <- c.UidFetch(seqSet, items, messages)
213+
}()
214+
215+
var msg *imap.Message
216+
for m := range messages {
217+
if msg == nil {
218+
msg = m
219+
}
220+
}
221+
if err := <-fetchDone; err != nil {
222+
return nil, err
223+
}
224+
return msg, nil
225+
}
226+
182227
func checkMailForAccount(account *EmailAccount) {
183228
if !account.Enabled {
184229
return
@@ -270,22 +315,8 @@ func checkFolderForAccount(account *EmailAccount, folder string) {
270315
seqSet := new(imap.SeqSet)
271316
seqSet.AddNum(uid)
272317

273-
var section imap.BodySectionName
274-
items := []imap.FetchItem{section.FetchItem(), imap.FetchEnvelope, imap.FetchInternalDate}
275-
messages := make(chan *imap.Message, 1)
276-
fetchDone := make(chan error, 1)
277-
278-
go func() {
279-
fetchDone <- c.UidFetch(seqSet, items, messages)
280-
}()
281-
282-
var msg *imap.Message
283-
for m := range messages {
284-
if msg == nil {
285-
msg = m // 获取第一个拿去处理,剩下的强行消费完(防止 IMAP Server 返回多个对象导致 Channel 卡死 goroutine 泄露)
286-
}
287-
}
288-
if fetchErr := <-fetchDone; fetchErr != nil {
318+
msg, fetchErr := fetchFirstMessage(c, seqSet, []imap.FetchItem{imap.FetchEnvelope, imap.FetchInternalDate})
319+
if fetchErr != nil {
289320
addLog(fmt.Sprintf("读取邮件失败 [%s/%s uid=%d]: %v", account.Name, folder, uid, fetchErr), "error")
290321
continue
291322
}
@@ -294,13 +325,30 @@ func checkFolderForAccount(account *EmailAccount, folder string) {
294325
addLog(fmt.Sprintf("读取邮件为空 [%s/%s uid=%d]", account.Name, folder, uid), "warning")
295326
continue
296327
}
328+
filterDate := messageDateForFilter(msg)
329+
if filterDate.IsZero() || filterDate.Before(serviceStartedAt) {
330+
addLog(fmt.Sprintf("跳过历史邮件 [%s/%s uid=%d]: %s", account.Name, folder, uid, displaySubject(msg.Envelope.Subject)), "info")
331+
continue
332+
}
297333

298334
from := ""
299335
if len(msg.Envelope.From) > 0 {
300336
from = msg.Envelope.From[0].Address()
301337
}
302338

303-
r := msg.GetBody(&section)
339+
var section imap.BodySectionName
340+
bodyMsg, fetchErr := fetchFirstMessage(c, seqSet, []imap.FetchItem{section.FetchItem()})
341+
if fetchErr != nil {
342+
addLog(fmt.Sprintf("读取邮件正文失败 [%s/%s uid=%d]: %v", account.Name, folder, uid, fetchErr), "error")
343+
continue
344+
}
345+
346+
if bodyMsg == nil {
347+
addLog(fmt.Sprintf("读取邮件正文为空 [%s/%s uid=%d]: %s", account.Name, folder, uid, displaySubject(msg.Envelope.Subject)), "warning")
348+
continue
349+
}
350+
351+
r := bodyMsg.GetBody(&section)
304352
if r == nil {
305353
addLog(fmt.Sprintf("邮件正文为空 [%s/%s uid=%d]: %s", account.Name, folder, uid, displaySubject(msg.Envelope.Subject)), "warning")
306354
continue
@@ -342,7 +390,7 @@ func checkFolderForAccount(account *EmailAccount, folder string) {
342390
Subject: msg.Envelope.Subject,
343391
From: from,
344392
To: account.EmailUser,
345-
Date: msg.Envelope.Date,
393+
Date: messageDateForStore(msg),
346394
Body: body,
347395
BodyHTML: bodyHTML,
348396
Status: "pending",

processor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func processPendingMessages() {
7979

8080
// 发送
8181
var sendErr error
82-
dateStr := msg.Date.Format("2006-01-02 15:04:05")
82+
dateStr := displayMessageDate(msg.Date)
8383
subjectForSend := displaySubject(msg.Subject)
8484
senderForSend := filterCtx.DisplaySender
8585

0 commit comments

Comments
 (0)