Работая над этой программой на Java, чтобы понять, как работает SMTP (запрещено использовать JavaMail) - PullRequest
0 голосов
/ 27 сентября 2019

Я не уверен, как передать закодированные учетные данные base64 на почтовый сервер.Есть ли способ сделать это без использования JavaMail?Я продолжаю сталкиваться с ошибкой аутентификации 530, требующей аутентификации, и я знаю, что это результат неправильной отправки учетных данных, но я не могу понять этот бит.

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 Ответ

2 голосов
/ 27 сентября 2019

В указанном вами коде не выполняется SMTP-аутентификация , поэтому команда RCPT TO не выполняется.См. Для чего нужен SMTP AUTH? .

Ваш SMTP-клиент должен отправить успешную команду AUTH после подключения к серверу, идентификации себя и перед отправкой любого MAIL FROM/ RCPT TO / DATA команды.Вам необходимо использовать EHLO вместо HELO, чтобы определить, какие AUTH схемы (LOGIN, PLAIN, GSSAPI, DIGEST-MD5, CRAM-MD5, OAUTHBEARER и т. Д.) Серверафактически поддерживает, а затем аутентифицируется соответственно с одним из них 1 .

1: К вашему сведению, mail.smtp2go.com поддерживает CRAM-MD5, PLAIN и LOGIN схемы авторизации.См. эту ссылку , которая описывает их более подробно.

См. RFC 4422: Уровень простой аутентификации и безопасности (SASL) , RFC 4954: SMTP Service Extension для аутентификации и другие связанные RFC для получения более подробной информации.

Я также предлагаю вам прочитать RFC 5321: Простой протокол передачи почты , чтобы понять, как работает протокол SMTP в целом.потому что код, который у вас есть сейчас, неполон в том, как он обрабатывает протокол, в частности в том, как он читает ответы сервера (см. раздел 4.2: SMTP-ответы ).

Попробуйте что-то ещекак это:

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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...