在没有 Java Mail API 或任何第三方 API 的情况下用 Java 编写 SMTP 客户端

问题描述

我问这个,我非常尴尬。我正在实现一个 SMTP 客户端,不使用 Java MAIL API 或任何其他第三方加密库,无论是否开源,因为我不喜欢第三方 API,并希望按照我的方式做事。我知道这很傲慢,但这就是我的方式。所以,到目前为止我有这个:-

import java.net.socket;
import java.util.Scanner;
import java.util.Base64;

public class SocketSample
{
    public static void main(String[] args) throws Exception
    {
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        String uid = Base64.getEncoder().encodetoString("xyz@gmail.com".getBytes());
        String pwd = Base64.getEncoder().encodetoString("abc123".getBytes());
        System.out.println(uid);
        System.out.println(pwd);
        //char ans = '\0';
        Scanner scanner = new Scanner(system.in);
        System.out.print("Enter host: ");
        String host = scanner.nextLine();
        System.out.print("Enter port: ");
        int port = Integer.parseInt(scanner.nextLine());
        socket = new Socket();
        socket.connect(new InetSocketAddress(host,port));
        if (socket.isConnected())
        {

            System.out.println("Socket connected.");
            out = socket.getoutputStream();
            String command = "HELO " + host + "\r\n";
            byte[] data = command.getBytes();
            out.write(data);
            out.flush();
            //
            in = socket.getInputStream();
            int c = '\0';
            while (c != -1)
            {
                c = in.read();
                System.out.print((char) c);
            }
            //
            command = "STARTTLS\r\n";
            data = command.getBytes();
            out.write(data);
            out.flush();
            c = '\0';
            while(c != -1)
            {
                c = in.read();
                System.out.print((char) c);
            }
            /*
            command = "HELO " + host + "\r\n";
            data = Base64.getEncoder().encodetoString(command.getBytes()).getBytes();
            out.write(data);
            out.flush();
            c = '\0';
            while(c != -1)
            {
                c = in.read();
                System.out.print((char) c);
            }
            */
            System.out.println(uid);
            System.out.println(pwd);
            command = "AUTH PLAIN " + uid + "\r\n";
            data = command.getBytes();
            out.write(data);
            out.flush();
            c = '\0';
            while(c != -1)
            {
                c = in.read();
                System.out.print((char) c);
            }
            //
            command = pwd + "\r\n";
            data = command.getBytes();
            out.write(data);
            out.flush();
            c = '\0';
            while (c != -1)
            {
                c = in.read();
                System.out.print((char) c);
            }
        }
        out.close();
        in.close();
        socket.close();
        System.exit(0);
    }
}

这会卡在 STARTTLS 上,虽然我用 base64 编码用户名和密码,但它仍然卡在那里。我做错了什么?请帮帮我。 谢谢! P. S.: - 我是 Java 新手。

解决方法

我建议依靠 inputStream::available() 方法来阅读内容。这样,你可以创建一个像

这样的辅助方法
private static String readResponse(InputStream inputStream) throws IOException {
    int c;
    StringBuilder raw = new StringBuilder();
    do {
        c = inputStream.read();
        raw.append((char) c);
    } while (inputStream.available() > 0);
    return raw.toString();
}

然后替换代码块

int c = '\0';
while (c != -1) {
    c = in.read();
    System.out.print((char) c);
}

System.out.println(readResponse(in)); 上。

那样您将继续执行 STARTTLS 命令,但我不确定您是否应该发送它,因为使用普通 Sockets 自己实现 TLS 并不是您在家中想要做的事情任务。