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

Java 手寫 SMTP 郵件發送器:從 Socket 通訊到 GUI 完整實現

     編輯:Java 相關知識

核心原理

直接使用 Socket 連接 SMTP 服務器(默認端口 25),按 SMTP 協議發送命令序列:HELO/EHLO → AUTH LOGIN → Base64 編碼用戶名/密碼 → MAIL FROM → RCPT TO → DATA → 郵件內容 → . → QUIT。

關鍵實現細節

  • SMTP 服務器判斷:根據發件人郵箱後綴(@163/@126/@sina/@qq)選擇對應 SMTP 主機。
  • Base64 編碼:用戶名/密碼必須 Base64 編碼後發送(使用 sun.misc.BASE64Encoder,編譯警告屬正常,因屬內部 API)。
  • 郵件格式:DATA 後發送頭部(From/To/Subject),Subject 後必須空一行(\r\n),然後正文,結尾單獨一行 .。
  • 命令結尾:每條命令必須以 \r\n 結束。

完整代碼結構

1. 郵件實體類

class E_Mail {
    String from, to, subject, content, userName, pwd;
    public E_Mail(String from, String to, String subject, String content, String userName, String pwd) {
        this.from = from; this.to = to; this.subject = subject; this.content = content;
        this.userName = toBASE64(userName); this.pwd = toBASE64(pwd);
    }
    private String toBASE64(String str) {
        return new sun.misc.BASE64Encoder().encode(str.getBytes());
    }
}

2. 發送核心類

public class SimpleMailSender {
    private String smtpServer; private int port = 25;
    private Socket socket; private BufferedReader br; private PrintWriter pw;

    private void initServer(String from) { /* 根據後綴設置 smtpServer */ }

    public void sendEmail(E_Mail email) {
        try {
            initServer(email.from);
            socket = new Socket(smtpServer, port);
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            pw = new PrintWriter(socket.getOutputStream(), true);

            sendReceive(null);           // 接收歡迎信息
            sendReceive("ehlo hao");
            sendReceive("auth login");
            sendReceive(email.userName);
            sendReceive(email.pwd);
            sendReceive("mail from:<" + email.from + ">");
            sendReceive("rcpt to:<" + email.to + ">");
            sendReceive("data");

            pw.println("from:" + email.from);
            pw.println("to:" + email.to);
            pw.println("subject:" + email.subject + "\r\n"); // 關鍵空行
            pw.println(email.content);
            sendReceive(".");            // 結束數據
            sendReceive("quit");
        } catch (IOException e) { e.printStackTrace(); }
        finally { closeQuietly(socket); }
    }

    private void sendReceive(String cmd) throws IOException {
        if (cmd != null) { pw.print(cmd + "\r\n"); pw.flush(); System.out.println(">> " + cmd); }
        char[] buf = new char[1024];
        br.read(buf);
        System.out.println(new String(buf).trim());
    }
    // getReader/getWriter/closeQuietly 略
}

3. Swing GUI 界面

class MailSenderGUI extends JFrame implements ActionListener {
    // 組件:發件人、用戶名、密碼、收件人、主題、正文、發送/重置按鈕
    // 佈局:BorderLayout 北部表單、中部正文區、南部按鈕
    // 事件:發送 → 組裝 E_Mail → 調用 SimpleMailSender.sendEmail()
    //       重置 → 清空所有輸入框
}

實測踩坑記錄

  1. QQ/Sina SMTP 連不上:僅 163/123 成功,可能需開啟「客戶端授權碼」而非登錄密碼,或服務器策略變更。
  2. 代碼重複:sendEmail 中命令序列有重複,可提取為命令數組循環發送。
  3. QQ 郵箱收信極快:nslookup 發現 QQ SMTP 服務器集群規模遠大於 163。
  4. 頻繁發送被封:同一賬號短時間大量發送會被服務器拒收,需控制頻率。

總結

手寫 SMTP 客戶端能深入理解郵件協議細節,適合教學與輕量級無依賴場景。生產環境強烈建議使用成熟庫(JavaMail、Simple Java Mail),支持 SSL/TLS、MIME、附件、異步發送等企業級特性。

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