Java实现邮件发送程序设计(互联网程序设计课程 第7讲)


教学与实践目的:学会网络邮件发送的程序设计技术。

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

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

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

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

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

邮箱设置一定要开启smtp/pop3服务(以QQ邮箱为例,在[邮箱设置]中的[账户]中开启相关服务,QQ邮箱至少要提前14天完成整个工作,所以请提前完成该设置)。目前大部分邮箱开启服务时,需要设置第三方客户端使用的授权码,该授权码就是代替密码使用,目的是防止密码泄露, qq邮箱、163邮箱等均改成了这种使用方式,例如图7.1所示。

在这里插入图片描述

一、 程序设计第一步:准备一段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){
   java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
   String encodeMsg = null;
   try
   {
     encodeMsg = encoder.encodeToString(str.getBytes("UTF-8"));
   }
   catch (Exception e)
   {
     e.printStackTrace();
   }
   return encodeMsg;
 }
}

注意:(1)若用户密码验证过程中出现失败或提示需要开启SMTP终端服务,则通过浏览器的 web方式进入你的邮箱,更改邮箱的属性设置–>帐户,勾选或开启支持SMTP客户端软件;
(2)对于QQ邮箱还需要先设置独立密码,然后才能开启支持SMTP客户端软件(这个工作要提前一周做)。

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

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

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

AUTH LOGIN  //在输入auth login回车后,先粘贴base64程序编码的完整邮箱名并回车;再粘贴base64编码的授权码并回车,成功会有Authentication successful提示信息

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程序包下,并重构命名为TCPMailClientFX1.java,并添加针对用户名和密码的Base64编码功能;

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

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

AUTH LOGIN
//发送auth login后,先发送Base64编码的邮箱名,然后再发送Base64编码的授权码,成功后会有Authentication successful信息

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所示的邮件发送窗口(界面仅供参考,多行文本域TextArea控件用于输入邮件正文内容),并命名为TCPMailClientFX2.java,将手动操作的SMTP过程封装到程序中,实现邮件自动发送,注意不要短时间频繁发送,会被邮件服务器拒绝smtp服务(特别是不要上一个邮件还没发完,又点击发送按钮,很容易被拒绝服务)。
在这里插入图片描述

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

public void send(String msg) {
  //输出字符流,由Socket调用系统底层函数,经网卡发送字节流
  pw.println(msg);
  try {
    //进行邮件交互、发送smtp指令之间应该暂停一段时间
    Thread.sleep(400);
  } 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 = BASE64.encode(userName);
  tcpMailClient.send(msg);

  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:" + tfSubject.getText().trim();
tcpMailClient.send(msg);

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

//发送空行,隔开邮件头和邮件正文
tcpMailClient.send("\n");


  //省略……   

五、优化TCPMailClientFX2

(1)TCPMailClientFX2看不到服务器反馈信息,不利于了解发送状态和排查错误。例如自动发送邮件的程序,如果短时间发送次数过多,有时候邮件服务器会出现502错误,造成发送失败,或者会出现503 Send command HELO/EHLO first错误,所以有必要添加服务器反馈信息的显示。将程序优化,添加一个文本域(TextArea控件),用于显示邮件服务器的反馈信息,并尽量解决同时发送和显示服务器信息造成的卡顿。
为了解决以上问题,可以考虑在发送按钮的代码中,开两个新线程,将发送代码和显示服务器信息的代码放在两个单独线程中执行,并且先执行显示服务器信息的线程,暂停100毫秒后再执行发送线程,这样保证发送线程后执行。另外请注意,如果每次点击发送按钮都使用new Thread的方式创建新线程不是一个合理的方式,我们只额外需要两个线程,而这种方式显然会浪费资源,接收服务器信息的线程会不断增加,造成资源浪费和接收信息混乱,可以考虑使用固定线程数为2的线程池。优化后的程序参考界面如图7.3所示。注意:在上一个邮件发送的对话还没关闭前,不要再次点击发送按钮,很容易被拒绝服务。
在这里插入图片描述
(2)邮件发送者地址应该是《互联网程序设计》实验注册的邮件地址,邮件接收者地址为:,发送内容必须为:学号&姓名,例如20181111111&程旭元。用该程序发送这个指定邮件后,观察服务器反馈信息外,并查看自己的发送邮箱是否收到自动回复邮件。特别注意:只是发送成功还不一定就能获取分数(例如学生发送了有内容的邮件,教师163邮箱成功收到的学生邮件,但正文内容为空,原因在于163邮箱服务器的兼容性,为避免这种问题,一定要记住发送按钮的相关代码中,在正文内容之前发送一个换行,隔开邮件头和邮件正文),判断是否课堂实验成功的唯一标准是再次使用查分服务器,查询是否获得本次课程分。
特别要注意:邮件发送者地址、邮件接收者地址和邮件发送的内容必须按规定填写,没得到分数往往是上面的失误造成的。

六、扩展练习一 验证POP3(110)电子邮件接收协议

可以使用telnet 或 TCPMailClientFX1.java来验证,这里以telnet为例:

TELNET   pop.qq.com 110

USER 完整邮箱名  //不需要base64编码

PASS 授权码  //不需要base64编码 

STAT 或LIST  //stat统计当前邮箱数量和占用空间,list列出所有邮件信息,如果邮件特别多,list会比较耗时

RETR 2  //显示第2个邮件,注意,显示的都是编码的内容,正常无法阅读

 
QUIT  //退出

七、扩展练习二 JavaMail API 程序设计

为了简化邮件客户程序的开发,Oracle公司制定了JavaMail API,它封装了按照各种邮件通信协议,如IMAP、POP3和SMTP等与邮件服务器通信的细节,为Java应用程序提供了收发电子邮件的公共接口,用于开发邮件收发客户端,有兴趣的同学可进一步学习。
(1)下载JavaMail API类库文件javax.mail.jar并加入到项目:
对于加入外部jar,在项目开发中经常使用maven来进行配置,但对于我们的练习项目,完全可以手动下载jar,添加到项目中。该类库文件下载地址为:https://github.com/javaee/javamail/releases/download/JAVAMAIL-1_6_2/javax.mail.jar(或者在oc系统中下载)。对于idea,可以在项目工程下新建lib文件夹,将需要的外部jar包都拷贝到这个文件夹,如图7.4所示,
在这里插入图片描述

在这里插入图片描述
(2)阅读理解程序文件JavaMailAPIClient.java,将对应变量修改为自己的邮箱信息;
(3)运行及调试成功发送和接收邮件。
JavaMailAPIClient.java源程序:

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class JavaMailAPIClient {
  /*
  Session类表示邮件会话,是JavaMail API的最高层入口类。
  Session对象从java.util.Properties对象中获取配置信息,
  如邮件发送服务器的主机名或IP地址、接收邮件的协议、发送邮件的协议、
  用户名、口令及在整个应用程序中共享的其他信息。
  * */
  protected Session session;
  /*
  Store类表示接收邮件服务器上的注册账号的存储空间,
  通过Store类的getFolder()方法,可以访问用户的特定邮件夹。
  */
  protected Store store;
  /*
  Transport类根据指定的邮件发送协议(通常是 SMTP),
  通过指定的邮件发送服务器来发送邮件。
  Transport类是抽象类,它的静态方法send(Message)负责发送邮件
  * */
  protected Transport transport;

  //定义接收邮件服务器
  private String receiveHost = "pop.qq.com";
  //定义发送邮件服务器
  private String sendHost = "smtp.qq.com";
  //接收邮件协议
  private String receiveProtocol = "pop3";


  public void init() throws Exception {
    //设置邮箱属性
    Properties props = new Properties();
    props.put("mail.transport.protocol", "smtp");
    props.put("mail.store.protocol", receiveProtocol);
    props.put("mail.imap.class", "com.sun.mail.imap.IMAPStore");
    props.put("mail.smtp.class", "com.sun.mail.smtp.SMTPTransport");
    props.put("mail.smtp.host", sendHost);//设置发送邮件服务器

    //创建session对象
    session = Session.getDefaultInstance(props);

    //创建Store对象
    store = session.getStore(receiveProtocol);

    //连接到接收邮件服务器,地址和授权码不需要BASE64编码
    store.connect(receiveHost, "接收邮箱的完整地址", "该邮箱的授权码");
  }

  public void close() throws Exception {
    store.close();
  }

  /**
   * 发送邮件
   * @param fromAddr 发送邮件的邮箱地址
   * @param toAddr 接收邮件的邮箱地址
   */
  public void sendMail(String fromAddr, String toAddr)
      throws MessagingException {
    //发送邮件时,我们需要构造一个Message对象,
    // 然后调用Transport.send(Message)即可完成发送

    MimeMessage message = new MimeMessage(session);
    // 设置发送方地址
    message.setFrom(new InternetAddress(fromAddr));
    // 设置接收方地址
    message.setRecipient(Message.RecipientType.TO, new InternetAddress(toAddr));
    // 设置邮件主题
    message.setSubject("你好", "UTF-8");
    // 设置邮件正文
    message.setText("开心的一天!", "UTF-8");
    //发送(授权码不需要base64编码)
    Transport.send(message,fromAddr,"该发送邮箱的授权码");
  }

  /**
   * 接收邮件
   * @throws Exception
   */
  public void receiveMail() throws Exception {
    //inbox邮件夹是邮件账号的保留邮件夹(IMAP不允许用户删除该邮件夹),
    // 邮件服务器把所有接收到的新邮件都存在该邮件夹中
    browseMessagesFromFolder("inbox");
  }

  public void browseMessagesFromFolder(String folderName) throws Exception {
    Folder folder = store.getFolder(folderName);
    if (folder == null) {
      throw new Exception(folderName + "邮件夹不存在");
    }
    browseMessagesFromFolder(folder);
  }

  public void browseMessagesFromFolder(Folder folder) throws Exception {
    //Folder类代表邮件夹,邮件都放在邮件夹中
    folder.open(Folder.READ_ONLY);
    System.out.println("你的邮箱里有: " + folder.getMessageCount() + "封邮件");
    System.out.println("你的邮箱里有:  " + folder.getUnreadMessageCount() + "封未读邮件");

    //读邮件,Message类代表电子邮件。Message类提供了读取和设置邮件内容的方法
    for (int i = 1; i <= folder.getMessages().length; i++) {
      System.out.println("-------第" + i + "封邮件--------");
      System.out.print("其发送者是:");

      //Address类代表邮件地址,和Message 类一样,Address类也是个抽象类。
      // 常用的具体子类为javax.mail.internet.InternetAddress类
      InternetAddress[] addr = (InternetAddress[]) folder.getMessage(i).getFrom();

      //发送者地址
      System.out.println(addr[0].getAddress());
      System.out.print("发送的标题为:");
      String subject = folder.getMessage(i).getSubject();
      System.out.println(subject);
      System.out.print("发送日期为:");

      System.out.println(" 邮件内容为: ");
      System.out.println(folder.getMessage(i).getContent().toString());
    }

    folder.close(false);//关闭邮件夹,但是不要删除邮件夹中标记为"deleted"的邮件
  }


  public static void main(String[] args) throws Exception{
    JavaMailAPIClient mailClient = new JavaMailAPIClient();
    mailClient.init();
    mailClient.sendMail("发送邮箱地址","目的地邮箱地址");

//    mailClient.receiveMail();
    mailClient.close();
  }
}

项目结构

在这里插入图片描述

完整代码

chapter07/BASE64.java

package chapter07;

/**
 * @projectName: NetworkApp
 * @package: chapter07
 * @className: BASE64
 * @author: GCT
 * @description: TODO
 * @date: 2022/10/18 19:03
 * @version: 1.0
 */
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){
        java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
        String encodeMsg = null;
        try
        {
            encodeMsg = encoder.encodeToString(str.getBytes("UTF-8"));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return encodeMsg;
    }
}

chapter07/TCPMailClient.java

package chapter07;

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

/**
 * @projectName: NetworkApp
 * @package: chapter02
 * @className: TCPCilent
 * @author: GCT
 * @description: TODO
 * @date: 2022/9/4 18:06
 * @version: 1.0
 */
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 {
            //进行邮件交互、发送smtp指令之间应该暂停一段时间
            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();
        }
    }

    public static void main(String[] args) throws IOException{
        TCPMailClient tcpClient = new TCPMailClient("127.0.0.1", "8008");
        tcpClient.send("hello");
        System.out.println(tcpClient.receive());

    }
}

chapter07/TCPMailClientFX1.java

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 TCPMailClientFX1 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();

            try {
//                tcpMailClient = new TCPMailClient(smtpAddr,smtpPort);

                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();

                tcpMailClient.send("HELO gct");
                tcpMailClient.send("AUTH LOGIN");
//            base64 = new BASE64();
                String userName="";
                String authCode = "";
                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("完成");
            } catch (Exception e) {
                e.printStackTrace();
            }


//            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);
    }
}
//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);
//        }
//        }

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GCTTTTTT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值