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

BCB 開發支援 ESMTP 身份驗證的郵件發送程式:從協定分析到 Base64 實作

     編輯:關於C++

為抑制垃圾郵件,多數郵件伺服器採用 ESMTP 身份驗證。BCB 6 的 NMSMTP 元件雖方便,但不支援驗證功能。本文分析 ESMTP AUTH LOGIN 流程,並實作 Base64 編碼,擴充元件實現帶驗證的郵件發送。

ESMTP AUTH LOGIN 流程分析

以網易郵箱為例(C=客戶端,S=伺服器):

(1) C: AUTH LOGIN
(2) S: 334 dXNlcm5hbWU6        // Base64("username:") -> 要求用戶名
(3) C: d3lxX2puX3NkX2Nu        // Base64 編碼用戶名
(4) S: 334 UGFzc3dvcmQ6        // Base64("password:") -> 要求密碼
(5) C: [Base64 編碼密碼]
(6) S: 235 Authentication successful

關鍵點:334 表示繼續,235 表示成功。所有認證資料均為 Base64 編碼傳輸。

MIME Base64 編碼原理

  • 標準位元組:8 bits(256 種組合)。
  • Base64:6 bits(64 種),字符集 A-Z a-z 0-9 + /。
  • 3 位元組 → 4 Base64 字符。不足 3 位元組時補 0,輸出用 = 填充(1 個 = 代表缺 1 位元組,2 個 = 缺 2 位元組)。

設計思路

  1. 使用 NMSMTP.Connect() 連線伺服器。
  2. 在 OnConnect 事件中,利用元件繼承自 PowerSocket 的 SendBuffer、Read、DataAvailable 等底層網路函數,手動實作 AUTH LOGIN 交互。
  3. 驗證成功後啟用發送按鈕;失敗則斷線提示。

核心實作代碼

// 1. 登入按鈕觸發連線
void __fastcall TForm1::Logon1Click(TObject *Sender) {
    AddLog("正在登入 " + Edit1->Text + "...");
    NMSMTP1->Host = Edit1->Text;
    NMSMTP1->Port = 25;
    NMSMTP1->UserID = Edit4->Text; // 用戶名
    NMSMTP1->Connect();
}

// 2. OnConnect 事件處理認證流程
void __fastcall TForm1::NMSMTP1Connect(TObject *Sender) {
    AddLog("連線伺服器成功。");
    AnsiString Data, rData; bool b_ok;

    if (CheckBox1->Checked) { // 需要驗證
        // 步驟 1: 發送 AUTH LOGIN
        Data = "AUTH LOGIN\r\n";
        NMSMTP1->SendBuffer(Data.c_str(), Data.Length());
        rData = WaitForReply(5);
        if (!(rData.Length()>=3 && rData.TrimLeft().SubString(1,3)=="334")) { Fail(); return; }
        AddLog("正在驗證身份...");

        // 步驟 2: 發送 Base64 用戶名
        Data = encode(Edit4->Text) + "\r\n";
        NMSMTP1->SendBuffer(Data.c_str(), Data.Length());
        rData = WaitForReply(5);
        if (!(rData.Length()>=3 && rData.TrimLeft().SubString(1,3)=="334")) { Fail(); return; }
        AddLog("正在驗證密碼...");

        // 步驟 3: 發送 Base64 密碼
        Data = encode(Edit5->Text) + "\r\n";
        NMSMTP1->SendBuffer(Data.c_str(), Data.Length());
        rData = WaitForReply(5);
        if (!(rData.Length()>=3 && rData.TrimLeft().SubString(1,3)=="235")) { Fail(); return; }
        AddLog("登入成功!");
    }
    SendMail->Enabled = true;
    disconnect->Enabled = true;
    Logon1->Enabled = false;
}

// 3. Base64 編碼函數
AnsiString TForm1::encode(AnsiString s) {
    int m_len = s.Length(), i, m_tmp;
    AnsiString m_64code;
    char *m_s = s.c_str();
    char m_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    for (i=0; i<m_len-m_len%3; i+=3) { // 每 3 位元組處理
        m_tmp = m_s[i] / 4;                    m_64code += m_64[m_tmp];
        m_tmp = m_s[i]%4*16 + m_s[i+1]/16;     m_64code += m_64[m_tmp];
        m_tmp = m_s[i+1]%16*4 + m_s[i+2]/64;   m_64code += m_64[m_tmp];
        m_tmp = m_s[i+2]%64;                   m_64code += m_64[m_tmp];
    }
    // 餘 2 位元組
    if (m_len%3 == 2) {
        m_tmp = m_s[m_len-2]/4;                m_64code += m_64[m_tmp];
        m_tmp = m_s[m_len-2]%4*16 + m_s[m_len-1]/16; m_64code += m_64[m_tmp];
        m_tmp = m_s[m_len-1]%16*4;             m_64code += m_64[m_tmp];
        m_64code += '=';
    }
    // 餘 1 位元組
    if (m_len%3 == 1) {
        m_tmp = m_s[m_len-1]/4;                m_64code += m_64[m_tmp];
        m_tmp = m_s[m_len-1]%4*16;             m_64code += m_64[m_tmp];
        m_64code += "==";
    }
    return m_64code;
}

測試結果

在 Windows 2000 + BCB 6.0 環境下,分別測試網易與新浪郵箱,均能順利完成身份驗證與郵件發送。

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