邮件发送程序设计

一、背景简介

邮件传输协议包括SMTP(简单邮件传输协议,RFC821)及其扩充协议MIME;邮件接收协议包括POP3和功能更强大的IMAP协议;服务邮件发送的服务器其端口为25(开启ssl可能使用465或587端口),服务邮件接收的服务器端口为110。

1、 SMTP(简单邮件传输协议)

SMTP是一种提供可靠且有效的电子邮件传输的协议。SMTP是建立在FTP文件传输服务上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。在SMTP握手阶段,客户端向SMTP服务器分别指定发件人和收件人的电子邮件地址。握手阶段完毕,SMTP服务器把客户端发出的邮件消息添加到发信队列中,通过TCP提供的可靠数据传输服务把该消息准确地传送到收件人的服务器。

连接和发送过程如下:
(1)建立TCP连接。
(2)客户端发送 HELO 命令以标识发件人自己的身份,客户端发送 MAIL 命令。服务器以OK作为响应,表明准备接收。
(3)使用 AUTH 命令登录SMTP服务器,输入用户名和密码(注意,用户名和密码都需要base64加密)。
(4)客户端发送 RCPT 命令,标识该电子邮件的计划接收人,可以有多个RCPT行。服务器以OK作为响应,表示愿意为收件人发送邮件。
(5)协商结束后,使用 DATA 命令发送。
(6)以 . 号表示结束,输入内容一起发送出去,结束此次发送,用 QUIT 命令退出。

2、设置QQ邮箱

(1)对于QQ邮箱需要先设置独立密码,然后才能开启支持SMTP客户端软件
(2) 在设置->账号中启动POP3/SMTP服务和IMAP/SMTP服务
请添加图片描述
(3) 发送指定短信后即可获得授权码

二、BASE64编码程序

为什么需要base64编码程序?因为在SMTP过程中,使用 AUTH 命令登录SMTP服务器,输入用户名和密码需要base64加密后才能有效传输!

package chapter07;
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、发送方法

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


2、发送按钮部分代码

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

  //省略……   

3、TCPMailClientFX2完整代码

package chapter07;

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 java.io.IOException;

public class TCPMailClientFX2 extends Application {
    private Button btnExit = new Button("退出");
    private Button btnSend = new Button("发送");

    private TextArea taSend = new TextArea();
    private TextArea taDisplay = new TextArea();

    private TextField tfIP = new TextField("smtp.qq.com");
    private TextField tfPort = new TextField("25");

    private TextField tfSender = new TextField("你的邮件地址");
    private TextField tfReceiver = new TextField("目的邮件地址");
    private TextField tfTitle = new TextField();

    private TCPMailClient tcpMailClient;
    private Thread readThread;
    private Thread sendThread;

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

    @Override
    public void start(Stage primaryStage) {
        BorderPane mainPane = new BorderPane();

        VBox head = new VBox();
        HBox connHbox = new HBox();
        connHbox.setAlignment(Pos.CENTER);
        connHbox.setSpacing(10);
        connHbox.getChildren().addAll(new Label("邮件服务器地址:"), tfIP, new Label("邮件服务器端口:"), tfPort);

        HBox addrHbox = new HBox();
        addrHbox.setAlignment(Pos.CENTER);
        addrHbox.setSpacing(10);
        addrHbox.getChildren().addAll(new Label("邮件发送者地址:"), tfSender, new Label("邮件接收者地址:"), tfReceiver);

        HBox titleHbox = new HBox();
        tfTitle.setPrefWidth(400);
        titleHbox.setAlignment(Pos.CENTER);
        titleHbox.getChildren().addAll(new Label("邮件标题:"), tfTitle);


        head.getChildren().addAll(connHbox, addrHbox, titleHbox);
        head.setSpacing(20);
        mainPane.setTop(head);

        HBox middle = new HBox();
        middle.setAlignment(Pos.CENTER);
        VBox vBox = new VBox();
        vBox.setSpacing(10);
        vBox.setPadding(new Insets(10, 20, 10, 20));
        // 设置发送信息的文本框
        // 自动换行
        taDisplay.setWrapText(true);
        // 只读
        taDisplay.setEditable(false);
        vBox.getChildren().addAll(new Label("信息显示区: "), taDisplay);
        VBox.setVgrow(taDisplay, Priority.ALWAYS);

        VBox mailVBox = new VBox();
        mailVBox.setPadding(new Insets(10, 20, 10, 20));
        // 设置发送信息的文本框
        // 自动换行
        taSend.setWrapText(true);
        mailVBox.getChildren().addAll(new Label("邮件正文: "), taSend);
        mailVBox.setSpacing(10);
        VBox.setVgrow(taSend, Priority.ALWAYS);

        middle.getChildren().addAll(mailVBox, vBox);
        mainPane.setCenter(middle);

        HBox hBox = new HBox();
        hBox.setSpacing(10);
        hBox.setPadding(new Insets(10, 20, 10, 20));
        hBox.setAlignment(Pos.CENTER_RIGHT);

        String ip = tfIP.getText().trim();
        String port = tfPort.getText().trim();

        btnExit.setOnAction(event -> {
            exit();
        });
        btnSend.setOnAction(event -> {
            String smtpAddr = tfIP.getText().trim();
            String smtpPort = tfPort.getText().trim();
            try {
                tcpMailClient = new TCPMailClient(smtpAddr, smtpPort);
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 启用接收信息进程
            readThread = new Thread(() -> {
                String msg = null;
                while ((msg = tcpMailClient.receive()) != null) {
                    String msgTemp = msg;
                    Platform.runLater(() -> {
                        taDisplay.appendText(msgTemp + "\n");
                    });
                }
                Platform.runLater(() -> {
                    taDisplay.appendText("对话已关闭!\n");
            readThread.start();

            sendThread = new Thread(() -> {
                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:<" + tfSender.getText().trim() + ">";
                tcpMailClient.send(msg);

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

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

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


                msg = "SUBJECT:" + tfTitle.getText().trim();

                tcpMailClient.send(msg);

                msg = "TO:" + tfReceiver.getText().trim();

                tcpMailClient.send(msg);

                tcpMailClient.send("\n");
                
                msg = "";
                tcpMailClient.send(msg);

                msg = taSend.getText().trim();
                tcpMailClient.send(msg);

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

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


                btnSend.setDisable(false);

            });
            sendThread.start();
            // 禁用发送按钮
            btnSend.setDisable(true);
        });


        hBox.getChildren().addAll(btnSend, btnExit);
        mainPane.setBottom(hBox);
        Scene scene = new Scene(mainPane, 700, 400);

        // 响应窗体关闭
        primaryStage.setOnCloseRequest(event -> {
            exit();
        });

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void exit() {
        // 系统退出时,单独的读线程没有结束,因此会出现异常。
        // 解决方案:在这里通知线程中断,在线程循环中增加条件检测当前线程是否被中断。
//        readThread.interrupt();
        readThread.stop();
        System.exit(0);
    }

}

四、实验结果请添加图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值