ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

MailKit 快速上手:用 .NET 实现 SMTP 发送、POP3 与 IMAP 收件全流程

MailKit 快速上手:用 .NET 实现 SMTP 发送、POP3 与 IMAP 收件全流程 后端通信【免费下载链接】MailKitA cross-platform .NET library for IMAP, POP3, and SMTP.项目地址https://gitcode.com/gh_mirrors/ma/MailKit点击查看免费下载MailKit 是一个跨平台的 .NET 邮件客户端库基于 MimeKit 构建为 IMAP、POP3、SMTP 三种协议提供了完整的客户端实现源码见 MailKit/MailKit.csproj项目说明见 README.md。本文以官方 NuGet 入门指南 nuget/GettingStarted.md 为骨架完整演示从安装到发送邮件、收取邮件、以及使用 IMAP 的高级能力摘要抓取、按需下载 MIME 部件、标记/删除、搜索排序、文件夹导航的实战路径并结合仓库源码解释连接参数与底层实现读完即可将 MailKit 集成到自己的 .NET 应用中。一、安装 MailKit通过 NuGet 安装是最快的方式详见 README.mdInstall-Package MailKit在项目文件中也可以直接添加 PackageReferencePackageReference IncludeMailKit Version* /MailKit 使用SmtpClient、Pop3Client、ImapClient三个客户端类分别封装三种协议它们都位于MailKit.Net.*命名空间下。解析与构造邮件对象则依赖 MimeKitMimeMessage、TextPart等因此写代码时通常需要同时引入以下命名空间using MailKit; using MailKit.Net.Smtp; // 或 MailKit.Net.Pop3 / MailKit.Net.Imap using MimeKit;二、使用 SMTP 发送邮件发送邮件是 MailKit 最常用的场景之一。官方入门示例 nuget/GettingStarted.md 给出了一个最小可运行的控制台程序using System; using MailKit.Net.Smtp; using MailKit; using MimeKit; namespace TestClient { class Program { public static void Main (string[] args) { var message new MimeMessage (); message.From.Add (new MailboxAddress (Joey Tribbiani, joeyfriends.com)); message.To.Add (new MailboxAddress (Mrs. Chanandler Bong, chandlerfriends.com)); message.Subject How you doin?; message.Body new TextPart (plain) { Text Hey Chandler, I just wanted to let you know that Monica and I were going to go play some paintball, you in? -- Joey }; using (var client new SmtpClient ()) { client.Connect (smtp.friends.com, 587, false); // Note: only needed if the SMTP server requires authentication client.Authenticate (joey, password); client.Send (message); client.Disconnect (true); } } } }整个流程可拆解为四步构造MimeMessage通过From/To添加地址MailboxAddress的第一个参数是显示名第二个是邮箱地址设置Subject用TextPart作为纯文本正文。需要发送带附件、HTML 正文的邮件时可改用BodyBuilder参考 Documentation/Examples/BodyBuilder.cs。连接 SMTP 服务器Connect (host, port, useSsl)的第三个布尔参数表示是否直接使用 SSL/TLS 加密连接对应枚举SecureSocketOptions.SslOnConnect。认证可选只有服务器要求认证时才需要调用Authenticate。MailKit 支持 CRAM-MD5、DIGEST-MD5、LOGIN、NTLM、PLAIN、SCRAM-SHA-1/256/512 以及 OAUTHBEARER、XOAUTH2 等 SASL 机制见 README.md 与 MailKit/Security/ 目录下的SaslMechanism*实现。发送并断开Send完成后用Disconnect (true)退出true表示发送 QUIT 命令优雅关闭连接。更推荐的连接方式SecureSocketOptions入门示例中的Connect (host, port, bool useSsl)是历史遗留的简化重载。从源码看SmtpClient真正完整的方法是见 MailKit/Net/Smtp/SmtpClient.cspublic override void Connect (string host, int port 0, SecureSocketOptions options SecureSocketOptions.Auto, CancellationToken cancellationToken default)SecureSocketOptions枚举定义于 MailKit/Security/SecureSocketOptions.cs提供了更精细的加密控制选项行为None完全不使用 SSL/TLS 加密Auto默认值由 MailKit 自动决定若服务器不支持加密则继续明文连接SslOnConnect连接建立后立即升级为 SSL/TLS即传统 SMTPS 直连端口 465StartTls收到服务器问候与能力列表后强制 STARTTLS服务器不支持则抛出NotSupportedExceptionStartTlsWhenAvailable服务器支持 STARTTLS 才升级否则继续明文连接源码注释还说明了Auto模式的端口推断规则端口为 465 时默认使用SslOnConnect其他端口默认使用StartTlsWhenAvailable。因此对现代服务器更稳健的写法是await client.ConnectAsync (smtp.friends.com, 587, SecureSocketOptions.StartTls);MailKit 的所有 API 都提供了对应的*Async异步版本并且支持传入CancellationToken取消操作在服务器无响应时不会永久阻塞见 README.md。推荐在 ASP.NET Core、桌面 UI 等场景下优先使用异步 API。三、通过 POP3 收取邮件POP3 客户端的使用同样简单。入门文档给出了完整示例using System; using MailKit.Net.Pop3; using MailKit; using MimeKit; namespace TestClient { class Program { public static void Main (string[] args) { using (var client new Pop3Client ()) { client.Connect (pop.friends.com, 110, false); client.Authenticate (joey, password); for (int i 0; i client.Count; i) { var message client.GetMessage (i); Console.WriteLine (Subject: {0}, message.Subject); } client.Disconnect (true); } } } }关键点说明client.Count返回服务器上邮件的总数GetMessage (index)按序号从 0 开始下载完整邮件返回解析好的MimeMessage对象可直接读取Subject、Body等属性。与 IMAP 不同POP3 协议设计上是下载即删式的离线协议GetMessage会把整封邮件全部下载下来无法像 IMAP 那样只抓取摘要或单个 MIME 部件。除 SASL 机制外POP3 客户端还支持 APOP 和USER/PASS认证并支持 TOP、UIDL、STLS、UTF8 等扩展见 README.md。连接参数同样支持SecureSocketOptions加密收件可写为client.Connect (pop.friends.com, 995, SecureSocketOptions.SslOnConnect)。四、使用 IMAP读取收件箱MailKit 官方认为 IMAP 支持比 POP3 更重要nuget/GettingStarted.md。IMAP 是在线协议邮件保留在服务器上客户端可以按需读取。基础读取示例using System; using MailKit.Net.Imap; using MailKit.Search; using MailKit; using MimeKit; namespace TestClient { class Program { public static void Main (string[] args) { using (var client new ImapClient ()) { client.Connect (imap.friends.com, 993, true); client.Authenticate (joey, password); // The Inbox folder is always available on all IMAP servers... var inbox client.Inbox; inbox.Open (FolderAccess.ReadOnly); Console.WriteLine (Total messages: {0}, inbox.Count); Console.WriteLine (Recent messages: {0}, inbox.Recent); for (int i 0; i inbox.Count; i) { var message inbox.GetMessage (i); Console.WriteLine (Subject: {0}, message.Subject); } client.Disconnect (true); } } } }要点client.Inbox是所有 IMAP 服务器都保证存在的收件箱文件夹Open (FolderAccess.ReadOnly)以只读方式打开避免误改服务器状态。若需增删改应使用FolderAccess.ReadWrite。inbox.Count与inbox.Recent分别对应EXISTS与RECENT响应。IMAP 客户端支持非常广泛的扩展包括 IDLE实时推送、CONDSTORE/QRESYNC增量同步、SORT/THREAD、SPECIAL-USE、MOVE、METADATA、QUOTA 等完整清单见 README.md这也是 IMAP 客户端实现远比 POP3 复杂的原因。4.1 只抓取邮件摘要FetchIMAP 相对 POP3 的核心优势是可以在不下载整封邮件的情况下只获取邮件的摘要信息。使用Fetch系列方法可以为文件夹中任意范围的消息请求任意子集的摘要foreach (var summary in inbox.Fetch (0, -1, MessageSummaryItems.Full)) { Console.WriteLine ([summary] {0:D2}: {1}, summary.Index, summary.Envelope.Subject); }Fetch (start, end, items)中0, -1表示从第 0 条到最后一封包含全部消息。MessageSummaryItems.Full请求完整的信封信息也可以按需组合位标志例如MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure。对应的底层 FETCH 指令组装与解析实现在 MailKit/Net/Imap/ImapFolderFetch.cs 中单元测试见 UnitTests/Net/Imap/ImapFolderFetchTests.cs。4.2 按需下载单个 MIME 部件GetBodyPart摘要 正文结构BodyStructure的组合还有一个杀手级用途只下载邮件中的某一个部件而不是整封邮件。例如只取text/plain正文、只取text/html正文甚至只取某个图片附件foreach (var summary in inbox.Fetch (0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure)) { if (summary.TextBody ! null) { // this will download *just* the text/plain part var text inbox.GetBodyPart (summary.UniqueId, summary.TextBody); } if (summary.HtmlBody ! null) { // this will download *just* the text/html part var html inbox.GetBodyPart (summary.UniqueId, summary.HtmlBody); } // if youd rather grab, say, an image attachment... it might look something like this: if (summary.Body is BodyPartMultipart) { var multipart (BodyPartMultipart) summary.Body; var attachment multipart.BodyParts.OfTypeBodyPartBasic ().FirstOrDefault (x x.FileName logo.jpg); if (attachment ! null) { // this will download *just* the attachment var part inbox.GetBodyPart (summary.UniqueId, attachment); } } }summary.TextBody/summary.HtmlBody是BodyPart引用GetBodyPart只向服务器请求该部件对应的 BODY 段。多部分正文通过BodyPartMultipart.BodyParts遍历可用 LINQ 按FileName定位附件。更完整的用法可参考 Documentation/Examples/ImapBodyPartExamples.cs。4.3 设置消息标志Flags将邮件标记为已读\Seen是典型的标志操作。要设置标志只需要消息的 UID或序号以及它所属的文件夹folder.Store (uid, new StoreFlagsRequest (StoreAction.Add, MessageFlags.Seen) { Silent true });StoreAction.Add表示追加标志其他值见StoreAction枚举MailKit/StoreAction.cs如Remove清除标志、Replace整体替换。MessageFlags.Seen即 IMAP 的\Seen枚举中还包含Answered、Deleted、Flagged、Draft等标准标志。Silent true表示不要求服务器返回更新后的标志减少网络往返相关请求类型定义见 MailKit/StoreFlagsRequest.cs。4.4 删除邮件IMAP 删除邮件是两步操作先标记\Deleted再可选地执行 EXPUNGE 真正清除folder.Store (uid, new StoreFlagsRequest (StoreAction.Add, MessageFlags.Deleted) { Silent true }); folder.Expunge ();标记\Deleted的写法与标记\Seen完全一致。注意Expunge会不可恢复地删除所有被标记的消息如果只想删除指定消息可结合 UID 范围调用Expunge的重载。FolderAccess.ReadOnly模式下无法执行上述存储/删除操作。4.5 搜索与排序MailKit 提供了类型安全的查询构建器SearchQuery无需手写 IMAP 搜索字符串。下面的示例搜索2013-01-12 之后送达、主题包含 MailKit 且已读的邮件// lets search for all messages received after Jan 12, 2013 with MailKit in the subject... var query SearchQuery.DeliveredAfter (DateTime.Parse (2013-01-12)) .And (SearchQuery.SubjectContains (MailKit)).And (SearchQuery.Seen); foreach (var uid in inbox.Search (query)) { var message inbox.GetMessage (uid); Console.WriteLine ([match] {0}: {1}, uid, message.Subject); } // lets do the same search, but this time sort them in reverse arrival order var orderBy new [] { OrderBy.ReverseArrival }; foreach (var uid in inbox.Sort (query, orderBy)) { var message inbox.GetMessage (uid); Console.WriteLine ([match] {0}: {1}, uid, message.Subject); } // youll notice that the orderBy argument is an array... this is because you // can actually sort the search results based on multiple columns: orderBy new [] { OrderBy.ReverseArrival, OrderBy.Subject }; foreach (var uid in inbox.Sort (query, orderBy)) { var message inbox.GetMessage (uid); Console.WriteLine ([match] {0}: {1}, uid, message.Subject); }SearchQuery的完整查询谓词日期、标志、主题、正文、头部、UID、注解等见 MailKit/Search/SearchQuery.cs对应实现与测试在 UnitTests/Net/Imap/ImapFolderSearchTests.cs 与 UnitTests/Search/SearchQueryTests.cs。inbox.Sort (query, orderBy)依赖服务器支持 SORT/ESORT 扩展README.mdorderBy是数组支持按多列排序如先按到达时间倒序、再按主题。拿到 UID 后除了GetMessage下载整封邮件也可以配合前面的Fetch只取摘要信息或做标志、删除等后续操作。4.6 文件夹导航MailKit 可以列出个人命名空间下的顶层文件夹// Get the first personal namespace and list the toplevel folders under it. var personal client.GetFolder (client.PersonalNamespaces[0]); foreach (var folder in personal.GetSubfolders (false)) Console.WriteLine ([folder] {0}, folder.Name);如果服务器支持 SPECIAL-USE 或 XLISTGmail扩展可以直接拿到预定义的 All、Drafts、Flagged即 Important、Junk、Sent、Trash 等文件夹if ((client.Capabilities (ImapCapabilities.SpecialUse | ImapCapabilities.XList)) ! 0) { var drafts client.GetFolder (SpecialFolder.Drafts); } else { // maybe check the users preferences for the Drafts folder? }当服务器不支持上述扩展时就需要自行设计启发式规则来定位 Sent/Drafts/Trash 文件夹。入门文档给出了两种等价写法——循环匹配static string[] CommonSentFolderNames { Sent Items, Sent Mail, Sent Messages, /* maybe add some translated names */ }; static IFolder GetSentFolder (ImapClient client, CancellationToken cancellationToken) { var personal client.GetFolder (client.PersonalNamespaces[0]); foreach (var folder in personal.GetSubfolders (false, cancellationToken)) { foreach (var name in CommonSentFolderNames) { if (folder.Name name) return folder; } } return null; }以及用 LINQ 简化的版本static string[] CommonSentFolderNames { Sent Items, Sent Mail, Sent Messages, /* maybe add some translated names */ }; static IFolder GetSentFolder (ImapClient client, CancellationToken cancellationToken) { var personal client.GetFolder (client.PersonalNamespaces[0]); return personal.GetSubfolders (false, cancellationToken).FirstOrDefault (x CommonSentFolderNames.Contains (x.Name)); }另一种常见做法是允许用户在应用设置中自行指定 Sent/Drafts/Trash 等文件夹具体策略取决于产品需求。命名空间枚举client.PersonalNamespaces在连接后由 NAMESPACE 扩展填充MailKit/Net/Imap/ImapClient.cs。五、更多示例与参考资料代码示例集Documentation/Examples/ 目录收录了大量可运行片段包括 SmtpExamples.cs、Pop3Examples.cs、ImapExamples.cs、ImapBodyPartExamples.cs、BodyBuilder.cs、DkimExamples.cs、FilterExamples.cs 等。完整示例应用samples/ 下包含ImapClientDemo桌面版、ImapClientDemo.Android、ImapClientDemo.iOS以及 samples/ImapIdle/展示 IDLE 实时监控新邮件等多个可编译工程。常见问题FAQ.md 整理了高频问题其中包含如何开启协议日志ProtocolLog辅助排查。版本变更ReleaseNotes.md 记录了各版本的功能演进与破坏性变更升级前建议查阅。六、排障建议官方入门指南 nuget/GettingStarted.md 在Reporting Bugs一节给出了两条非常实用的排障经验同样适用于日常开发与邮件服务器交互异常时务必提供协议日志。MailKit 的ProtocolLogger见 MailKit/ProtocolLogger.cs可以记录客户端与服务器之间的原始命令/响应例如using (var client new SmtpClient (new ProtocolLogger (smtp.log))) { // ... }没有协议日志服务器行为几乎无法定位。更完整的说明见 FAQ.md 的 ProtocolLog 章节。报告异常时不要只贴Exception.Message还要附上Exception.StackTrace——仅凭 Message 往往无法判断错误发生在协议层、TLS 层还是 I/O 层。MailKit 抛出的SmtpCommandException、ImapCommandException、SmtpProtocolException、ImapProtocolException等异常类型定义在 MailKit/Net/ 各协议目录中StackTrace 能帮你区分是哪一类。通过本文的完整示例你已经可以用 MailKit 完成发信SMTP→ 收信POP3/IMAP→ 摘要抓取 → 按需下载 → 标记与删除 → 搜索排序 → 文件夹导航的全链路开发。所有代码均可直接复制到 .NET 项目中运行官方示例与源码测试UnitTests/提供了进一步的参考价值。赞分享后端通信【免费下载链接】MailKitA cross-platform .NET library for IMAP, POP3, and SMTP.项目地址https://gitcode.com/gh_mirrors/ma/MailKit点击查看免费下载相关推荐MailKit 跨平台邮件客户端库完全指南基于 .NET 的 SMTP、POP3 与 IMAP 开发实战MailKit 跨平台邮件客户端库完全指南基于 .NET 的 SMTP、POP3 与 IMAP 开发实战 MailKit 是构建于 MimeKit https后端通信深入解析MailKit掌握IMAP、POP3和SMTP邮件协议的终极指南深入解析MailKit掌握IMAP、POP3和SMTP邮件协议的终极指南 MailKit是一个功能强大的跨平台.NET邮件客户端库专门用于处理IMAP、PO后端通信MailKit 遥测指标完全指南Socket 与 SMTP/POP3/IMAP 客户端 OpenTelemetry 指标详解MailKit 遥测指标完全指南Socket 与 SMTP/POP3/IMAP 客户端 OpenTelemetry 指标详解 本指南以 MailKit 官方后端通信上一篇手机号反查QQ号还能行phone2qq免费工具完整上手指南下一篇VCClientRealtime Voice Changer实战指南AI 实时变声的模型生态、双架构部署与 REST API 集成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表