欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java网络编程:邮件发送程序设计,SMPT传输协议实现(完整代码实现)

程序员文章站 2024-03-18 14:06:22
...

邮件发送程序设计

网络程序设计的精髓是什么?

就是客户端和服务器的对话和响应契约(协议)。 简单邮件传输协议SMTP可以很好地诠释这一点。

邮件传输协议包括SMTP(简单邮件传输协议,RFC821)及其扩充协议MIME;

邮件接收协议包括POP3和功能更强大的IMAP协议。

服务邮件发送的服务器其端口为25(开启ssl可能使用465或587端口),服务邮件接收的服务器端口为110。

邮箱设置一定要开启smtp/pop3服务,目前大部分邮箱开启服务时,需要设置第三方客户端使用的授权码,该授权码就是代替密码使用,目的是防止密码泄露, qq邮箱、163邮箱等均改成了这种使用方式,例如图7.1所示。

Java网络编程:邮件发送程序设计,SMPT传输协议实现(完整代码实现)

图7.1 QQ邮箱的授权码

一、 程序设计第一步:准备一段BASE64编码程序

新建一个Java包,建议包名:chapter07,并新建BASE64.java程序。

按SMTP过程,要成功地发送和接收邮件,用户名和密码需要BASE64编码后才能有效传输,这个类就是完成这个需求:

public class BASE64 {
 public static void main(String[] args) {
  String userName="你的完整邮箱名";
  String authCode = "你的邮箱授权码";
  //显示邮箱名的base64编码结果
  System.out.println(encode(userName));
  //显示授权码的base64编码结果
  System.out.println(encode(authCode));
 }

 public static String encode(String str) {
  return new sun.misc.BASE64Encoder().encode(str.getBytes());
 }
}

注意:

(1)若用户密码验证过程中出现失败或提示需要开启SMTP终端服务,则通过浏览器的 web方式进入你的邮箱,更改邮箱的属性设置–>帐户,勾选或开启支持SMTP客户端软件;

(2)对于QQ邮箱还需要先设置独立密码,然后才能开启支持SMTP客户端软件(这个工作要提前一周做)。

二、telnet手动体验SMTP协议过程1

操作系统默认没有安装telnet,可以通过控制面板=》程序和功能=》启用或关闭windows功能中选择telnet客户端进行安装。安装后,打开操作系统的命令行窗口,键入:telnet smtp.qq.com 25(完成三次握手连接),然后完成如下的对话过程,其中加粗加亮字体是smtp协议支持的命令,必须输入一致,其余内容根据具体情况填写,双斜杠内容是注释,不用输入:

HELO hostname  //hostname可以是IP或其他随意别名

AUTH LOGIN

//在输入auth login回车后,先粘贴哟个BASE64程序编码的完整邮箱名并回车;再粘贴编码的授权码并回车

MAIL FROM:<your mail address>  //在这里填写自己的邮箱地址,用于发送邮件(注意冒号后面别有空格,建议使用注册时的邮箱地址)

RCPT TO:<your mail address> //接收方的邮箱,在这里暂时填写和上面一样的邮箱地址,即自己发送邮件给自己,验证是否成功

DATA    //在输入data回车后,接下来开始发送邮件头相关内容

Subject: this is simple mail   // 邮件的标题  

//在这里再多发送一行空行,来分隔邮件内容,下面就是邮件正文内容

Hello!

 很好!  

//控制台中中文会变成?的乱码,但不影响接受者接收到中文内容

.  //在邮件正文发送完毕后,单独用一行输入一个小圆点,作为结束标志,然后回车

QUIT  //结束通信(含4次握手断开)

知识点:以上基于命令行窗口的邮件发送方法,可以让你不需要其他软件的帮助就可以完成简单邮件的发送与接收。

三、程序设计第二步:体验SMTP协议过程2

现在用自己的程序代替telnet,来验证smtp发送给邮件的过程:

(1)将第3讲原有的TCPClient.java程序复制重构到chapter07程序包下;

(2)将第3讲TCPClientThreadFX.java对话窗口程序,复制到chapter07程序包下,并重构命名为TCPMailClientFX.java,并添加针对用户名和密码的Base64编码功能;

(3)运行TCPMailClientFX.java程序,ip文本框填写smtp.qq.com,端口文本框填写25,连接后按照如下的对话顺序通过send按钮发送命令,注意,和第一次体验有所不同,增加了发件人信息和收件人信息:

HELO hostname  //hostname可以是IP或其他随意别名

AUTH LOGIN

//发送auth login后,先发送Base64编码的邮箱名,然后再发送Base64编码的授权码

MAIL FROM:<your mail address>  //在这里填写《互联网程序设计》实验注册的邮箱地址,用于发送邮件(注意冒号后面别有空格)

RCPT TO:<other mail address> //接收方的邮箱,在这里用自己另外的邮箱或同学的邮箱地址测试。

 

DATA    //在输入data回车后,接下来开始设置邮件头,邮件头除了邮件标题,还包括发件人地址和收件人地址

From:@qq.com // 发件人的邮箱地址

Subject: 给同学的一封测试邮件   // 邮件的标题  

To:@qq.com  //会显示在邮件接收者栏上

// 在这里再多发送一行空行,来分隔邮件内容,下面是邮件正文内容

I am 同学  //邮件正文内容

.  //在邮件正文发送完毕后,单独发送一个小圆点,作为结束标志

QUIT  //发送quit结束通信(含4次握手断开)

 

用自己的图形界面进行smtp交互发送邮件,是否比telnet方便?

注意:

判断邮件是否成功发送,可查看你“已发送”箱中该邮件的发送状态或是否有发送失败的提示或收到自动回复邮件(仅供参考)。

四、窗口程序实现自动发邮件

(1)设置如图7.2所示的邮件发送窗口(供参考),并命名为TCPMailClientFX2.java,将手动操作的SMTP过程封装到程序中,实现邮件自动发送,注意不要短时间频繁发送,会被邮件服务器拒绝smtp服务。

Java网络编程:邮件发送程序设计,SMPT传输协议实现(完整代码实现)

图7.2 邮件发送窗口

(2)将TCPClient.java复制重构,并命名为TCPMailClient.java,并修改其中的发送方法如下:

public void send(String msg) {
 //输出字符流,由Socket调用系统底层函数,经网卡发送字节流
 pw.println(msg);
 try {
  //进行邮件交互、发送smtp指令之间应该暂停一段时间
  Thread.sleep(200);
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
}

注意:邮件命令需要一行一行地发送,使用程序自动发送过程中需要设置一定的睡眠等待时间。

(3)“发送按钮”的部分代码如下:



String smtpAddr = tfSmtpAddr.getText().trim();
String smtpPort = tfSmtpPort.getText().trim();
try {
 tcpMailClient = new TCPMailClient(smtpAddr, smtpPort);
 tcpMailClient.send("HELO myfriend");

 tcpMailClient.send("AUTH LOGIN");

 String username = "你的完整邮箱地址";
 String authCode = "申请的授权码";

 String msg = BASE64Encoder.encode(username);
 tcpMailClient.send(msg);

 msg = BASE64Encoder.encode(authCode);
 tcpMailClient.send(msg);

 msg = "MAIL FROM:<" + tfSenderAddr.getText().trim() + ">";
 tcpMailClient.send(msg);

 msg = "RCPT TO:<" + tfRecieverAddr.getText().trim() + ">";
 tcpMailClient.send(msg);

 msg = "DATA";
 tcpMailClient.send(msg);

 msg = "FROM:" + tfSenderAddr.getText().trim();
 tcpMailClient.send(msg);



 

完整代码实现

TCPClientFX

package chapter07;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.*;
import java.net.Socket;
import java.util.Optional;

public class TCPClientFX extends Application {
    private Button btnExit = new Button("退出");
    private Button btnSend = new Button("发送");
    private Button btnOpen = new Button("加载");
    private Button btnSave = new Button("保存");
    private Button btnConnect = new Button("连接");
    //待发送信息的文本框
    private TextField inputField = new TextField("这是邮件内容");

    private TextField from = new TextField("aaa@qq.com");
    private TextField to = new TextField("aaa@qq.com");

    private TextField subject = new TextField("邮件标题");
    //显示信息的文本区域
    private TextArea receiveArea = new TextArea();
    //接受ip地址的单行文本框
    private TextField ipAddressField = new TextField("smtp.qq.com");
    //接受port的单行文本框
    private TextField ipPortField = new TextField("25");
    //    private static TCPClient tcpClient;
    private Socket socket;
    private BufferedReader bufferedReader;
    private PrintWriter printWriter;
    private TCPMailClient tcpMailClient;

    public void start(Stage primaryStage) throws IOException {
//        primaryStage.setTitle("登录查看成绩");
        BorderPane mainPane = new BorderPane();
        //输入区域
        VBox vBox = setVBoxArea();
        mainPane.setCenter(vBox);
        //底部按钮区域
        HBox hBox = setHBoxArea();
        mainPane.setBottom(hBox);
        //顶部ip相关区域
        HBox hBox1 = setTopIpArea();
        mainPane.setTop(hBox1);
        btnExitAction();
        btnSendAction();
        btnOpenAction(primaryStage);
        btnSaveAction(primaryStage);
        btnConnectAction();
        Scene scene = new Scene(mainPane, 700, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void btnConnectAction() throws IOException {
        btnConnect.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                try {
//                    tcpClient = new TCPClient("127.0.0.1", 8008);
                    String ip = ipAddressField.getText();
                    int port = Integer.parseInt(ipPortField.getText());
                    socket = new Socket(ip, port);
                    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
//        socketClient = new SocketClient("172.16.229.253", 8008);
    }

    private void btnSaveAction(Stage primaryStage) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        DirectoryChooser directoryChooser = new DirectoryChooser();
                        File file = directoryChooser.showDialog(primaryStage);
                        if (file == null || !file.isDirectory()) {
                            Alert alert = new Alert(Alert.AlertType.ERROR, "请选择文件夹!");
                            Optional<ButtonType> buttonType = alert.showAndWait();
                            return;
                        }
                        String exportFilePath = file.getAbsolutePath();
                        String message = receiveArea.getText();
                        try (BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(exportFilePath + "/temp.txt")))) {
                            bufferedWriter.write(message);
                            bufferedWriter.flush();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }).start();
    }

    private void btnOpenAction(Stage primaryStage) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                btnOpen.setOnMouseClicked(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        FileChooser fileChooser = new FileChooser();
                        File file = fileChooser.showOpenDialog(primaryStage);
                        if (file != null && file.canRead()) {
                            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));) {
                                StringBuilder stringBuilder = new StringBuilder();
                                String line;
                                while ((line = bufferedReader.readLine()) != null) {
                                    stringBuilder.append(line);
                                }
                                receiveArea.setText(stringBuilder.toString());
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Alert alert = new Alert(Alert.AlertType.ERROR, "请选择文件!");
                            alert.showAndWait();
                            return;
                        }
                    }
                });
            }
        }).start();
    }

    private void btnSendAction() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                btnSend.setOnMouseClicked(mouseEvent -> {
                    String host = ipAddressField.getText().trim();
                    String port = ipPortField.getText();
                    try {
                        tcpMailClient = new TCPMailClient(host, port);
                        tcpMailClient.send("Helo liyuan");
                        tcpMailClient.send("auth login");
                        String username = "MjgxMjMyOTQyNUBxcS5jb20=";
                        tcpMailClient.send(username);
                        String code = "aHV3dGR6Y3FlZW9qZGRnag==";
                        tcpMailClient.send(code);
                        String fromMail = "mail from: <" + from.getText().trim() + ">";
                        tcpMailClient.send(fromMail);
                        String toMail = "rcpt to: <" + to.getText().trim() + ">";
                        tcpMailClient.send(toMail);
                        String data = "data";
                        tcpMailClient.send(data);
                        tcpMailClient.send("from:"+from.getText().trim());
                        String content = "subject:"+subject.getText().trim();
                        tcpMailClient.send(content);
                        tcpMailClient.send(inputField.getText());
                        tcpMailClient.send(".");

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
            }
        }).start();
    }

    private void btnExitAction() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                btnExit.setOnMouseClicked(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        if (printWriter != null) {
                            printWriter.println("bye");
                        } else {
                            System.exit(-1);
                        }
                        //                            socket.close();
                    }
                });
            }
        }).start();
    }

    private HBox setTopIpArea() {
        HBox hBox1 = new HBox();
        Label ipAddressLabel = new Label("邮件服务器地址:");
        ipAddressLabel.setLabelFor(ipAddressField);
        Label ipPortLabel = new Label("邮件服务器端口:");
        ipPortLabel.setLabelFor(ipPortField);
        ipPortLabel.setAlignment(Pos.BASELINE_CENTER);
        btnConnect = new Button("连接");
        hBox1.getChildren().addAll(ipAddressLabel, ipAddressField, ipPortLabel, ipPortField, btnConnect);
        hBox1.setAlignment(Pos.BOTTOM_CENTER);
        hBox1.setSpacing(15);
        hBox1.setPadding(new Insets(20, 20, 0, 20));
        return hBox1;
    }

    private VBox setVBoxArea() {
        //内容显示区域
        VBox vBox = new VBox();
        vBox.setSpacing(10);//各控件之间的间隔
        //VBox面板中的内容距离四周的留空区域
        vBox.setPadding(new Insets(10, 20, 10, 20));
        vBox.getChildren().addAll(new Label("发送方:"), from, new Label("接收方:"), to, new Label("邮件标题"), subject, new Label("信息显示区:"),
                receiveArea, new Label("信息输入区:"), inputField);
        //设置显示信息区的文本区域可以纵向自动扩充范围
        receiveArea.setEditable(false);
        VBox.setVgrow(receiveArea, Priority.ALWAYS);
        return vBox;
    }

    private HBox setHBoxArea() {
        HBox hBox = new HBox();
        hBox.setSpacing(10);
        hBox.setPadding(new Insets(10, 20, 10, 20));
        hBox.setAlignment(Pos.CENTER_RIGHT);
        hBox.getChildren().addAll(btnSend, btnSave, btnOpen, btnExit);
        return hBox;
    }


}

TCPClient

//package chapter02;
//
//import java.io.*;
//import java.net.Socket;
//
//public class TCPClient {
//    private Socket socket;
//    private PrintWriter pw;
//    private BufferedReader br;
//
//    public TCPClient(String ip,String port) throws IOException {
//        socket = new Socket(ip, Integer.parseInt(port));
//        OutputStream socketOut = socket.getOutputStream();
//        pw = new PrintWriter(
//                new OutputStreamWriter(socketOut, "utf-8"), true);
//        InputStream socketIn = socket.getInputStream();
//        br = new BufferedReader(
//                new InputStreamReader(socketIn, "utf-8"));
//    }
//        public void send(String msg) {
//            pw.println(msg);
//        }
//        public String receive(){
//            String msg = null;
//            try {
//                msg=br.readLine();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            return msg;
//        }
//        public void close(){
//            try {
//                if(socket != null){
//                    socket.close();
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//
//    public static void main(String[] args) throws IOException {
//        TCPClient tcpClient = new TCPClient("127.0.0.1" ,"8008");
//        tcpClient.send("hello");//发送一串字符
//        //接收服务器返回的字符串并显示
//        System.out.println(tcpClient.receive());
//    }
//}

package chapter07;

import java.io.*;
import java.net.Socket;

public class TCPMailClient {
    private Socket socket; //定义套接字
    //定义字符输入流和输出流
    private PrintWriter pw;
    private BufferedReader br;

    public TCPMailClient(String ip, String port) throws IOException {
        //主动向服务器发起连接,实现TCP的三次握手过程
        //如果不成功,则抛出错误信息,其错误信息交由调用者处理
        socket = new Socket(ip, Integer.parseInt(port));

        //得到网络输出字节流地址,并封装成网络输出字符流
        OutputStream socketOut = socket.getOutputStream();
        pw = new PrintWriter( // 设置最后一个参数为true,表示自动flush数据
                new OutputStreamWriter(//设置utf-8编码
                        socketOut, "utf-8"), true);

        //得到网络输入字节流地址,并封装成网络输入字符流
        InputStream socketIn = socket.getInputStream();
        br = new BufferedReader(
                new InputStreamReader(socketIn, "utf-8"));
    }

    public void send(String msg) {
        //输出字符流,由Socket调用系统底层函数,经网卡发送字节流
        pw.println(msg);
        try{
            Thread.sleep(200);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public String receive() {
        String msg = null;
        try {
            //从网络输入字符流中读信息,每次只能接受一行信息
            //如果不够一行(无行结束符),则该语句阻塞,
            // 直到条件满足,程序才往下运行
            msg = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return msg;
    }
    public void close() {
        try {
            if (socket != null) {
                //关闭socket连接及相关的输入输出流,实现四次握手断开
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //本机模块内测试与运行,需先运行TCPServer
    public static void main(String[] args) throws IOException {
        TCPMailClient tcpMailClient = new TCPMailClient("127.0.0.1" ,"8008");
        tcpMailClient.send("hello");//发送一串字符
        //接收服务器返回的字符串并显示
        System.out.println(tcpMailClient.receive());
    }
}

TCPMailClientFX2

package chapter07;

import chapter01.TextFileIO;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import sun.misc.BASE64Encoder;

import java.io.IOException;

public class TCPMailClientFX2 extends Application {
    private Button btnExit = new Button("退出");
    private Button btnSend = new Button("发送");
    private Button btnConnect = new Button("连接");
    //待发送信息的文本框
    private TextField tfSend = new TextField();
    private TextField tfSmtpAddr = new TextField("smtp.qq.com");
    private TextField tfSmtpPort = new TextField("25");
    private TextField tfSenderAddr = new TextField();
    private TextField tfRecieverAddr = new TextField();
    private TextField mtitle = new TextField();
    //显示信息的文本区域
    private TextArea taMainText = new TextArea();
    private TextArea taSerMsg = new TextArea();
    private TextFileIO textFileIO = new TextFileIO();
    private TCPMailClient tcpMailClient;
    Thread readThread;
    BASE64 base64;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        BorderPane mainPane = new BorderPane();
        // 顶部输入
        HBox tophbox = new HBox();
        tophbox.setSpacing(10);
        tophbox.setPadding(new Insets(10,20,10,20));
        tophbox.setAlignment(Pos.CENTER);
        tophbox.getChildren().addAll(new Label("邮件服务器地址:"), tfSmtpAddr,new Label("邮件服务器端口:"), tfSmtpPort);
        HBox tophbox1 = new HBox();
        tophbox1.setSpacing(10);
        tophbox1.setPadding(new Insets(10,20,10,20));
        tophbox1.setAlignment(Pos.CENTER);
        tophbox1.getChildren().addAll(new Label("邮件发送者地址:"), tfSenderAddr,new Label("邮件发送者端口:"), tfRecieverAddr);
        HBox tophbox2 = new HBox();
        tophbox2.setSpacing(10);
        tophbox2.setPadding(new Insets(10,20,10,20));
        tophbox2.setAlignment(Pos.CENTER);
        mtitle.setPrefWidth(470);
        tophbox2.getChildren().addAll(new Label("邮件标题:"),mtitle);
        //内容显示区域
        VBox InVbox = new VBox();
        InVbox.setSpacing(10);
        InVbox.setPadding(new Insets(10, 20, 10, 20));
        InVbox.getChildren().addAll(new Label("邮件正文:"),taMainText);
        InVbox.prefHeightProperty().bind(primaryStage.heightProperty());

        VBox InVbox1 = new VBox();
        InVbox1.setSpacing(10);
        InVbox1.setPadding(new Insets(10, 20, 10, 20));
        InVbox1.getChildren().addAll(new Label("服务器反馈信息:"),taSerMsg);
        taMainText.setWrapText(true);
        taSerMsg.setWrapText(true);
        taMainText.heightProperty();
        VBox.setVgrow(taMainText, Priority.ALWAYS);
        VBox.setVgrow(taSerMsg, Priority.ALWAYS);
        HBox mainhbox=new HBox();
        mainhbox.setSpacing(10);
        mainhbox.setPadding(new Insets(10,20,10,20));
        mainhbox.setAlignment(Pos.CENTER);
        mainhbox.getChildren().addAll(InVbox,InVbox1);
//        HBox.setHgrow(InVbox,Priority.ALWAYS);
//        HBox.setHgrow(InVbox1,Priority.ALWAYS);


        VBox vBox = new VBox();
        vBox.setSpacing(10);//各控件之间的间隔
        //VBox面板中的内容距离四周的留空区域
        vBox.setPadding(new Insets(10, 20, 10, 20));
        vBox.getChildren().addAll(tophbox,tophbox1,tophbox2,mainhbox);
        //设置显示信息区的文本区域可以纵向自动扩充范围
        mainPane.setCenter(vBox);
        //底部按钮区域
        HBox hBox = new HBox();
        hBox.setSpacing(10);
        hBox.setPadding(new Insets(10, 20, 10, 20));
        hBox.setAlignment(Pos.CENTER_RIGHT);
        hBox.getChildren().addAll(btnSend,  btnExit);
        mainPane.setBottom(hBox);
        Scene scene = new Scene(mainPane, 800, 500);
        primaryStage.setScene(scene);
        primaryStage.show();

        String ip = tfSmtpAddr.getText().trim();
        String port = tfSmtpPort.getText().trim();
        try {
            tcpMailClient = new TCPMailClient(ip,port);
            // 多线程不需要这一条了
//                String firstMsg = tcpClient.receive();
//                taDisplay.appendText(firstMsg+"\n");
            btnSend.setDisable(false);
            btnConnect.setDisable(true);
            //多线程方法

            readThread = new Thread(()->{
                String msg = null;
                while((msg = tcpMailClient.receive())!=null){
                    String msgTemp = msg;
                    Platform.runLater(()->{
                        taSerMsg.appendText(msgTemp+"\n");
                    });
                }
                Platform.runLater(()->{
                    taSerMsg.appendText("对话已关闭!\n");
                });
            });
            readThread.start();
        } catch (IOException e) {
            taSerMsg.appendText("服务器连接失败"+e.getMessage()+"\n");
            btnSend.setDisable(true);
        }
//        btnSend.setDisable(true);
//        btnConnect.setOnAction(event -> {
//            String ip = tfSmtpAddr.getText().trim();
//            String port = tfSmtpPort.getText().trim();
//            try {
//                tcpMailClient = new TCPMailClient(ip,port);
//                // 多线程不需要这一条了
                String firstMsg = tcpClient.receive();
                taDisplay.appendText(firstMsg+"\n");
//                btnSend.setDisable(false);
//                btnConnect.setDisable(true);
//                //多线程方法
//
//                readThread = new Thread(()->{
//                    String msg = null;
//                    while((msg = tcpMailClient.receive())!=null){
//                        String msgTemp = msg;
//                        Platform.runLater(()->{
//                            taSerMsg.appendText(msgTemp+"\n");
//                        });
//                    }
//                    Platform.runLater(()->{
//                        taSerMsg.appendText("对话已关闭!\n");
//                    });
//                });
//                readThread.start();
//            } catch (IOException e) {
//                taSerMsg.appendText("服务器连接失败"+e.getMessage()+"\n");
//                btnSend.setDisable(true);
//            }
//        });
//        btnConnect.fire();
        btnExit.setOnAction(event -> {
            endSystem();
        });
        primaryStage.setOnCloseRequest(event -> {
            endSystem();
        });
        btnSend.setOnAction(event -> {
            String smtpAddr = tfSmtpAddr.getText().trim();
            String smtpPort = tfSmtpPort.getText().trim();

            //                tcpMailClient = new TCPMailClient(smtpAddr,smtpPort);
            tcpMailClient.send("HELO Viper");
            tcpMailClient.send("AUTH LOGIN");
//            base64 = new BASE64();
            String userName="aaa@qq.com";
            String authCode = "rbrxsegwmwjgbbge";
            String msg = BASE64.encode(userName);
            System.out.println(msg);
            tcpMailClient.send(msg);
            System.out.println("userName send");
            msg = BASE64.encode(authCode);
            tcpMailClient.send(msg);

            msg = "MAIL FROM:<"+ tfSenderAddr.getText().trim()+">";
            tcpMailClient.send(msg);
            msg = "RCPT TO:<"+ tfRecieverAddr.getText().trim()+">";
            tcpMailClient.send(msg);
            msg = "DATA";
            tcpMailClient.send(msg);
            msg = "FROM:"+tfSenderAddr.getText().trim();
            tcpMailClient.send(msg);
            msg = "Subject:"+mtitle.getText().trim();
            tcpMailClient.send(msg);
            msg = "To:"+tfRecieverAddr.getText().trim();
            tcpMailClient.send(msg);
            msg = "\n";
            tcpMailClient.send(msg);
            msg = taMainText.getText();
            tcpMailClient.send(msg);

            msg = ".";
            tcpMailClient.send(msg);
            msg = "QUIT";
            tcpMailClient.send(msg);
            System.out.println("完成");

//            String sendMsg = tfSend.getText();
//            if(sendMsg.equals("bye")) {
//                btnConnect.setDisable(false);
//                btnSend.setDisable(true);
//            }
//            tcpMailClient.send(sendMsg);//向服务器发送一串字符
//            taDisplay.appendText("客户端发送:" + sendMsg + "\n");
//            //注释掉这句话,和线程不冲突,不会卡死。
            String receiveMsg = tcpClient.receive();//从服务器接收一行字符
            taDisplay.appendText(receiveMsg + "\n");
//            tfSend.clear();
        });


    }

    private void endSystem() {
        if(tcpMailClient != null){
            //向服务器发送关闭连接的约定信息
            tcpMailClient.send("bye");
            tcpMailClient.close();
        }
        System.exit(0);
    }
}
pMailClient.send(msg);
            System.out.println("完成");

//            String sendMsg = tfSend.getText();
//            if(sendMsg.equals("bye")) {
//                btnConnect.setDisable(false);
//                btnSend.setDisable(true);
//            }
//            tcpMailClient.send(sendMsg);//向服务器发送一串字符
//            taDisplay.appendText("客户端发送:" + sendMsg + "\n");
//            //注释掉这句话,和线程不冲突,不会卡死。
            String receiveMsg = tcpClient.receive();//从服务器接收一行字符
            taDisplay.appendText(receiveMsg + "\n");
//            tfSend.clear();
        });


    }

    private void endSystem() {
        if(tcpMailClient != null){
            //向服务器发送关闭连接的约定信息
            tcpMailClient.send("bye");
            tcpMailClient.close();
        }
        System.exit(0);
    }
}