Golang IMAP: Move mails in two different folders results in "The specified message set is invalid"

huangapple go评论88阅读模式
英文:

Golang IMAP: Move mails in two different folders results in "The specified message set is invalid"

问题

使用情况:我们有一个邮箱,我们从客户那里收到邮件。在进一步处理之前,我必须检查它们是否符合协议(主题必须与正则表达式匹配,每封邮件只能有一个附件等)。
我有以下应用程序:

import (
	"fmt"
	"imaptest/src/db"
	"io"
	"log"
	"path/filepath"
	"strings"

	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
	"github.com/emersion/go-message"
	"github.com/iglin/go-config"
)

(...)
// 用于存储邮件的通道
messages := make(chan *imap.Message, 10)
// 用于检索错误的通道
done := make(chan error, 1)
go func() {
	seqset := new(imap.SeqSet)
	seqset.AddRange(1, mbox.Messages)
	// 获取邮件并将其推送到通道中
	done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchRFC822}, messages)
}()

// 用于无效邮件的 SeqSet
seqsetErrorMessages := new(imap.SeqSet)
// 用于有效邮件的 SeqSet
seqsetValidMessages := new(imap.SeqSet)

for msg := range messages {
	// 进行不同的检查,例如是否有附件
	// 使用特定的正则表达式匹配主题
	if isMessageValid(msg) {
		// 邮件有效
		seqsetValidMessages.AddNum(msg.SeqNum)
	} else {
		// 邮件无效
		seqsetErrorMessages.AddNum(msg.SeqNum)
	}
}

// 检查获取邮件时是否出现错误
if err := <-done; err != nil {
	log.Fatal(err)
}

// 将所有无效邮件移动到错误文件夹
if !seqsetErrorMessages.Empty() {
	if err := c.Move(seqsetErrorMessages, FOLDER_ERROR); err != nil {
		log.Fatalf("移动到 %s 时出错:%v", FOLDER_ERROR, err)
	}
}
// 将所有有效邮件移动到导出文件夹
if !seqsetValidMessages.Empty() {
	if err := c.Move(seqsetValidMessages, FOLDER_OUT); err != nil {
		log.Fatalf("移动到 %s 时出错:%v", FOLDER_OUT, err)
	}
}

FOLDER_OUT 和 FOLDER_ERROR 是此邮箱中现有文件夹的常量字符串。

如果源文件夹中的所有邮件都是有效的(或无效的),一切都正常,所有邮件都会被移动。

但是,如果既有有效邮件又有无效邮件,我会收到以下错误消息:

移动到错误时出错:指定的邮件集无效。

我还尝试使用 msg.Uidc.UidMove() 替代 msg.Seqnumc.Move(),但结果相同。

如何解决这个问题?

英文:

Use case: we have a mailbox in which we receive mails from customers. Before further processing I have to check if they comply with the agreements (subject has to match a regex, only one attachment per mail, etc.)
I have the following application:

import (
&quot;fmt&quot;
&quot;imaptest/src/db&quot;
&quot;io&quot;
&quot;log&quot;
&quot;path/filepath&quot;
&quot;strings&quot;
&quot;github.com/emersion/go-imap&quot;
&quot;github.com/emersion/go-imap/client&quot;
&quot;github.com/emersion/go-message&quot;
&quot;github.com/iglin/go-config&quot;
)
(...)
//Channel for the messages
messages := make(chan *imap.Message, 10)
//Channel for retrieve if an error appeared
done := make(chan error, 1)
go func() {
seqset := new(imap.SeqSet)
seqset.AddRange(1, mbox.Messages)
//Fetch the messages and push them into the channel
done &lt;- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchRFC822}, messages)
}()
//SeqSet for invalid messages
seqsetErrorMessages := new(imap.SeqSet)
//SeqSet for valid messages
seqsetValidMessages := new(imap.SeqSet)
for msg := range messages {
//Different checks like are there attachments
//Matches the subject with a specific regex
if isMessageValid(msg) {
//Message is valid
seqsetValidMessages.AddNum(msg.SeqNum)
} else {
//Message is invalid
seqsetErrorMessages.AddNum(msg.SeqNum)
}
}
//Check if there was an error when fetching the messages
if err := &lt;-done; err != nil {
log.Fatal(err)
}
//Move all invalid messages to error
if !seqsetErrorMessages.Empty() {
if err := c.Move(seqsetErrorMessages, FOLDER_ERROR); err != nil {
log.Fatalf(&quot;Error on move to %s: %v&quot;, FOLDER_ERROR, err)
}
}
//Move all valid messages to toExport
if !seqsetValidMessages.Empty() {
if err := c.Move(seqsetValidMessages, FOLDER_OUT); err != nil {
log.Fatalf(&quot;Error on move to %s: %v&quot;, FOLDER_OUT, err)
}
}

FOLDER_OUT and FOLDER_ERROR are constant strings of existent folders in this mailbox.

In the case that all messages of the source folder are valid (or invalid), everything is
fine and all mails are moved.

But if I have the case that there are both valid and invalid mails, I receive the following error:

>Error on move to error: The specified message set is invalid.

I also tried to use "msg.Uid" and "c.UidMove()" instead of "msg.Seqnum" and "c.Move()" but this leads to the same result.

How this can be solved?

答案1

得分: 1

在这里使用UID是正确的答案,但请确保你有UID来开始。"1,4,9"既可以作为MSN集合,也可以作为UID集合,但两者不能互换使用。你不能向服务器请求一个MSN集合,然后将其与UID命令一起使用。

如果邮箱中恰好有两条消息,并且你想将其中第一条移动到FOLDER_ERROR,第二条移动到FOLDER_OUT,那么你会遇到问题。你发送一个命令,说"将邮箱中的第一条消息移动到FOLDER_ERROR",服务器执行了这个命令。然后你发送"将邮箱中的第二条消息移动到FOLDER_OUT",服务器告诉你"这个邮箱中只有一条消息,根本没有第二条消息可以移动"。

使用UID可以解决这个问题,因为UID是稳定的。无论你移动哪些其他消息,一条消息都会保持其UID不变。

英文:

Using UIDs is the correct answer here, but make sure you have UIDs to start with. "1,4,9" is valid both as a MSN set and as a UID set, but the two aren't interchangeable. You cannot ask for an MSN set from the server and then use it with UID commands.

The problem you see is easily explained if there are precisely two messages in the mailbox and you want to move the first of those to FOLDER_ERROR and the second to FOLDER_OUT. You send a command that says "move the first message in the mailbox to FOLDER_ERROR" and the server does that. Then you send "move the second message in the mailbox to FOLDER_OUT" and the server tells you "there's only one message in this mailbox, there is no second message that I could possibly move".

Using UIDs solves this because those are stable. A message keeps its UID no matter which other messages you move.

huangapple
  • 本文由 发表于 2022年6月2日 22:27:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/72477890.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定