C#中POP3客户端无法实时获取新邮件的解决方案咨询
问题:无法获取程序运行期间收到的最新邮件
我用EAGetMail库在C#里开发邮件获取程序,目前能正常获取程序启动前的邮件,但无法获取程序运行期间收到的新邮件,尝试重启SSL连接或客户端也没用。相关代码如下:
using EAGetMail; using System; using System.Globalization; using System.IO; namespace PopServer { class Program { static string _generateFileName(int sequence) { DateTime currentDateTime = DateTime.Now; return string.Format("{0}-{1:000}-{2:000}.eml", currentDateTime.ToString("yyyyMMddHHmmss", new CultureInfo("en-US")), currentDateTime.Millisecond, sequence); } static void Main(string[] args) { try { string localInbox = string.Format("{0}\\inbox", Directory.GetCurrentDirectory()); if (!Directory.Exists(localInbox)) { Directory.CreateDirectory(localInbox); } MailServer oServer = new MailServer("popserver.com", "username@mail.com", "password", ServerProtocol.Pop3); oServer.SSLConnection = true; oServer.Port = 995; MailClient oClient = new MailClient("TryIt"); oClient.Connect(oServer); MailInfo[] infos = oClient.GetMailInfos(); Console.WriteLine("Total {0} email(s)\r\n", infos.Length); //我曾尝试利用SSL连接让程序更新邮件,但它仅能获取程序启动前的邮件 while (oServer.SSLConnection) { for (int i = 0; i < infos.Length; i++) { MailInfo info = infos[i]; Console.WriteLine("Index: {0}; Size: {1}; UIDL: {2}", info.Index, info.Size, info.UIDL); Mail oMail = oClient.GetMail(info); Console.WriteLine("From: {0}", oMail.From.ToString()); Console.WriteLine("Subject: {0}\r\n", oMail.Subject); Console.WriteLine("Body: {0}\r\n", oMail.TextBody); string fileName = _generateFileName(i + 1); string fullPath = string.Format("{0}\\{1}", localInbox, fileName); oMail.SaveAs(fullPath, true); //删除已读邮件 //oClient.Delete(info); } } oClient.Quit(); Console.WriteLine("Completed!"); } catch (Exception ep) { Console.WriteLine(ep.Message); } } } }
核心原因
你的代码存在两个关键问题:
MailInfo[] infos = oClient.GetMailInfos();仅在程序启动时执行一次,后续循环只会反复处理这批旧邮件,从未重新从服务器拉取新邮件列表。while (oServer.SSLConnection)是无效的循环条件——SSL连接状态不会自动变更,导致程序陷入死循环,一直重复处理初始邮件。
解决思路与方案
1. 定时轮询拉取新邮件
将获取邮件列表的逻辑放入循环内部,每隔固定时间重新调用GetMailInfos(),同时用**UIDL(邮件唯一标识符)**记录已下载的邮件,避免重复处理。
2. 修正循环逻辑
把死循环改为带时间间隔的轮询,比如每隔30秒检查一次新邮件,减少资源占用。
修改后的示例代码
using EAGetMail; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading; namespace PopServer { class Program { // 记录已下载的邮件UIDL,避免重复下载 static HashSet<string> _downloadedUids = new HashSet<string>(); static string _generateFileName(int sequence) { DateTime currentDateTime = DateTime.Now; return string.Format("{0}-{1:000}-{2:000}.eml", currentDateTime.ToString("yyyyMMddHHmmss", new CultureInfo("en-US")), currentDateTime.Millisecond, sequence); } static void Main(string[] args) { try { string localInbox = Path.Combine(Directory.GetCurrentDirectory(), "inbox"); if (!Directory.Exists(localInbox)) { Directory.CreateDirectory(localInbox); } MailServer oServer = new MailServer("popserver.com", "username@mail.com", "password", ServerProtocol.Pop3); oServer.SSLConnection = true; oServer.Port = 995; MailClient oClient = new MailClient("TryIt"); oClient.Connect(oServer); // 初始化已下载邮件的UIDL列表 MailInfo[] initialInfos = oClient.GetMailInfos(); foreach (var info in initialInfos) { _downloadedUids.Add(info.UIDL); } Console.WriteLine("初始邮件数量:{0}\r\n", initialInfos.Length); // 定时轮询新邮件,间隔30秒 while (true) { MailInfo[] latestInfos = oClient.GetMailInfos(); int newMailCount = 0; foreach (var info in latestInfos) { // 只处理未下载过的邮件 if (!_downloadedUids.Contains(info.UIDL)) { newMailCount++; Console.WriteLine("新邮件 - Index: {0}; UIDL: {1}", info.Index, info.UIDL); Mail oMail = oClient.GetMail(info); Console.WriteLine("发件人: {0}", oMail.From.ToString()); Console.WriteLine("主题: {0}\r\n", oMail.Subject); Console.WriteLine("内容: {0}\r\n", oMail.TextBody); string fileName = _generateFileName(newMailCount); string fullPath = Path.Combine(localInbox, fileName); oMail.SaveAs(fullPath, true); // 标记为已下载 _downloadedUids.Add(info.UIDL); } } if (newMailCount > 0) { Console.WriteLine("本次新增邮件:{0}封\r\n", newMailCount); } else { Console.WriteLine("无新邮件,30秒后重试...\r\n"); } // 等待30秒后再次检查 Thread.Sleep(30000); } // 注:以上为死循环,实际项目需添加退出逻辑,此处Quit不会执行 // oClient.Quit(); // Console.WriteLine("Completed!"); } catch (Exception ep) { Console.WriteLine(ep.Message); } } } }
额外说明
- POP3协议限制:POP3是拉取式协议,无推送机制,只能通过轮询获取新邮件。若需更高实时性,建议改用IMAP协议(EAGetMail支持IMAP),IMAP可保持连接并接收服务器的新邮件通知。
- 连接稳定性:长时间保持POP3连接可能被服务器断开,建议每次轮询后断开连接,下次轮询时重新连接,或在捕获连接异常时自动重连。
- 资源优化:轮询间隔不要过短,根据需求设置10-60秒的合理间隔,避免给服务器和本地程序造成不必要的压力。
内容的提问来源于stack exchange,提问作者Shawn_Medinsky
相关产品推荐
相关产品推荐

