首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 實作 SMTP 驗證郵件發送元件:完整協議流程與原始碼深度解析

     編輯:關於C語言

前言:為何要手工實作 SMTP 協議?

.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 驗證)

關鍵方法原始碼解析

1. 接收伺服器回應

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;
}

2. 單指令交互與回應碼驗證

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;
}

3. 批次指令交互

private bool Dialog(string[] cmds, string errstr)
{
    foreach (string cmd in cmds)
        if (!Dialog(cmd, "")) { errmsg += Environment.NewLine + errstr; return false; }
    return true;
}

4. 完整發送流程

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

5. MIME 標頭建構(支援 Base64 主旨、HTML/純文字、字集、優先權)

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;
}

公開介面:多載 Send 方法

// 僅用屬性設定
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();
}

Base64 編碼輔助方法

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);

注意事項與現代化建議

  • 安全性:原始碼使用明文傳輸(埠 25),生產環境**必須**升級支援 STARTTLS 或隱性 SSL(埠 465),可搭配 SslStream 實作。
  • 編碼:主旨與本文皆以 Base64 編碼,相容中文等非 ASCII 字元。
  • 替代方案:.NET 2.0+ 建議直接使用 System.Net.Mail.MailMessage + SmtpClient(支援 SSL、非同步、附件、替代檢視),僅在教學、舊系統維護或特殊協議需求時參考本實作。
  • 例外處理:網路操作應包裝於 try/catch/finally 確保 TcpClient/NetworkStream 正確釋放。

總結

本元件完整展示了 SMTP/ESMTP 協議的指令交互流程、驗證機制、MIME 郵件結構建構與 Base64 編碼應用。透過逐行解析核心原始碼,讀者可深入理解郵件發送底層機制,並具備擴充支援附件、多部份 MIME、DKIM 簽名等進階功能的基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved