| 協議 | 全稱 | 預設埠 | 用途 |
|---|---|---|---|
| SMTP | Simple Mail Transfer Protocol | 25 | 發送/轉發郵件 |
| POP3 | Post Office Protocol v3 | 110 | 接收/下載郵件(存轉模式) |
| IMAP | Internet Message Access Protocol | 143 | 接收/同步郵件(支援多裝置、僅下載標題) |
本文專注 SMTP 發送實現。
HELO // 握手,宣告發送方域名
MAIL FROM: // 發件人
RCPT TO: // 收件人(可多次)
DATA // 進入資料模式
...郵件頭與內容...
. // 單獨一行點號結束
QUIT // 斷開連線
setLocation((screenW - frameW)/2, (screenH - frameH)/2)// 瀏覽附件
cmdBrowse.addActionListener(e -> {
FileDialog fd = new FileDialog(this, "選擇附件", FileDialog.LOAD);
fd.setVisible(true);
lblFile.setText(fd.getDirectory() + fd.getFile());
});
// 發送郵件
cmdSend.addActionListener(e -> {
mailSender.setFrom(txtFrom.getText().trim());
mailSender.setTo(txtTo.getText().trim());
mailSender.addHeader("Subject", txtSubject.getText().trim());
mailSender.addData(txtMail.getText());
if (!lblFile.getText().trim().isEmpty())
mailSender.addAttachment(lblFile.getText().trim());
mailSender.open(txtServer.getText().trim(), 25);
mailSender.transmit();
mailSender.close();
});
// 離開
cmdExit.addActionListener(e -> System.exit(0));
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
public int open(String server, int port) {
try {
mailSocket = new Socket(server, port);
send = new PrintWriter(mailSocket.getOutputStream(), true);
recv = new BufferedReader(new InputStreamReader(mailSocket.getInputStream()));
String resp = recv.readLine();
if (resp.charAt(0) == '4' || resp.charAt(0) == '5') return 0; // 錯誤回應
return 1;
} catch (Exception e) { return 0; }
}
private int sendString(String cmd) {
try {
send.println(cmd);
String resp = recv.readLine();
if (resp.length() == 0) return 0;
char c = resp.charAt(0);
return (c == '4' || c == '5') ? 0 : 1; // 4xx/5xx 為錯誤
} catch (Exception e) { return 0; }
}
public int transmit() {
// HELO
if (!domain.isEmpty() && sendString("HELO " + domain) != 1) return 0;
// MAIL FROM
if (!from.isEmpty() && sendString("MAIL FROM:" + from) != 1) return 0;
// RCPT TO
if (!to.isEmpty() && sendString("RCPT TO:" + to) != 1) return 0;
// DATA
if (sendString("DATA") != 1) return 0;
// 郵件頭
for (int i = 0; i < headers.size(); i += 2)
send.println(headers.get(i) + ": " + headers.get(i+1));
// 自動補 Date
if (!headers.contains("Date"))
send.println("Date: " + new Date());
send.println(); // 空行分隔頭/體
// 郵件體
for (String line : body) send.println(line);
// 結束標記
if (sendString(".") != 1) return 0;
return 1;
}
public int close() {
try {
sendString("QUIT");
mailSocket.close();
return 1;
} catch (Exception e) { return 0; }
}
// mailSendFrame.java - GUI 主程式
// smtpMail.java - SMTP 通訊核心
// 欄位:from, to, domain, headers(Vector), body(Vector), attachments(Vector)
// 方法:open/transmit/close/sendString + 郵件組裝輔助方法
SSLSocketFactory 連接 465/587 埠透過 Socket 直連 SMTP 伺服器、按協議發送文本命令、解析數字回應碼,即可實現基礎郵件發送。雖然生產環境建議使用 JavaMail、Apache Commons Email 等成熟庫,但親手實作 SMTP 流程能深度理解郵件傳遞本質,為排查發送失敗、實作客製化郵件系統打下堅實基礎。