结论:必须用mailkit替代已过时的smtpclient;因后者不支持tls 1.2+、sni及现代认证,.net 6+起官方标记为废弃。关键配置包括:qq邮箱用smtp.qq.com+587+starttls、授权码认证、mailboxaddress构造收发件人、显式disconnect。

直接说结论:用 MailKit,别碰 SmtpClient —— 后者在 .NET 6+ 已标记为过时,且默认不支持现代 SMTP 认证和 TLS 1.2+ 协商,发不出去是常态,不是你的代码问题。
为什么 SmtpClient 在 2026 年基本不能用
它不是“写错了才失败”,而是设计上就卡在几个现实断点上:
-
SmtpClient的EnableSsl实际只支持旧式 STARTTLS 或硬编码 SSL 握手,遇到 QQ 邮箱、163、Gmail 等强制 TLS 1.2+ + SNI 的服务时,AuthenticationFailed或Unable to read data from the transport connection是高频错误 - 它无法显式控制 TLS 版本,.NET 运行时升级后(如从 .NET 5 升到 .NET 8),底层
SslStream行为变化会导致原来能发的代码突然中断 - 没有异步重试、连接池、凭证缓存等生产级能力,发批量邮件或高并发场景下容易夯住或抛
TimeoutException - 官方文档已明确标注:
SmtpClientis obsolete and will be removed in a future version
MailKit 发送邮件的最小可行配置
不是“装了就能发”,关键参数必须对齐邮箱服务商真实要求。以 QQ 邮箱为例(其他如 163、Outlook、Gmail 同理,只换域名和端口):
-
smtp.qq.com必须配587端口 +true(不是 465) -
Authenticate()第二个参数必须是「授权码」,不是 QQ 登录密码;且该授权码需在邮箱设置 → 账户 → “POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务” 中手动开启并生成 -
MimeMessage.From和To必须用MailboxAddress构造,不能直接传字符串,否则中文名会乱码或被拒 - 务必调用
client.Disconnect(true),否则连接不释放,发几封后就会卡在Service not available
示例片段:
var message = new MimeMessage();
message.From.Add(new MailboxAddress("张三", "zhangsan@qq.com"));
message.To.Add(new MailboxAddress("李四", "lisi@example.com"));
message.Subject = "测试";
message.Body = new TextPart("plain") { Text = "Hello" };
using (var client = new SmtpClient())
{
client.Connect("smtp.qq.com", 587, SecureSocketOptions.StartTls);
client.Authenticate("zhangsan@qq.com", "xxxxxx-xxxx-xxxx-xxxx"); // 授权码
client.Send(message);
client.Disconnect(true); // 关键
}
附件和 HTML 邮件怎么加才不丢内容
常见失效点不在逻辑,而在 MIME 结构误配:
- HTML 邮件必须用
MultipartMixed或MultipartAlternative包裹,直接设message.Body = new TextPart("html")会丢失样式和图片引用 - 附件路径必须存在且进程有读取权限;若用相对路径(如
"./files/report.pdf"),运行目录要和预期一致,否则抛FileNotFoundException - 带附件的 HTML 邮件,应使用
MultipartRelated:HTML 主体作为根 part,图片用ContentId引用,附件单独 add 到 multipart - 避免混用
Body和BodyBuilder——BodyBuilder是辅助类,一旦调用bodyBuilder.ToMessageBody(),就不要再手动赋值message.Body
最后提醒一个真·隐蔽坑
QQ、163 等国内邮箱对发信 IP 有行为风控:同一 IP 短时间发大量相同内容邮件,会被临时限频甚至拉黑。这不是代码问题,是策略限制。上线前务必用真实收件箱做单封测试,再逐步放开频率;别依赖本地开发机直连发——CI/CD 环境或云服务器的出口 IP 往往已被其他用户污染过。











