65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 构建您自己的邮件客户端

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.08/5 (9投票s)

2009 年 3 月 26 日

CPOL

4分钟阅读

viewsIcon

112238

这篇文章将带您一步一步地使用 C# 构建您自己的邮件客户端。

IMailPlus.zip

引言

此处代码根据知识共享许可协议编写,您可以从上方链接或下一个链接 IMailPlus.zip 下载项目。它受到了 Rodolfo Finochietti POP3 项目 的启发,我对其进行了重新设计、实现并添加了 SSL 支持,优化了设计,以便您可以轻松地在此基础上添加其他邮件客户端。下方是创建的演示应用程序的屏幕截图。

imailplusdemo

这篇帖子将一步一步地指导您使用 C# 构建自己的邮件客户端。首先,您需要了解用于检索电子邮件的协议。我将在此讨论 **POP3 协议**。POP3 协议是一个应用层互联网标准协议,与 IMAP4 一起,它们是目前最流行的两种电子邮件检索互联网标准协议。为了理解协议的工作原理,让我们来看一个(服务器 - 客户端)通信示例。首先,服务器正在等待来自任何客户端的连接。
S: <等待 TCP 端口 110 上的连接>
客户端与服务器建立 TCP 连接
C: <建立连接>
然后服务器响应 +OK Ready 状态
S: +OK POP3 server ready <1123.69123552@mail.ramymostafa.com>
然后我们使用用户名和密码进行身份验证
C: USER 用户名_在此
S: +OK send PASS C: PASS 密码
S: +OK Welcome.
C: LIST
S: +OK 2 messages (320 octets)
S: 1 120
S: 2 200
S: .
C: RETR 1
S: +OK 120 octets
S: <POP3 服务器发送消息 1>
S: .
C: DELE 1
S: +OK message 1 deleted
C: RETR 2
S: +OK 200 octets
S: <POP3 服务器发送消息 2>
QUIT 命令将从服务器中删除已检索的消息并退出。
C: QUIT
S: +OK dewey POP3 server signing off (maildrop empty) C: <关闭连接>
S: <等待下一个连接>

设计邮件客户端



imailpluslibrarydiagram

现在我们知道了 POP3 协议的工作原理,就可以开始构建我们的邮件客户端了。但在那之前,让我们讨论一下电子邮件消息的结构。
mailmessage 邮件消息包含
  • Header (头部),其中包括
    • Mime 类型
    • 接收日期
    • 主题
    • 改为
  • Body (正文),其中包括消息内容
    • HTML 消息
    • 文本消息
因此,基本上,邮件客户端应该首先连接到服务器,然后向服务器进行身份验证,接着开始与服务器交换协议消息,解析回复以提取消息数据或回复状态等。它还应该能够从服务器检索电子邮件,并解析消息以提取 MailMessage 信息。
email-client EmailClient 是一个抽象类,包含连接服务器所需的一些属性,如服务器用户名、密码、端口号,以及服务器是否使用 SSL 等。它还包含连接服务器和执行命令的方法,获取服务器响应字符串以及获取邮件列表。为了使用邮件客户端,您应该创建一个继承自 EmailClient 的类,该类代表了 MailClient 协议。在本示例中,我实现了 POPEmailClient,您可以在下方找到它的成员。
popmailclient POPEmailClient 重载了 Connect 方法以使用 POP3 命令进行连接,它还重载了 CreateCommand 方法以使用提供的命令参数创建 POP3 命令格式。Disconnect 方法用于断开与服务器的连接,如果您不想在服务器上保留电子邮件副本,则调用此方法。如果您想保留电子邮件副本,则不应调用此方法。该类还重写了 GetMailList 方法以从 POP3 服务器检索电子邮件,并将其解析为 POP3Messages 列表。

实现邮件客户端

使用给定的用户名、密码和服务器连接客户端到服务器,它将邮件服务器域名、邮件账户用户名和密码作为参数。
        public override void Connect(string server, string UserName, string Password)
{
       try
       {
           if (_isConnected)
           {
               return;
           }
           if (!UseSSL)
           {
               Connect(server, PortNumber);
               string response = Response();
               if (!response.Trim().StartsWith("+OK"))
               {
                    //TODO: Raise Error Event
               }
               else
               {
                   ExecuteCommand("USER", UserName);
                   ExecuteCommand("PASS", Password);
               }
               _isConnected = true;
           }
           else
           {
               byte[] bts;
               int res;
               string responseString = "";
               ResponseList.Clear();
               Connect(server, PortNumber);
               inStream = new SslStream(this.GetStream(), false,
                  new RemoteCertificateValidationCallback(ValidateServerCertificate),
                   new LocalCertificateSelectionCallback(SelectLocalCertificate));
               inStream.AuthenticateAsClient(server);
               bts = new byte[1024];
               res = inStream.Read(bts, 0, bts.Length);
               ResponseList.Add(Encoding.ASCII.GetString(bts, 0, res));
               responseString = ExecuteCommand("USER", UserName);
               ResponseList.Add(responseString);
               responseString = ExecuteCommand("PASS", Password);
               ResponseList.Add(responseString);
               if (!responseString.Trim().StartsWith("+OK"))
               {
                   //TODO: Raise Error Event
               }
               else
                   _isConnected = true;
            }
        }
        catch (Exception ex)
        {
            //TODO: Raise Error Event
        }
}
GetMailList 方法首先执行 List 命令,然后从响应字符串中检索 MetaMessageInfo。这里响应字符串被解析以检索服务器上电子邮件的元信息,例如消息数量和消息长度。
 List result = new List();
 string responseString = ExecuteCommand("LIST");
MetaMessageInfo info = new MetaMessageInfo(MailClientType.POP3,responseString);
这里我们进行循环检索消息,直到检索到所有消息。使用 POPMessage 构造函数中的消息数量,它会从字符串中提取所有消息信息来填充其属性。
for (int i = 1; i <= info.NumberOfMessages; i++)
{
    responseString = ExecuteCommand("RETR", i.ToString(), true);
    POPMessage message = new POPMessage(responseString);
    message.Number = i.ToString();
    message.Retrieved = true;
    if (message.MessageBoundaryId != null)
         result.Add(message);
}
用于解析响应字符串以检索电子邮件信息的函数是 LoadMethod。
public override void Load(string messageString)
{
    string message = messageString.Replace("+OK message follows", "");
    Message = message;
    string messageIdPure = MessageBoundaryId;
    //the start of the message body starts from MessageBoundaryId ex --- ID --- Here I extract the Message body from the complete
   //response string
    int bodyIndex = message.IndexOf("--" + messageIdPure, StringComparison.CurrentCultureIgnoreCase);
    int messageLength = message.Length - bodyIndex;
    if (bodyIndex < 0)
        return;
    string bodyString = message.Substring(bodyIndex, messageLength);
    string[] splitMessageOptions = new string[1];
    splitMessageOptions[0] = "--" + messageIdPure;
    //Here I Split with the message boundary Id to seperate the Text and HTML Messages
    string[] messages = bodyString.Split(splitMessageOptions, StringSplitOptions.RemoveEmptyEntries);
    //The Get Message Body Method retrieves the HTML, and Text Messages from the messages array
    GetMessageBody(messages);
}
要提取头部属性,我使用
_from = GetHeaderValue(EmailHeaders.From);
其中 EmailHeaders.From 是一个包含头部的枚举器,GetHeaderValue 方法从完整的消息字符串中提取所需的头部值。

IMailPlusLibrary 的使用

使用该库很简单,您只需要执行以下代码:
POPEmailClient popClient = new POPEmailClient();
popClient.UseSSL = account.UseSSL;
popClient.PortNumber = Convert.ToInt32(account.PortNumber);
popClient.Connect(account.Server, account.UserName, account.Password);
account.CurrentAccountMails = popClient.GetMailList();

分享您的想法

最后,我希望这个项目能对您有所帮助。如果您对代码有任何不理解的地方,请随时与我联系。您会发现该库的代码已进行完整的 XML 文档注释。另外,如果您有任何很棒的想法或更新,请在此分享您的想法。
© . All rights reserved.