前言
.NET Framework 2.0+ 內建 `System.Net.Mail` 命名空間,提供 `SmtpClient`、`MailMessage`、`Attachment` 等類別,無需註冊 COM 元件、支援 SSL/TLS、非同步發送、標準 MIME 編碼。本文整理郵件發送核心類別、封裝通用發送元件、附件處理、SSL 設定、異步模式與常見問題排查。
核心類別速查
| 類別 | 用途 |
| MailMessage | 郵件實體:From/To/CC/Bcc/Subject/Body/Attachments/Priority/Encoding |
| SmtpClient | SMTP 傳輸客戶端:Host/Port/Credentials/EnableSsl/Timeout/Send/SendAsync |
| Attachment | 附件:檔案路徑/串流、ContentType/ContentDisposition/NameEncoding |
| MailAddress | 郵件地址:Address/DisplayName/Encoding |
| AlternateView | 替代檢視:純文字/HTML 多部分郵件 |
1. 基本發送 (同步)
using System.Net;
using System.Net.Mail;
public void SendBasic()
{
using (var msg = new MailMessage())
{
msg.From = new MailAddress("sender@domain.com", "發件人");
msg.To.Add(new MailAddress("receiver@domain.com", "收件人"));
msg.Subject = "測試主旨";
msg.Body = "HTML 內容
";
msg.IsBodyHtml = true;
msg.BodyEncoding = Encoding.UTF8;
msg.SubjectEncoding = Encoding.UTF8;
msg.Priority = MailPriority.Normal;
using (var client = new SmtpClient("smtp.domain.com", 587))
{
client.Credentials = new NetworkCredential("user", "pwd");
client.EnableSsl = true; // STARTTLS (587) 或 Implicit SSL (465)
client.Timeout = 30000;
client.Send(msg);
}
}
}
2. 封裝通用發送元件
public class MailService
{
private readonly string _host;
private readonly int _port;
private readonly string _user;
private readonly string _pass;
private readonly bool _ssl;
private readonly string _fromAddr;
private readonly string _fromName;
public MailService(string host, int port, string user, string pass, bool ssl, string fromAddr, string fromName)
{
_host = host; _port = port; _user = user; _pass = pass; _ssl = ssl; _fromAddr = fromAddr; _fromName = fromName;
}
public bool Send(string to, string subject, string htmlBody,
IEnumerable cc = null, IEnumerable bcc = null,
IEnumerable attachments = null, string replyTo = null)
{
try
{
using (var msg = new MailMessage())
{
msg.From = new MailAddress(_fromAddr, _fromName, Encoding.UTF8);
msg.To.Add(new MailAddress(to));
if (cc != null) foreach (var c in cc) msg.CC.Add(new MailAddress(c));
if (bcc != null) foreach (var b in bcc) msg.Bcc.Add(new MailAddress(b));
if (!string.IsNullOrEmpty(replyTo)) msg.ReplyToList.Add(new MailAddress(replyTo));
msg.Subject = subject;
msg.SubjectEncoding = Encoding.UTF8;
msg.Body = htmlBody;
msg.BodyEncoding = Encoding.UTF8;
msg.IsBodyHtml = true;
msg.Priority = MailPriority.Normal;
if (attachments != null) foreach (var a in attachments) msg.Attachments.Add(a);
using (var client = new SmtpClient(_host, _port))
{
client.Credentials = new NetworkCredential(_user, _pass);
client.EnableSsl = _ssl;
client.Send(msg);
}
}
return true;
}
catch (Exception ex)
{
// 記錄 Log
return false;
}
}
// 附件建立輔助
public static Attachment CreateAttachment(string filePath, string mimeType = null)
{
var att = new Attachment(filePath);
if (!string.IsNullOrEmpty(mimeType)) att.ContentType = new ContentType(mimeType);
// 中文檔名 RFC 2231 編碼 (System.Net.Mail 4.5+ 自動處理)
return att;
}
}
3. 附件中文檔名正確編碼 (.NET 4.5+)
// .NET 4.5+ 自動使用 RFC 2231 (filename*=UTF-8'')
var att = new Attachment(@"C:\報表.xlsx");
// 手動指定 (舊版或特殊需求)
att.ContentDisposition.FileName = "報表.xlsx"; // 自動編碼
att.ContentDisposition.FileNameStar = "UTF-8''" + Uri.EscapeDataString("報表.xlsx"); // 明確指定
4. 異步發送 (不阻塞 UI/執行緒)
public async Task SendAsync(string to, string subject, string htmlBody,
IEnumerable attachments = null)
{
using (var msg = new MailMessage())
{
msg.From = new MailAddress(_fromAddr, _fromName, Encoding.UTF8);
msg.To.Add(new MailAddress(to));
msg.Subject = subject;
msg.SubjectEncoding = Encoding.UTF8;
msg.Body = htmlBody;
msg.BodyEncoding = Encoding.UTF8;
msg.IsBodyHtml = true;
if (attachments != null) foreach (var a in attachments) msg.Attachments.Add(a);
using (var client = new SmtpClient(_host, _port))
{
client.Credentials = new NetworkCredential(_user, _pass);
client.EnableSsl = _ssl;
// 事件式非同步 (舊版) 或 Task 包裝
await client.SendMailAsync(msg); // .NET 4.5+
}
}
return true;
}
5. 常見 SMTP 設定對照表
| 提供者 | SMTP Host | Port | SSL 模式 |
| Gmail | smtp.gmail.com | 587 | STARTTLS (EnableSsl=true) |
| Outlook/Office365 | smtp.office365.com | 587 | STARTTLS |
| 163/126 | smtp.163.com | 465 / 587 | Implicit SSL (465) / STARTTLS (587) |
| QQ 企業郵箱 | smtp.exmail.qq.com | 465 | Implicit SSL |
| 本機 IIS SMTP | localhost | 25 | 無 (內網常用) |
6. 常見錯誤與排查
| 錯誤 | 原因 | 解決 |
| 5.7.1 Unable to relay | SMTP 未授權中繼 | 設定 SMTP 允許該 IP 中繼、或使用認證帳號 |
| The SMTP server requires a secure connection | 未啟用 SSL | `EnableSsl=true`、確認 Port (465/587) |
| Authentication failed | 帳號/密碼錯誤、未開啟 SMTP 服務、需應用程式專用密碼 | 檢查郵件商設定 (Gmail 需開啟「低安全性應用」或使用 App Password) |
| Timeout | 防火牆阻擋、Port 錯誤、網路不通 | `telnet smtp.host port` 測試連通性、調整 `client.Timeout` |
| 附件檔名亂碼 | 舊版 .NET 編碼不標準 | 升級 .NET 4.5+、或手動設定 `ContentDisposition.FileNameStar` |
7. 本機 IIS SMTP 虛擬伺服器快速設定
- 「伺服器管理員」→ 新增功能 → SMTP Server。
- IIS 6.0 管理器 → SMTP 虛擬伺服器 → 屬性 → 「存取」→ 「中繼限制」→ 新增本機 IP (127.0.0.1 / 伺服器 IP)。
- 「傳遞」→ 「輸出安全性」→ 匿名存取 (內網) 或基本認證。
- 防火牆開放 TCP 25/587/465。
總結
`System.Net.Mail` 是 ASP.NET 發送郵件的標準方式:無 COM 依賴、支援 SSL/TLS、異步、標準 MIME 編碼。封裝 `MailService` 統一管理認證、編碼、附件建立,即可滿足絕大多數業務場景。避免使用已停止維護的 JMail/CDO 元件,降低部署與相容性風險。