有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用此Java程序了解SMTP工作原理的socket(不允许使用JavaMail)

我不确定如何将编码的base64凭据传递到邮件服务器。有没有办法不用JavaMail就可以做到这一点?我一直遇到authentication 530 authentication required错误,我知道这是由于未正确发送凭据造成的,但我无法找出这一点

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.util.Base64;
import java.util.Base64.Encoder;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
import java.net.*;


public class EmailClient
{
public static void main(String[] args) throws Exception
{
// Establish a TCP connection with the mail server.
SSLSocket socket = (SSLSocket) ((SSLSocketFactory)
SSLSocketFactory.getDefault()).
createSocket(InetAddress.getByName("smtp.gmail.com"), 465);

/* encoding the username and password in Base64 for SMTP */
Encoder base64Encoder = Base64.getEncoder();
String smtpUser = 
base64Encoder.encodeToString("username".getBytes());
String smtpPass = 
base64Encoder.encodeToString("password".getBytes());

 // Create a BufferedReader to read a line at a time.
 InputStream is = socket.getInputStream();
 InputStreamReader isr = new InputStreamReader(is);
 BufferedReader br = new BufferedReader(isr);


// Read greeting from the server.
String response = br.readLine();
System.out.println(response);
if (!response.startsWith("220")) {
throw new Exception("220 reply not received from server.");
}

// Get a reference to the socket's output stream.
   OutputStream os = socket.getOutputStream();

// Send HELO command and get server response.
   String command = "HELO alice\r\n";
   System.out.print(command);
   os.write(command.getBytes("US-ASCII"));
   response = br.readLine();
   System.out.println(response);
   if (!response.startsWith("250")) {
   throw new Exception("250 reply not received from server.");
        }
// Authentication
   String cmmd authMsg = "AUTH LOGIN\r\n"

// How do I send my encoded credentials to the server?

// Send MAIL FROM command.
   String mailFrom = "MAIL FROM: <xxxxxxxx@gmail.com>\r\n";
   System.out.print(mailFrom);
   os.write(mailFrom.getBytes("US-ASCII"));
   response = br.readLine();
   System.out.println(response);
   if (!response.startsWith("250")) {
   socket.close();
   throw new Exception("250 reply not received from server.");
        }
        // Send RCPT TO command.
        String commandRCPT = "RCPT TO:<xxxxxxxxxx.com>\r\n";
        System.out.print(commandRCPT);
        os.write(commandRCPT.getBytes("US-ASCII"));
        response = br.readLine();
        System.out.println(response);
        if (!response.startsWith("250")) {
        socket.close();
        throw new Exception("250 reply not received from server.");
        }

        // Send DATA command.
        String commandDATA = "DATA\r\n";
        System.out.print(commandDATA);
        os.write(commandDATA.getBytes("US-ASCII"));
        response = br.readLine();
        System.out.println(response);
        if (!response.startsWith("354")) {
        socket.close();
        throw new Exception("354 reply not received from server.");
        }

        // Send message data.
        String msgLine1 = "email sent\r\n";
        System.out.print(msgLine1);
        os.write(msgLine1.getBytes("US-ASCII"));

        // End with line with a single period.
        String msgLine2 = ".\r\n";
        System.out.print(msgLine2);
        os.write(msgLine2.getBytes("US-ASCII"));
        response = br.readLine();
        System.out.println(response);
        if (!response.startsWith("250")) {
        socket.close();
        throw new Exception("250 reply not received from server.");
        }

        // Send QUIT command.
        String commandQUIT = "QUIT\r\n";
        System.out.print(commandQUIT);
        os.write(commandQUIT.getBytes("US-ASCII"));
        response = br.readLine();
        System.out.println(response);
        if (!response.startsWith("221")) {
        socket.close();
        throw new Exception("221 reply not received from server.");
        }

        socket.close();
    }
}

共 (1) 个答案

  1. # 1 楼答案

    在您展示的代码中没有发生SMTP authentication,这就是RCPT TO命令失败的原因。见What is the need of SMTP AUTH?

    SMTP客户端需要在连接到服务器、识别自身之后,以及在发送任何MAIL FROM/RCPT TO/DATA命令之前,成功发送AUTH命令。您需要使用EHLO而不是HELO来确定服务器实际支持哪些AUTH方案(LOGINPLAINGSSAPIDIGEST-MD5CRAM-MD5OAUTHBEARER,等等),然后对其中一个方案进行相应的身份验证

    1:FYI,mail.smtp2go.com支持^{}^{}^{}身份验证方案。请参阅this reference,其中对它们进行了更详细的描述

    有关更多详细信息,请参阅RFC 4422: Simple Authentication and Security Layer (SASL)RFC 4954: SMTP Service Extension for Authentication和其他相关RFC

    我还建议您阅读RFC 5321: Simple Mail Transfer Protocol以了解SMTP协议的一般工作原理,因为您现在掌握的代码在如何处理协议方面并不完整,尤其是在如何读取服务器的响应方面(请参见section 4.2: SMTP Replies

    试着做些类似的事情:

    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.util.Base64;
    import java.util.Base64.Encoder;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import java.io.*;
    import java.net.*;
    
    public class EmailClient
    {
        private SSLSocket socket;
    
        private BufferedReader br;
        private OutputStream os;
    
        private String lastResponseText;
    
        private void checkReplyCode(int replyCode, int expectedReplyCode)
        {
            if (replyCode != expectedReplyCode)
                throw new Exception(lastResponseText);
        }
    
        private int checkReplyCodes(int replyCode, int expectedReplyCodes[])
        {
            if (expectedReplyCodes == null)
                return replyCode;
    
            for (int i = 0; i < expectedReplyCodes.length; ++i)
            {
                if (replyCode == expectedReplyCodes[i])
                    return replyCode;
            }
    
            throw new Exception(lastResponseText);
        }
    
        private int readResponse()
        {
            lastResponseText = "";
    
            String line = br.readLine();
            System.out.println(line);
    
            lastResponseText = line;
    
            if ((line.length() > 3) && (line[3] == '-'))
            {
                String prefix = line.substring(0, 4);
                do
                {
                    line = br.readLine();
                    System.out.println(line);
                    lastResponseText += ("\r\n" + line.substring(4));
                }
                while (line.startsWith(prefix));
            }
    
            return Integer.parseInt(lastResponseText.substring(0, 3));
        }
    
        private void readResponse(int expectedReplyCode)
        {
            checkReplyCode(readResponse(), expectedReplyCode);
        }
    
        private int readResponse(int expectedReplyCodes[])
        {
            return checkReplyCodes(readResponse(), expectedReplyCodes);
        }
    
        private void sendLine(String line)
        {
            System.out.println(line);
            os.write((line + "\r\n").getBytes("US-ASCII"));
        }
    
        private int sendCommand(String command)
        {
            sendLine(command);
            return readResponse();
        }
    
        private void sendCommand(String command, int expectedReplyCode)
        {
            sendLine(command);
            readResponse(expectedReplyCode);
        }
    
        private int sendCommand(String command, int expectedReplyCodes[])
        {
            sendLine(command);
            return readResponse(expectedReplyCodes);
        }
    
        private String stringAsBase64(String data)
        {
            return Base64.getEncoder().encodeToString(data.getBytes("UTF-8"));
        }
    
        public static void main(String[] args) throws Exception
        {
            // Establish a TCP connection with the mail server.
            socket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(InetAddress.getByName("smtp.gmail.com"), 465);
    
            // Create a BufferedReader to read a line at a time.
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    
            // Get a reference to the socket's output stream.
            os = socket.getOutputStream();
    
            // Read greeting from the server.
            readResponse(220);
    
            // Send HELO command and get server response.
            //sendCommand("HELO alice", 250);
            sendCommand("EHLO alice", 250);
    
            // Authentication
            sendCommand("AUTH LOGIN", 334);
    
            /* encoding the username and password in Base64 for SMTP */
            if (sendCommand(stringAsBase64("username"), new int[]{235, 334}) == 334)
                sendCommand(stringAsBase64("password"), 235);
    
            // Send MAIL FROM command.
            sendCommand("MAIL FROM: <xxxxxxxx@gmail.com>", 250);
    
            // Send RCPT TO command.
            sendCommand("RCPT TO:<xxxxxxxxxx.com>", 250);
    
            // Send DATA command.
            sendCommand("DATA", 354);
    
            // Send message data.
            sendLine("From: <xxxxxxxx@gmail.com>");
            sendLine("To: <xxxxxxxxxx.com>");
            sendLine("Subject: Test");
            sendLine("");
            sendLine("email sent");
    
            // End with line with a single period.
            sendCommand(".", 250);
    
            // Send QUIT command.
            sendCommand("QUIT", 221);
    
            socket.close();
        }
    }