提到 Java,許多人腦海中浮現的可能只是裝飾網頁的小程式,像經典的水面倒影效果。但這些只是 Java 應用的冰山一角。作為一門為網路而生的語言,Java 在編寫基於 TCP/IP 的網路應用時,展現出了驚人的簡潔與高效。本文將深入探討如何利用 Java Applet,依據 SMTP 與 POP3 協議實現線上收發電子郵件的功能。
Java 透過 Socket 類別的建構子 Socket(String host, int port) 來建立連線。受限於 Applet 的安全機制(沙箱模型),Applet 只能連回其原始伺服器。因此,我們通常先透過 getCodeBase() 取得載入 Applet 的基底 URL,再呼叫 getHost() 解析出主機名稱。例如從 https://person.zj.cninfo.net/~caveman/ 可解析出 person.zj.cninfo.net。
常見通訊埠:SMTP (25)、POP3 (110)、FTP (21)。實際部署前請確認目標伺服器使用的埠號。
socket.getOutputStream() 取得輸出串流,包裝為 DataOutputStream,使用 writeBytes() 逐字元寫入。socket.getInputStream() 取得輸入串流,包裝為 DataInputStream,使用 readLine() 逐行讀取伺服器回應。呼叫 socket.close() 即可釋放資源、斷開 TCP 連線。
SMTP (Simple Mail Transfer Protocol) 雖定義了 14 條命令,但發送一封郵件僅需核心 5 步:
| 命令 | 功能 |
|---|---|
| HELO <domain> | 與伺服器握手,傳送本機網域名稱 |
| MAIL FROM:<address> | 指定寄件者信箱 |
| RCPT TO:<address> | 指定收件者信箱 |
| DATA | 開始傳送郵件資料(含標頭與內文),以單獨一行的 . 結束 |
| QUIT | 結束會話 |
除了 ISP 提供的伺服器,某些免費個人主頁伺服器(如早期的 person.zj.cninfo.net)若未啟用 Relay 限制,也可作為發信跳板。將編寫好的 Applet 與呼叫的 HTML 頁面放置於此類伺服器,即可實現瀏覽器端直接發信。
TextField:寄件者、收件者、主旨TextArea:信件內容輸入區、伺服器回應/錯誤訊息顯示區Button:觸發發送動作核心邏輯封裝於 bu1run() 方法中:
public void bu1run() {
try {
// 1. 連接 SMTP 伺服器 (埠 25)
Socket socket1 = new Socket(getCodeBase().getHost(), 25);
DataOutputStream dataout2 = new DataOutputStream(socket1.getOutputStream());
DataInputStream dataIn3 = new DataInputStream(socket1.getInputStream());
// 2. 讀取伺服器歡迎訊息
GetReply(dataIn3);
// 3. 依序發送 SMTP 命令
dataout2.writeBytes("HELO person.zj.cninfo.net\r\n");
GetReply(dataIn3);
dataout2.writeBytes("MAIL FROM: " + tf1.getText() + "\r\n");
GetReply(dataIn3);
dataout2.writeBytes("RCPT TO: " + tf2.getText() + "\r\n");
GetReply(dataIn3);
dataout2.writeBytes("DATA\r\n");
GetReply(dataIn3);
// 4. 發送郵件標頭與內文
dataout2.writeBytes("From: " + tf1.getText() + "\r\n");
dataout2.writeBytes("To: " + tf2.getText() + "\r\n");
dataout2.writeBytes("Subject:" + tf3.getText() + "\n\n" + ta1.getText() + "\r\n.\r\n");
GetReply(dataIn3);
// 5. 結束會話
dataout2.writeBytes("QUIT\r\n");
GetReply(dataIn3);
socket1.close();
bu1.enable();
} catch (IOException e) {
ta2.appendText("Error!\n");
bu1.enable();
}
}
輔助方法 GetReply(DataInputStream in) 負責讀取並顯示伺服器每一步的回應碼與訊息,便於除錯。
本文展示了 Java 在網路應用層的強大表達力。雖然現代瀏覽器已淘汰 Applet 支援,但此處展示的 Socket 程式設計模型、協議解析邏輯、異常處理模式,至今仍是 Java 網路程式設計(如後端微服務、中介軟體開發)的基石。理解這些底層機制,有助於開發者在更高層框架(如 Spring Boot、Netty)下排查疑難雜症、優化效能。