SMTP (Simple Mail Transfer Protocol) 是郵件傳輸的核心協議。本例拋棄 JavaMail,直接使用 Socket 連接埠 25,手動發送 HELO, MAIL FROM, RCPT TO, DATA 等指令完成郵件發送,是理解「郵件如何送達」的最直觀教學案例。
C: HELO theWorld // 問候,宣告客戶端身分
S: 250 OK
C: MAIL FROM: <> // 寄件者(空地址常被拒收)
S: 250 OK
C: RCPT TO: recipient@domain.com // 收件者
S: 250 OK
C: DATA // 開始資料傳輸
S: 354 Start mail input
C: Subject: Test Mail // 郵件主旨 (Header 一部分)
C: From: sender <> // 寄件者顯示名
C: // 空行分隔 Header 與 Body
C: 這是郵件正文內容...
C: . // 單獨一行 "." 結束資料
S: 250 OK queued
C: QUIT // 結束會話
S: 221 Bye
Socket s = new Socket(mailServer, 25);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "8859_1"));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream(), "8859_1"));
// 封裝發送指令並讀取回應
void send(BufferedReader in, BufferedWriter out, String cmd) {
out.write(cmd + "\n");
out.flush();
System.out.println("C: " + cmd);
String reply = in.readLine();
System.out.println("S: " + reply);
}
// 主流程
send(in, out, "HELO theWorld");
send(in, out, "MAIL FROM: <>");
send(in, out, "RCPT TO: " + recipient);
send(in, out, "DATA");
send(out, "Subject: 測試郵件"); // 僅寫入不讀回應
send(out, "From: sender <>");
send(out, "\n"); // 空行
send(out, "郵件正文內容...");
send(out, "\n.\n"); // 結束標記
send(in, out, "QUIT");
s.close();
HELO/MAIL/RCPT/DATA/QUIT 是指令,需讀取伺服器回應碼;DATA 後的 Header/Body 是資料流,不逐行讀取回應,直到發送 .\n 才讀取最終回應。程式碼透過重載 send(BufferedWriter out, String) 區分兩種模式。AUTH LOGIN/PLAIN (Base64 編碼帳密)MAIL FROM 必須為真實可驗證域名此程式碼極佳地展示了 SMTP 協議狀態機本質,但距離生產可用尚遠。實戰建議:
RFC 5321 完整實作指令語法、回應碼處理、錯誤重試、流量控制。