Java實現QQ郵件傳送客戶端

Charzueus發表於2021-01-29

目錄

一、前言:QQ郵件傳送程式

二、封裝SMTP操作

三、實現多執行緒接收

四、QQ郵件客戶端介面設計

    1、連線按鈕

    2、傳送按鈕 

五、QQ郵件傳送效果演示

六、總結


一、前言: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、連線按鈕

Java實現QQ郵件傳送客戶端
//連線按鈕
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();
    }
 
});
View Code

2、傳送按鈕 

Java實現QQ郵件傳送客戶端
//傳送按鈕
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");
    }
});
View Code

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

版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。
本文連結:https://blog.csdn.net/Charzous/article/details/111148425

相關文章