目錄
一、前言:QQ郵件發送程序
在上一篇《Java網絡編程:實現QQ郵件發送客戶端》,我們解決了telnet終端發送郵件誤操作帶來的麻煩,實現了自己的簡單Java界面進行發送QQ郵件,界面可直接與smtp.qq.com服務器端建立連接,通過命令方式發送郵件信息。
這一篇為QQ郵件發送客戶端程序設計的下篇,將實現更加完善的功能,不用命令發送方式,類似日常發送郵件,直接編寫郵件標題、內容,然后直接發送即可,基本實現了QQ郵件發送客戶端的功能,操作更加簡便,實現自己的QQ郵件發送端,以后就用這個啦。
二、封裝SMTP操作
原來的終端發送逐步操作如下:
HELO hostname //回車,hostname可以是IP或其他隨意別名
AUTH LOGIN //回車后,先粘貼base64程序編碼的完整郵箱名並回車;再粘貼base64編碼的授權碼並回車
MAIL FROM:<czh_charzeus@qq.com> //在這里填寫自己的郵箱地址,用於發送郵件(注意冒號后面別有空格)
RCPT TO:<czh_charzeus@qq.com> //接收方的郵箱,在這里暫時填寫和上面一樣的郵箱地址,即自己發送郵件給自己,驗證是否成功
DATA //回車,接下來開始發送郵件頭相關內容
Subject: the simple mail // 郵件的標題,回車 //在這里再多發送一行空行,來分隔郵件內容,下面就是郵件正文內容
Hello,the mail content! 測試發送郵件! //控制台中中文會變成?的亂碼,但不影響接受者接收到中文內容
. //在郵件正文發送完畢后,單獨用一行輸入一個小圓點,作為結束標志,然后回車
QUIT //結束通信(含4次握手斷開)
因此,我們要避免這種繁瑣的命令形式,只需要將每個語句封裝到發送程序里面,在用戶界面則無需進行命令的輸入,只需要輸入內容。
實現的方法很簡單,只需要在發送按鈕中,把命令加進去就可以,如下:
tcpMailClient.send("HELO friend"); tcpMailClient.send("auth login"); String userNameBase64= encode(senderMail); tcpMailClient.send(userNameBase64); String authCode = encode("你的授權碼"); tcpMailClient.send(authCode); String msg = "mail from:<"+senderMail+">"; tcpMailClient.send(msg); msg = "rcpt to:<"+receiverMail+">"; tcpMailClient.send(msg); tcpMailClient.send("data"); msg="from:"+senderMail; tcpMailClient.send(msg); msg="to:"+receiverMail; tcpMailClient.send(msg); msg="subject:"+sub; tcpMailClient.send(msg); tcpMailClient.send("\n"); // tcpMailClient.send("這是一封測試java客戶端自動發送功能的郵件。");
tcpMailClient.send(content); tcpMailClient.send("."); tcpMailClient.send("quit");
從代碼可以看到,當發送按鈕一點擊后,程序會執行所有語句,我們從上一篇知道,郵件服務器也會返回信息,所以QQ客戶端需要使用多線程的技術,來處理返回信息,避免單線程阻塞導致發送不成功。
三、實現多線程接收
根據前面分析,將客戶端接收的功能交給一個線程處理,就能夠達到目的,不會因為接收語句阻塞使得主進程卡住。
所以,將線程放到連接按鈕里面為好,在成功連接服務器之后,程序就啟動線程,時機正好。連接按鈕中的線程代碼如下:
//用於接收服務器信息的單獨線程
readThread = new Thread(()->{ String receiveMsg=null;//從服務器接收一串字符
while ((receiveMsg=tcpMailClient.receive())!=null){ String msgTemp = receiveMsg; Platform.runLater(()->{ taDisplay.appendText(msgTemp+"\n"); }); } Platform.runLater(()->{ taDisplay.appendText("對話已關閉!\n"); }); }); readThread.start();
程序執行發送每一條命令語句的速度比我們自己輸入發送要快許多,為了避免QQ郵件接收服務器無法及時響應出錯,程序自動發送過程中需要設置一定的睡眠等待時間,在send方法設置等待200ms或者500ms。
QQ郵件客戶端實現代碼可見上一篇Java網絡編程:實現QQ郵件發送客戶端,這里不再重復介紹。
public void send(String msg){ //輸出字符流,由socket調用系統底層函數,經網卡發送字節流
pw.println(msg); try { //進行郵件交互,發送smtp指令之間應該暫停一段時間
Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }
四、QQ郵件客戶端界面設計
界面的設計與以往類似,可以根據自己的需求設計不同的界面風格,可參考本文前言或者總結部分的系列文章進行實現。這里給出關鍵按鈕的完整代碼。
1、連接按鈕

//連接按鈕 btConn.setOnAction(event -> { String ip=ipAddress.getText().trim(); String port=tfport.getText().trim(); try { tcpMailClient = new TCPMailClient(ip, port); //成功連接服務器,接受服務器發來的第一條歡迎信息 String firstMsg=tcpMailClient.receive(); taDisplay.appendText(firstMsg+"\n"); //用於接收服務器信息的單獨線程 readThread = new Thread(()->{ String receiveMsg=null;//從服務器接收一串字符 while ((receiveMsg=tcpMailClient.receive())!=null){ //lambda表達式不能直接訪問外部非final類型局部變量,需要定義一個臨時變量 //若將receiveMsg定義為類成員變量,則無需臨時變量 String msgTemp = receiveMsg; Platform.runLater(()->{ taDisplay.appendText(msgTemp+"\n"); }); } Platform.runLater(()->{ taDisplay.appendText("對話已關閉!\n"); }); }); readThread.start(); } catch (IOException e) { e.printStackTrace(); } });
2、發送按鈕

//發送按鈕 btnSend.setOnAction(event -> { String senderMail = mail.getText().trim(); String receiverMail = toMail.getText().trim(); String sub = subject.getText(); String content = tfSend.getText(); try { tcpMailClient.send("HELO friend"); tcpMailClient.send("auth login"); String userNameBase64= encode(senderMail); tcpMailClient.send(userNameBase64); String authCode = encode("你的授權碼"); tcpMailClient.send(authCode); String msg = "mail from:<"+senderMail+">"; tcpMailClient.send(msg); msg = "rcpt to:<"+receiverMail+">"; tcpMailClient.send(msg); tcpMailClient.send("data"); msg="from:"+senderMail; tcpMailClient.send(msg); msg="to:"+receiverMail; tcpMailClient.send(msg); msg="subject:"+sub; tcpMailClient.send(msg); tcpMailClient.send("\n"); // tcpMailClient.send("這是一封測試java客戶端自動發送功能的郵件。"); tcpMailClient.send(content); tcpMailClient.send("."); tcpMailClient.send("quit"); }catch (Exception e){ taDisplay.appendText("服務器連接失敗!"+e.getMessage()+"\n"); } });
QQ客戶端的程序可以沿用之前的內容,詳見這篇:基於TCP協議網絡socket編程(java實現C/S通信)
五、QQ郵件發送效果演示
細心的讀者可以發現,在我點擊發送之后,程序卡斷了一會,其實就是因為我設置發送睡眠1000ms,實際可以發送成功,建議設置200ms或以上!
發送到自己QQ郵箱:
發送到自己的126郵箱進行測試:
六、總結
這一篇為QQ郵件發送客戶端程序設計的下篇,記錄了實現的關鍵部分,不用命令發送方式,類似日常發送郵件,直接編寫郵件標題、內容,然后直接發送即可,基本實現了QQ郵件發送客戶端的功能,操作更加簡便。根據本篇的知識內容,后面可以實現更加完善的QQ郵件發送小程序,增加一系列小功能!
如果覺得不錯歡迎“一鍵三連”哦,點贊收藏關注,有問題直接評論,交流學習!
我的博客園:https://www.cnblogs.com/chenzhenhong/p/14331829.html
我的CSDN博客:https://blog.csdn.net/Charzous/article/details/111148425