如何在TcpClient类中使用SSL

22
在 .NET framework 中有一个名为 TcpClient 的类,可以从电子邮件服务器检索电子邮件。该 TcpClient 类有 4 个构造函数与服务器连接,最多需要两个参数。它适用于那些不使用 SSL 的服务器。但是 Gmail 或许多其他电子邮件提供商使用 SSL 进行 IMAP。
我可以连接到 Gmail 服务器,但无法使用电子邮件 ID 和密码进行身份验证。
我用于验证用户的代码是:
public void AuthenticateUser(string username, string password)
{
    _imapSw.WriteLine("$ LOGIN " + username + " " + password);
    //_imapSw is a object of StreamWriter class
    _imapSw.Flush();
    Response();
}

但是这段代码无法登录。

那么当我需要使用SSL时,如何使用TcpClient类来检索电子邮件呢?

3个回答

48
你需要使用SslStreamTcpClient,然后使用SslStream来读取数据,而不是TcpClient。
类似于以下代码:
        TcpClient mail = new TcpClient();
        SslStream sslStream;

        mail.Connect("pop.gmail.com", 995);
        sslStream = new SslStream(mail.GetStream());

        sslStream.AuthenticateAsClient("pop.gmail.com");

        byte[] buffer = new byte[2048];
        StringBuilder messageData = new StringBuilder();
        int bytes = -1;
        do
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);

            Decoder decoder = Encoding.UTF8.GetDecoder();
            char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
            decoder.GetChars(buffer, 0, bytes, chars, 0);
            messageData.Append(chars);

            if (messageData.ToString().IndexOf("<EOF>") != -1)
            {
                break;
            }
        } while (bytes != 0);

        Console.Write(messageData.ToString());
        Console.ReadKey();

编辑

上述代码将简单地通过SSL连接到Gmail并输出测试消息的内容。要登录到Gmail帐户并发出命令,您需要执行类似以下内容的操作:

        TcpClient mail = new TcpClient();
        SslStream sslStream;
        int bytes = -1;

        mail.Connect("pop.gmail.com", 995);
        sslStream = new SslStream(mail.GetStream());

        sslStream.AuthenticateAsClient("pop.gmail.com");

        byte[] buffer = new byte[2048];
        // Read the stream to make sure we are connected
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

        //Send the users login details
        sslStream.Write(Encoding.ASCII.GetBytes("USER USER_EMAIL\r\n"));
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

        //Send the password                        
        sslStream.Write(Encoding.ASCII.GetBytes("PASS USER_PASSWORD\r\n"));
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

        // Get the first email 
        sslStream.Write(Encoding.ASCII.GetBytes("RETR 1\r\n"));
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

显然,没有所有的代码复制 :)


谢谢您的回答。但用户登录是我的主要问题。 - Md Kamruzzaman Sarker
非常感谢您的回答。它工作得很好。它使用POP协议访问邮件,但我想使用IMAP协议访问电子邮件。我已将邮件服务器名称和端口号更改为“imap.gmail.com”和“993”,但它并不起作用。怎么做? - Md Kamruzzaman Sarker
如果你是“服务器”而不是客户端,这会如何改变?我想使用 SSL 接收连接。 - Zapnologica
在循环的第二次迭代中,我在bytes = sslStream.Read(buffer, 0, buffer.Length)处卡住了,因为messageData.ToString()没有<EOF>。 - Dmitry Sokolov

3
为了针对IMAP和IMAP身份验证的问题定制最佳响应,您需要稍微修改代码以使用以下IMAP命令。为了进行调试,您可以在strOut被赋值后设置断点以查看服务器响应。
            pmOffice pmO = new pmOffice();
            pmO.GetpmOffice(3, false);

            TcpClient mail = new TcpClient();
            SslStream sslStream;
            int bytes = -1;

            mail.Connect("outlook.office365.com", 993);
            sslStream = new SslStream(mail.GetStream());

            sslStream.AuthenticateAsClient("outlook.office365.com");

            byte[] buffer = new byte[2048];
            // Read the stream to make sure we are connected
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

            //Send the users login details (insert your username & password in the following line
            sslStream.Write(Encoding.ASCII.GetBytes("$ LOGIN " + pmO.mailUsername + " " + pmO.mailPassword + "\r\n"));
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            string strOut = Encoding.ASCII.GetString(buffer, 0, bytes);

            // Get the status of the inbox (# of messages)
            sslStream.Write(Encoding.ASCII.GetBytes("$ STATUS INBOX (messages)\r\n"));
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            strOut = Encoding.ASCII.GetString(buffer, 0, bytes);

pmOffice是什么? - Dmitry Sokolov
pmOffice是我创建的一个类,用于从数据库中访问我的邮件设置和凭据。 - msleep01

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接