我正在研究imap sort extention的一个问题:
我的命令如下:
var query = "icône";
//byte[] bytes = Encoding.Default.GetBytes(query);
//query = Encoding.UTF8.GetString(bytes);
var command = "SORT (REVERSE ARRIVAL) UTF-8 " + "{" + query.Length + "}";
var imapAnswerString = client.Command(command);
imapAnswerString = client.Command(query);
我收到以下错误: IMAP命令中的BAD错误SORT:原子中的8位数据
我发现了这个: C# Imap search command with special characters like á,é
但我不知道如何准备我的代码以成功发送此请求。
答案 0 :(得分:2)
如果你想坚持使用MailSystem.NET,那么arnt给出的答案是正确的。
但是,正如我指出here(以下为方便起见),MailSystem.NET存在很多架构设计问题,使其无法使用。
如果您使用其他开源库,例如MailKit,则可以更轻松地完成此搜索查询:
var query = SearchQuery.BodyContains ("icône");
var orderBy = new OrderBy[] { OrderBy.ReverseArrival };
var results = folder.Search (query, orderBy);
希望有所帮助。
MailSystem.NET中的架构问题包括:
MailSystem.NET无法正确处理文字标记 - 发送它们(用于除APPEND之外的任何其他内容)或接收它们(用于除FETCH请求中的实际消息数据之外的任何内容)。作者似乎没有注意到,服务器可能会选择使用文字进行任何字符串响应。
这是什么意思?
这意味着服务器可以选择使用邮箱名称的文字来响应LIST命令。
这意味着BODYSTRUCTURE中的任何字段都可以是文字,并且不必像它们都假设的那样是带引号的字符串。
(以及......)
例如,MailSystem.NET也没有正确编码或引用邮箱名称:来自MailSystem.NET的示例:
public string RenameMailbox(string oldMailboxName, string newMailboxName)
{
string response = this.Command("rename \"" + oldMailboxName + "\" \"" + newMailboxName + "\"");
return response;
}
这值得Jean-Luc Picard 和 Will Riker面掌。这段代码只是盲目地在邮箱名称周围加上双引号。这至少有两个原因是错误的:
我能找到的大多数(全部?).NET IMAP客户端将服务器的整个响应读入1个大字符串,然后尝试使用正则表达式,IndexOf()和Substring()的某种组合来解析响应。更糟糕的是,它们中的大多数也是由开发人员编写的,他们不知道unicode字符计数(即string.Length)和八位字节(即 byte 计数)之间的区别,所以当他们尝试解析对消息的FETCH请求的响应,他们在解析" {}"之后执行此操作。响应的第一行中的值:
int startIndex = response.IndexOf ("}") + 3;
int endIndex = startIndex + octets;
string msg = response.Substring (startIndex, endIndex - startIndex);
MailSystem.NET开发人员显然得到了关于这不适用于国际邮件的错误报告,所以他们的#34;修复"是这样做的:
public string Body(int messageOrdinal)
{
this.ParentMailbox.SourceClient.SelectMailbox(this.ParentMailbox.Name);
string response = this.ParentMailbox.SourceClient.Command("fetch "+messageOrdinal.ToString()+" body", getFetchOptions());
return response.Substring(response.IndexOf("}")+3,response.LastIndexOf(" UID")-response.IndexOf("}")-7);
}
基本上,他们假设 UID键/值对将在消息之后,并将其用作无能为力的黑客行为。不幸的是,为现有的无能力增加更多的无能力只会增加无能,它实际上并没有解决它。
IMAP规范明确指出结果的顺序可能会有所不同,甚至可能不会出现相同的无标记响应。
不仅如此,他们的FETCH请求甚至不会从服务器请求UID值,因此服务器是否要返回它是不是!
<强> TL; DR 强>
如何评估IMAP客户端库
在评估IMAP客户端库实现时,您应该做的第一件事是查看它们如何解析响应。如果他们不使用实际的标记器,你可以直接告诉他们图书馆是由那些不知道他们在做什么的人写的。这是STAY AWAY最明确的警告标志。
库是否在中心位置(例如命令管道)处理未标记的(&#34; *&#34;)响应?或者它是否会像尝试一样做一些延迟,并在每个发送命令的方法中解析它(例如ImapClient.SelectFolder(),ImapClient.FetchMessage()等)?如果图书馆没有在中心位置处理它,可以正确处理这些未标记的响应并更新状态(并通知您重要的事情,如EXPUNGE&#39; s),请保留。
如果库将整个响应(或者甚至只是&#34;消息&#34;)读入System.String,请保持打开状态。
答案 1 :(得分:1)
你快到了。你的最终命令应该是
x sort (reverse arrival) utf-8 subject {6+}
icône
即。您只是缺少一个搜索词来描述IMAP服务器应该搜索icône的位置并对结果进行排序。还有许多其他搜索键,而不仅仅是主题。请参阅RFC3501第49页和后续页面。
修改:+
后需要6
才能将其作为单个命令发送(但要求服务器支持LITERAL+
扩展名)。如果服务器不支持LITERAL +,那么您需要将命令分解为多个段,如下所示:
C: a001 SORT (REVERSE ARRIVAL) UTF-8 SUBJECT {6}
S: + ok, whenever you are ready...
C: icône
S: ... <response goes here>
答案 2 :(得分:0)
感谢大家的回答。
基本上,MailSystem.net发送请求的方式(命令方法)是这个问题的关键,实际上是其他一些问题。
命令方法应更正如下:
首先,在向imap发送请求时,以下代码比原始代码效果更好:
//Convert stuff to have to right encoding in a char array
var myCommand = stamp + ((stamp.Length > 0) ? " " : "") + command + "\r\n";
var bytesUtf8 = Encoding.UTF8.GetBytes(myCommand);
var commandCharArray = Encoding.UTF8.GetString(bytesUtf8).ToCharArray();
#if !PocketPC
if (this._sslStream != null)
{
this._sslStream.Write(System.Text.Encoding.UTF8.GetBytes(commandCharArray));
}
else
{
base.GetStream().Write(System.Text.Encoding.UTF8.GetBytes(commandCharArray), 0, commandCharArray.Length);
}
#endif
#if PocketPC
base.GetStream().Write(System.Text.Encoding.UTF8.GetBytes(commandCharArray), 0, commandCharArray.Length);
#endif
然后,在同一方法中,为了避免一些死锁或错误的异常,改进有效性测试如下:
if (temp.StartsWith(stamp) || temp.ToLower().StartsWith("* " + command.Split(' ')[0].ToLower()) || (temp.StartsWith("+ ") && options.IsPlusCmdAllowed) || temp.Contains("BAD Error in IMAP command"))
{
lastline = temp;
break;
}
最后,如下所示更新退货:
if (lastline.StartsWith(stamp + " OK") || temp.ToLower().StartsWith("* " + command.Split(' ')[0].ToLower()) && !options.IsSecondCallCommand || temp.ToLower().StartsWith("* ") && options.IsSecondCallCommand && !temp.Contains("BAD") || temp.StartsWith("+ "))
return bufferString;
通过此更改,所有命令都可以正常工作,也可以使用双重调用命令。副作用比原始代码少。
这解决了我的大部分问题。