【问题标题】:Writing SMTP Client in Java without Java Mail API or any third party API在没有 Java Mail API 或任何第三方 API 的情况下用 Java 编写 SMTP 客户端
【发布时间】:2021-10-06 02:32:15
【问题描述】:

我在问这个问题,我感到非常尴尬。我在不使用 Java MAIL API 或任何其他第三方加密库的情况下实现 SMTP 客户端,无论是否开源,因为我不喜欢第三方 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 新手。

【问题讨论】:

  • 我不确定我是否应该鼓励你,但in.read() 在对方关闭之前不会返回 -1。如果您要做到这一点,甚至取得初步的成功,我建议您对原始协议有 100% 的把握。迹象表明你不是……
  • 非常感谢先生。是的,我对协议的了解至少可以说是初级的。我正在阅读它的规格和其他阅读我确信这个过程是正确的,但是在一些地方的错误是在选择正确的阅读器和编写器,使用正确格式的命令等。你能给我更多的提示吗,先生?谢谢。
  • 我的建议是在代码中标注服务器要发送的内容以及作为客户端要发送的内容
  • 非常感谢您,先生。我已经达到了我愿意的程度。先生,祝您未来好运。再次非常感谢您!

标签: java authentication smtp gmail


【解决方案1】:

我建议依靠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 不是您想在家做的事情任务。

【讨论】:

  • 非常感谢先生。我会立即听从你的建议。祝我好运。
  • 在 SO 上,如果您有答案,您可以将其标记为已接受 :)
  • 好吧,Eugene 先生,就像您说的那样,我能够发送 STARTTLS,但随后主机重置了连接并且程序引发了 SocketException。知道为什么吗,先生?
  • 终于!尤金先生,先生。靠着全能的主的恩典,我做到了。我已经成功发送了我的程序的测试电子邮件。先生非常感谢您。你的帮助让我摆脱了困境。再一次感谢你。先生,我该如何关闭这个帖子?
  • 我不想对此泼冷水,但值得注意的是InputStream::available() 可能并不总是可靠。读到阻塞的开头会更安全,此时您应该已经收到协议指示的响应
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 2017-03-05
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 2018-12-07
相关资源
最近更新 更多