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

这篇帖子将一步一步地指导您使用 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: <等待下一个连接>
现在我们知道了 POP3 协议的工作原理,就可以开始构建我们的邮件客户端了。但在那之前,让我们讨论一下电子邮件消息的结构。
因此,基本上,邮件客户端应该首先连接到服务器,然后向服务器进行身份验证,接着开始与服务器交换协议消息,解析回复以提取消息数据或回复状态等。它还应该能够从服务器检索电子邮件,并解析消息以提取 MailMessage 信息。
引言
此处代码根据知识共享许可协议编写,您可以从上方链接或下一个链接 IMailPlus.zip 下载项目。它受到了 Rodolfo Finochietti POP3 项目 的启发,我对其进行了重新设计、实现并添加了 SSL 支持,优化了设计,以便您可以轻松地在此基础上添加其他邮件客户端。下方是创建的演示应用程序的屏幕截图。
这篇帖子将一步一步地指导您使用 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: <等待下一个连接>
设计邮件客户端

现在我们知道了 POP3 协议的工作原理,就可以开始构建我们的邮件客户端了。但在那之前,让我们讨论一下电子邮件消息的结构。
![]() |
邮件消息包含
|
实现邮件客户端
使用给定的用户名、密码和服务器连接客户端到服务器,它将邮件服务器域名、邮件账户用户名和密码作为参数。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();