根本原因是attachment未正确绑定到mailmessage.attachments集合或附件流被提前释放;常见表现为附件为空、损坏或缺失,需确保流在send()完成前保持打开,并显式添加每个附件。

SmtpClient 发送带附件邮件时为什么收件人收不到附件?
根本原因通常是 Attachment 对象未正确绑定到 MailMessage 的 Attachments 集合,或附件流被提前释放。常见表现是邮件正文正常送达,但附件为空、损坏,或根本没出现在邮件里。
- 务必用
new Attachment(filePath)或new Attachment(stream, fileName)构造,不要直接传FileStream而不指定文件名 —— 某些邮箱(如 Outlook Web)会因缺失Content-Disposition中的filename字段而忽略附件 - 如果用流构造附件,确保该流在
client.Send()完成前**未被关闭或释放**;推荐用using包裹附件创建过程,或手动调用attachment.Dispose()在发送后 - 多个附件要逐个
message.Attachments.Add(),不能只加最后一个
如何配置 SmtpClient 支持 TLS 1.2 并绕过证书验证(开发调试用)
.NET Framework 4.6+ 默认启用 TLS 1.2,但旧 SMTP 服务(如某些内网 Exchange 或测试 SMTP 服务器)可能只支持 TLS 1.0 或返回自签名证书,导致 SmtpException: The remote certificate is invalid。
- 发送前强制设置协议:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12(注意:全局生效,生产环境慎用) - 跳过证书验证(仅限测试):
ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, errors) => true - 更安全的做法是改用
MailKit库 —— 它对证书和 TLS 控制更细粒度,且SmtpClient在 .NET Core 5+ 已标记为 [Obsolete]
附件路径含中文或空格时为什么报“找不到文件”?
错误信息通常是 System.IO.FileNotFoundException,即使文件明明存在。这不是编码问题,而是 Attachment 构造函数内部调用 File.OpenRead() 时对路径做了静默处理失败。
- 用绝对路径代替相对路径:
Path.GetFullPath("data/报表.xlsx") - 检查路径中是否含非法字符(如
| ? *),Windows 文件系统不允许这些作为文件名 - 若路径来自用户输入,先用
Uri.UnescapeDataString()解码(比如 URL 编码过的路径),再校验是否存在:File.Exists(path)
Send() 同步阻塞导致界面卡死或超时怎么办?
桌面应用(WinForms/WPF)中直接调用 client.Send() 会阻塞 UI 线程;Web 应用中则可能拖垮请求线程池。默认超时是 100 秒,但很多邮件网关实际响应远慢于此。
- 改用异步方法:
await client.SendMailAsync(message)(需SmtpClient实例未被跨线程复用) - 显式设置超时:
client.Timeout = 30000(单位毫秒),避免挂起过久 - 注意:.NET 6+ 中
SmtpClient不再支持SendAsync,必须迁移到MailKit或使用Task.Run(() => client.Send(...))包装(仅限简单场景)











