C# 发送邮件推荐使用 MailKit:因 .NET 6+ 已移除 SmtpClient 对用户名密码认证的支持,Gmail/Outlook 等服务商也禁用低安全性访问,必须改用 App Password 或 OAuth2;MailKit 支持 StartTls、App Password 和完整 MIME 结构,是目前最稳定方案。

直接说结论:C# 发送邮件不难,但用 SmtpClient 时默认已过时,.NET 6+ 必须改用 MailKit 或手动适配新 API;否则发不出、收不到、或被 Gmail/Outlook 拒绝登录。
为什么 SmtpClient 突然不工作了?
.NET Core 2.1 起,SmtpClient 被标记为 Obsolete;.NET 6+ 完全移除了对旧式凭据(如用户名密码直传)的支持。Gmail、Outlook 等主流服务商也已禁用“低安全性应用访问”,直接用账号密码会触发 AuthenticationFailed 错误。
- 常见错误信息:
535 Authentication Credentials Invalid、System.NotSupportedException: The SMTP server requires a secure connection - 即使配置了
EnableSsl = true和Port = 587,仍可能因未启用 OAuth2 或 App Password 而失败 -
SmtpClient不支持 OAuth2,而现代邮箱基本只认这个
用 MailKit 发 Gmail 邮件的最小可行代码
这是目前最稳定、兼容性最好、且文档清晰的方案。NuGet 安装:Install-Package MailKit。
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Your Name", "your@gmail.com"));
message.To.Add(new MailboxAddress("Recipient", "to@example.com"));
message.Subject = "Test from MailKit";
<p>message.Body = new TextPart("plain") {
Text = "Hello, this is a test email."
};</p><p>using var client = new SmtpClient();
client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
client.Authenticate("your@gmail.com", "your-app-password"); // 注意:不是账号密码!</p><p>client.Send(message);
client.Disconnect(true);
</p>
- Gmail 必须用
App Password:开启两步验证后,在 Google 账户安全页 生成,16位字母数字组合 - 不要用
gmail.com的普通密码,也不要用“应用专用密码”以外的任何凭据 - 若用企业 Gmail(Google Workspace),管理员需在管理控制台启用“允许用户使用应用专用密码”
发 Outlook/Hotmail 邮件要注意什么?
Outlook 使用 smtp-mail.outlook.com,但认证逻辑和 Gmail 不同——它仍接受传统密码(仅限部分旧账户),但更推荐统一走 App Password + OAuth2。实际中容易卡在端口与加密方式上:
- 必须用
Port = 587+SecureSocketOptions.StartTls;465+SSL在某些网络下会超时 - 如果收到
530 5.7.0 Must issue a STARTTLS command first,说明没调用client.Connect(..., SecureSocketOptions.StartTls) - Outlook 的 App Password 生成路径是:Microsoft 账户安全页 → “高级安全选项” → “应用密码”
附件、HTML 正文、抄送这些功能怎么加?
MailKit 的 API 是链式设计,加附件和 HTML 很直观,但关键点在于 MIME 结构不能错:
- HTML 正文要包裹在
MultipartMixed或MultipartAlternative中,否则 Outlook 可能只显示纯文本 - 附件用
message.Body = new Multipart("mixed") { ... },再把TextPart和MimePart(附件)都 Add 进去 - 抄送(CC)和密送(BCC)直接调用
message.Cc.Add(...)或message.Bcc.Add(...),注意它们和To是并列关系,不是子集 - 中文附件名要设置
ContentDisposition.Parameters.Add(new Parameter("filename*", "utf-8", "", "测试文件.pdf")),否则乱码
真正麻烦的从来不是“怎么发”,而是“为什么收件方看到的是乱码/无附件/被当垃圾邮件”。SMTP 协议本身很老,但邮箱服务商的反垃圾策略每天都在变——哪怕你代码完全正确,IP 被标记、域名没 SPF 记录、发信频率突增,都会让邮件进不了收件箱。这些不在代码里,但在生产环境里,比 SmtpClient 过时更致命。










