2

背景:我们有一个用 编写的内部 Intranet 系统- 服务器没有安装(在 php 中看到了一些漂亮的解决方案,例如这样,我们不能真正使用这些。) - 我们需要显示给我们的用户在他们的 imap 邮箱中有多少未读邮件。他们的 imap 邮箱内部托管在运行 postfix 和 dovecot imap 的 linux 机器上。

我的问题: 如何通过 .net(vb 或 c#)中的 Dovecot Imap 连接到 Postfix 邮件系统并确定未读邮件的数量?

我已经尝试过: 我们使用了Limilabs 邮件 dll和以下内容:

Imports System.Net.Security
Imports System
Imports Limilabs.Mail
Imports Limilabs.Client.IMAP
Imports Limilabs.Client

Function RetrieveUnread(_server, _user, _password)
    Using imap As New Limilabs.Client.IMAP.Imap
        '#### Handler needed because of self signed certificates
        RetrieveUnread = vbNull
        AddHandler imap.ServerCertificateValidate, AddressOf ValidateCertificate
        imap.ConnectSSL(_server)
        Try
            imap.Login(_user, _password)
        Catch ex As Exception
            RetrieveUnread = "Failed to login"
        End Try
        If CStr(RetrieveUnread) <> "Failed to login" Then
            imap.SelectInbox()
            Dim uids As List(Of Long) = imap.Search(Flag.Unseen)        'Find all unseen messages.
            'Console.WriteLine("Number of unseen messages is: " & CStr(uids.Count))
            RetrieveUnread = CStr(uids.Count)
        End If
        imap.Close()
    End Using
End Function

Private Sub ValidateCertificate(ByVal sender As Object, ByVal e As ServerCertificateValidateEventArgs)
    Const ignoredErrors As SslPolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors Or SslPolicyErrors.RemoteCertificateNameMismatch        ' name mismatch
    Dim nameOnCertificate As String = e.Certificate.Subject
    If (e.SslPolicyErrors And Not ignoredErrors) = SslPolicyErrors.None Then
        e.IsValid = True
        Return
    End If
    e.IsValid = False
End Sub

然而,虽然这种方法有效,但这种方法依赖于第三方,如果许可没有到位/不是最新的并且对于我们需要做的事情来说过于臃肿,DLL 将失败。我们只是好奇这是否可以在本机 .net 代码中完成。

4

1 回答 1

2

您不需要第 3 方 dll;一个简单的TcpClient就行了。

您可以将正确的 IMAP 命令发送到您的服务器,并使用正则表达式解析结果。


LINQPad 就绪示例:

Sub Main()
    Dim client = New System.Net.Sockets.TcpClient("hostname", 143)
    Using s = client.GetStream(), 
        reader = New StreamReader(s),
        writer = New StreamWriter(s)

            Dim send As Action(Of String) = Sub(command) 
                writer.WriteLine(command)
                writer.Flush()
            End Sub

            Dim recieve As Func(Of String, String) = Function(tag) 
                Dim response As String
                Dim str As String = ""
                response = reader.ReadLine()
                While response IsNot Nothing
                    str += response
                    If response.StartsWith(tag, StringComparison.Ordinal) Then
                        Exit While
                    End If
                    response = reader.ReadLine()
                End While
                Return str
            End Function

            send("a login username password"): recieve("a")
            send("b select inbox"): recieve("b")

            send("b2 SEARCH UNSEEN")
            Dim b2response = recieve("b2")
            Dim items = Regex.Match(b2response, "SEARCH (.*) OK").Groups(1).Value.Split(" "c)
            Console.WriteLine("Unread items: " + items.Count().ToString())

            send("c logout"): recieve("c")
    End Using
End Sub

void Main()
{
    var client = new System.Net.Sockets.TcpClient("hostname", 143);
    using (var s = client.GetStream())
    using (var reader = new StreamReader(s))
    using (var writer = new StreamWriter(s))
    {
        Action<string> send = (command) => 
        {
            writer.WriteLine(command);
            writer.Flush();
        };

        Func<String, String> recieve = (tag) =>
        {
            string response;
            string str="";
            while ((response = reader.ReadLine()) != null ) 
            {
                str+=response;
                if (response.StartsWith(tag, StringComparison.Ordinal))
                    break;
            }
            return str;
        };

        send("a login username password"); recieve("a");
        send("b select inbox"); recieve("b");

        send("b2 SEARCH UNSEEN");
        var b2response = recieve("b2");
        var items = Regex.Match(b2response, @"SEARCH (.*) OK").Groups[1].Value.Split(' ');
        Console.WriteLine("Unread items: " + items.Count().ToString());

        send("c logout"); recieve("c");
    }
}

如果要使用 SSL,则必须先将流包装s在 an 中SslStream并调用AuthenticateAsClient(并且可能使用端口 993)。

于 2012-10-04T10:48:27.563 回答