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

C# SMTP 郵件發送元件原始碼深度解析:ESMTP 驗證、多附件、HTML 郵件完整實作

     編輯:關於C語言

架構概覽

純 Socket 實作 SMTP 協定(RFC 5321),無第三方依賴,支援:

  • ESMTP 指令(EHLO)與 AUTH LOGIN 驗證
  • 多附件(Base64 編碼,MIME multipart/mixed)
  • HTML/純文字替代內容(multipart/alternative)
  • 自訂優先級、編碼、郵件標頭

核心類別結構


public class MailSender {
    // 伺服器設定
    public string Server { get; set; } = "";
    public int Port { get; set; } = 25;
    public string UserName { get; set; } = "";
    public string PassWord { get; set; } = "";

    // 郵件內容
    public string From { get; set; } = "";
    public string To { get; set; } = "";
    public string Subject { get; set; } = "";
    public string Body { get; set; } = "";
    public string HtmlBody { get; set; } = "";
    public bool IsHtml { get; set; } = false;
    public string LanguageEncoding { get; set; } = "GB2312";
    public string MailEncoding { get; set; } = "8bit";
    public int Priority { get; set; } = 3;

    // 附件集合
    public IList Attachments { get; } = new ArrayList();

    public void SendMail() { /* 核心流程 */ }
}

附件結構體


public struct AttachmentInfo {
    public string FileName { get; set; } // 自動取檔名
    public string Bytes { get; set; }    // Base64 字串

    // 多種建構方式
    public AttachmentInfo(string path) { /* 讀檔→Base64 */ }
    public AttachmentInfo(string fileName, Stream stream) { /* 讀流→Base64 */ }
    public AttachmentInfo(string fileName, byte[] bytes) { /* 直接 Base64 */ }
}

發送核心流程 SendMail()

  1. 建立 TCP 連線:`new TcpClient(server, port)`
  2. 讀取歡迎訊息:`ReadString(stream)`
  3. EHLO 啟動 ESMTP:期待 250 回碼
  4. AUTH LOGIN 驗證(若有帳密):
    • 發送 `AUTH LOGIN` → 334
    • 發送 Base64(UserName) → 334
    • 發送 Base64(PassWord) → 235
  5. MAIL FROM / RCPT TO / DATA
  6. 寫入郵件標頭:Date、From、To、Subject、MIME-Version、Content-Type、Priority 等
  7. 寫入郵件本文:
    • 純文字:`text/plain; charset=...`
    • HTML:`text/html; charset=...`
    • 使用 boundary 分隔:`unique-boundary-1` (外層), `unique-boundary-2` (內層 alternative)
  8. 寫入附件:逐個寫入 `application/octet-stream`,Base64 內容
  9. 結束標記:單獨一行 `.` → 期待 250
  10. 關閉連線

關鍵輔助方法


// 分塊寫入(每 75 bytes),避免單次寫入過大
protected void WriteString(NetworkStream ns, string str) {
    str += "\r\n";
    byte[] data = Encoding.GetEncoding(LanguageEncoding).GetBytes(str);
    // 分頁寫入邏輯...
}

// 讀取回應
protected string ReadString(NetworkStream ns) {
    byte[] buf = new byte[1024];
    int len = ns.Read(buf, 0, buf.Length);
    return len > 0 ? Encoding.Default.GetString(buf, 0, len) : null;
}

// 指令發送與狀態碼驗證
protected bool Command(NetworkStream ns, string cmd, string expectedCode) {
    WriteString(ns, cmd);
    string resp = ReadString(ns);
    return resp?.IndexOf(expectedCode) >= 0;
}

// Base64 編碼
protected string ToBase64(string s) {
    return Convert.ToBase64String(Encoding.Default.GetBytes(s));
}

使用範例


var ms = new MailSender {
    Server = "smtp.gmail.com",
    Port = 587, // 或 465 SSL
    UserName = "your@gmail.com",
    PassWord = "app-password",
    From = "your@gmail.com",
    To = "target@example.com",
    Subject = "測試郵件",
    Body = "純文字內容",
    HtmlBody = "

HTML 內容

", IsHtml = true, LanguageEncoding = "UTF-8" }; ms.Attachments.Add(new MailSender.AttachmentInfo(@"C:\report.pdf")); ms.Attachments.Add(new MailSender.AttachmentInfo("logo.png", File.OpenRead(@"C:\logo.png"))); try { ms.SendMail(); Console.WriteLine("發送成功"); } catch (Exception ex) { Console.WriteLine($"失敗: {ex.Message}"); }

現代替代方案與注意事項

議題說明建議
SSL/TLS原碼使用明文 TCP,Gmail/Outlook 等強制加密改用 SslStream 包裝 NetworkStream,或直接用 SmtpClient / MailKit
編碼預設 GB2312,國際郵件易亂碼統一使用 UTF-8,標頭以 `=?UTF-8?B?...?=` 編碼
大附件全量載入記憶體再 Base64,記憶體壓力大串流分塊 Base64 編碼,或改用 MailKit 的 MIME 串流
異步/取消同步阻塞呼叫改用 MailKit 非同步 API + CancellationToken
DKIM/SPF/DMARC無簽名支援,進垃圾箱機率高使用成熟庫(MailKit/MimeKit)並配置簽名

推薦現代庫

  • MailKit:跨平台、完整 MIME/IMAP/SMTP/POP3、支援 OAuth2、DKIM、S/MIME。
  • MimeKit:MailKit 底層 MIME 解析構建器。
  • FluentEmail:流暢 API 封裝,支援 Razor 模板、多發送器。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved