| 特性 | 方案一:啟動郵件用戶端 | 方案二:直接 SMTP 發送 |
|---|---|---|
| 實作複雜度 | 極低 | 中等 |
| 使用者體驗 | 彈出 Foxmail/Outlook 需手動確認 | 背景靜默發送 |
| 安全性 | 高(用戶掌控) | 需處理認證、加密 |
| 適用場景 | 簡單聯繫表單 | 自動通知、系統郵件 |
mailto: 協議啟動預設郵件客戶端public class EmailApplet extends Applet {
TextField emailField;
Button sendBtn;
public void init() {
setLayout(new BorderLayout());
emailField = new TextField();
sendBtn = new Button("sendMail");
add("North", emailField);
add("South", sendBtn);
}
public boolean action(Event e, Object arg) {
if ("sendMail".equals(arg)) {
try {
String mailto = emailField.getText(); // 格式: mailto:user@domain?subject=...&body=...
URL url = new URL(mailto);
getAppletContext().showDocument(url); // 瀏覽器處理 mailto: 協議
} catch (Exception ex) {
System.out.println(ex);
}
}
return true;
}
}
mailto:recipient@example.com?subject=Hello&body=Message%20content
mailto:user1@domain.com,user2@domain.com?cc=cc@domain.com&bcc=bcc@domain.com
attachment 參數但非標準)HELO → MAIL FROM → RCPT TO → DATA → 郵件內容 → . → QUITvoid sendMail() {
String sender = txtFrom.getText(); // from@domain.com
String recipient = txtTo.getText(); // to@domain.com
String content = txtBody.getText();
// 簡易郵箱格式驗證
if (!sender.contains("@") || !recipient.contains("@")) {
showError("郵件格式錯誤");
return;
}
try (Socket socket = new Socket(smtpHost, SMTP_PORT);
PrintStream out = new PrintStream(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
// 讀取歡迎訊息
System.out.println(in.readLine());
// SMTP 對話
out.println("HELO " + senderHost);
System.out.println(in.readLine());
out.println("MAIL FROM:<" + senderName + ">");
System.out.println(in.readLine());
out.println("RCPT TO:<" + recipientName + ">");
System.out.println(in.readLine());
out.println("DATA");
System.out.println(in.readLine());
out.println("Subject: Test from Applet");
out.println("From: " + sender);
out.println("To: " + recipient);
out.println(""); // 空行分隔標頭與內文
out.println(content);
out.println("."); // 結束標記
System.out.println(in.readLine());
out.println("QUIT");
showSuccess("郵件發送成功");
} catch (Exception e) {
showError("發送失敗: " + e.getMessage());
}
}
\r\n(PrintStream.println() 自動處理)DATA 後內文以單獨一行 . 結束. 行需轉義為 ..原始碼僅支援純文字。中文需採用 MIME 編碼:
out.println("Content-Type: text/plain; charset=UTF-8");
out.println("Content-Transfer-Encoding: base64");
out.println();
out.println(Base64.getEncoder().encodeToString(content.getBytes("UTF-8")));
// AUTH LOGIN 流程
out.println("AUTH LOGIN");
readResponse(); // 334 VXNlcm5hbWU6
out.println(Base64.getEncoder().encodeToString(username.getBytes()));
readResponse(); // 334 UGFzc3dvcmQ6
out.println(Base64.getEncoder().encodeToString(password.getBytes()));
readResponse(); // 235 Authentication successful
// 隱式 SSL (Port 465)
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = factory.createSocket(smtpHost, 465);
// 顯式 STARTTLS (Port 587)
Socket socket = new Socket(smtpHost, 587);
// ... 傳送 STARTTLS 指令後升級為 SSLSocket
Applet 技術已淘汰,現代 Web 應用建議:
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
msg.setSubject(subject);
msg.setText(body);
Transport.send(msg);
方案一適合簡單「聯繫我們」表單,零後端成本;方案二展示 SMTP 底層協議但缺乏認證、加密、MIME 等生產級功能。現代開發請務必使用成熟郵件庫或雲端服務,避免重複造輪子並踩安全坑。