.NET Framework 內建 System.Net.Mail.SmtpClient 已支援 SSL/TLS 與驗證,但在某些舊版環境(.NET 1.x)、特殊伺服器需求、或教學理解協議細節時,手工實作 SMTP 交互流程極具價值。本文解析一個支援 ESMTP AUTH LOGIN 驗證、Base64 編碼、HTML/純文字郵件、附件/抄送/密件副本 的完整郵件發送元件原始碼。
TcpClient 建立 TCP 連線至 SMTP 伺服器(預設埠 25/587)NetworkStream 進行位元組讀寫SendCommand → RecvResponse → Dialog 驗證回應碼RightCodeHT(成功碼)、ErrCodeHT(錯誤碼說明)HELO(無驗證)與 EHLO + AUTH LOGIN(ESMTP 驗證)private string RecvResponse()
{
byte[] buffer = new byte[1024];
int size;
try { size = ns.Read(buffer, 0, buffer.Length); }
catch { errmsg = "網路連線錯誤"; return "false"; }
if (size == 0) return "";
string resp = Encoding.Default.GetString(buffer, 0, size);
logs += resp;
return resp;
}
private bool Dialog(string cmd, string errstr)
{
if (string.IsNullOrWhiteSpace(cmd)) return true;
if (!SendCommand(cmd)) return false;
string resp = RecvResponse();
if (resp == "false") return false;
string code = resp.Substring(0, 3);
if (RightCodeHT[code] != null) return true;
errmsg += code + ErrCodeHT[code] + Environment.NewLine + errstr;
return false;
}
private bool Dialog(string[] cmds, string errstr)
{
foreach (string cmd in cmds)
if (!Dialog(cmd, "")) { errmsg += Environment.NewLine + errstr; return false; }
return true;
}
private bool SendEmail()
{
// 1. 連線
tc = new TcpClient(mailserver, mailserverport);
ns = tc.GetStream();
if (RightCodeHT[RecvResponse().Substring(0,3)] == null) { errmsg="連線失敗"; return false; }
// 2. 驗證
if (ESmtp)
{
string[] auth = {
"EHLO " + mailserver + crlf,
"AUTH LOGIN" + crlf,
Base64Encode(username) + crlf,
Base64Encode(password) + crlf
};
if (!Dialog(auth, "SMTP 驗證失敗")) return false;
}
else if (!Dialog("HELO " + mailserver + crlf, "")) return false;
// 3. 寄件人
if (!Dialog("MAIL FROM:<" + From + ">" + crlf, "寄件人地址錯誤")) return false;
// 4. 收件人 / CC / BCC
string[] rcpt = new string[10];
for (int i=0;i
string BuildMailHeaders()
{
string h = "";
h += "From: " + FromName + "<" + From + ">" + crlf;
h += "To: " + RecipientName + "<" + Recipient[0] + ">" + crlf;
h += "CC: " + string.Join(",", Recipient.Skip(1).Select((r,i)=>RecipientName[i]+"<"+r+">")) + crlf;
if (!string.IsNullOrEmpty(ReplyTo)) h += "Reply-To: " + ReplyTo + crlf;
h += "Subject: " + (string.IsNullOrEmpty(Charset) ? Subject : "=?"+Charset.ToUpper()+"?B?"+Base64Encode(Subject)+"?=") + crlf;
h += "MIME-Version: 1.0" + crlf;
h += "Content-Type: " + (Html ? "text/html" : "text/plain") + "; charset=" + (string.IsNullOrEmpty(Charset)?"iso-8859-1":Charset.ToLower()) + crlf;
h += "Content-Transfer-Encoding: base64" + crlf;
h += "X-Priority: " + priority + crlf;
return h;
}
// 僅用屬性設定
public bool Send() { /* 驗證屬性 → SendEmail() */ }
// 指定 SMTP 伺服器字串 "user:pass@host:port"
public bool Send(string smtpserver) { MailDomain=smtpserver; return Send(); }
// 完整參數單次發送
public bool Send(string smtpserver, string from, string fromname, string replyto,
string to, string toname, bool html, string subject, string body)
{
MailDomain=smtpserver; From=from; FromName=fromname; ReplyTo=replyto;
AddRecipient(to); RecipientName=toname; Html=html; Subject=subject; Body=body;
return Send();
}
private string Base64Encode(string src)
{
return Convert.ToBase64String(Encoding.GetEncoding(Charset).GetBytes(src));
}
var mail = new SmtpMailComponent
{
MailDomain = "smtp.gmail.com:587", // 或 "user:pass@smtp.gmail.com:587"
From = "me@gmail.com",
FromName = "My App",
Subject = "測試郵件",
Body = "Hello
這是 HTML 郵件
",
Html = true,
Charset = "utf-8",
Priority = "3"
};
mail.AddRecipient("you@example.com", "收件人");
bool ok = mail.Send();
if (!ok) Console.WriteLine(mail.ErrorMessage);
STARTTLS 或隱性 SSL(埠 465),可搭配 SslStream 實作。System.Net.Mail.MailMessage + SmtpClient(支援 SSL、非同步、附件、替代檢視),僅在教學、舊系統維護或特殊協議需求時參考本實作。try/catch/finally 確保 TcpClient/NetworkStream 正確釋放。本元件完整展示了 SMTP/ESMTP 協議的指令交互流程、驗證機制、MIME 郵件結構建構與 Base64 編碼應用。透過逐行解析核心原始碼,讀者可深入理解郵件發送底層機制,並具備擴充支援附件、多部份 MIME、DKIM 簽名等進階功能的基礎。