目錄
一、前言: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