Получение исключения при отправке электронной почты через SMTP через сервер GMail с использованием OAUTH и JavaMail 1.4.7

Я относительно новичок в отправке электронной почты из приложения (в моем случае настольного приложения, которое я зарегистрировал в Google), и получаю следующее исключение (несмотря на неправильное написание "механизмов"):

javax.mail.AuthenticationFailedException: механизмы аутентификации не поддерживаются как сервером, так и клиентом.

Вот мой код, упрощенный и упакованный в один класс MailTest. Вывод отладки соответствует источнику. Есть идеи, что я делаю не так?

Мой тестовый класс:

      import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Properties;
import java.util.stream.Collectors;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.google.gson.Gson;

public class MailTest {
    private static String TOKEN_URL = "https://www.googleapis.com/oauth2/v4/token";

    /* These constants are all encrypted and stored in my database.  I've decrypted and added them here as literals */
    private static final String APP_CLIENT_ID = "<my_app_client_id>apps.googleusercontent.com";
    private static final String APP_CLIENT_SECRET = "<my_app_secret>";
    private static final String REFRESH_TOKEN = "<my_app_refresh_token>";

    private static String accessToken = "ya29.a0AfH6SMARliKqauH9m9mFktgNcKuTZs_c3bPak1yQsS0Uxethlo75NWSP2ad3uBAJWItM-kzY08n6lSaL931gbBaqJY7ZavsyA2y092MZiGdqBnEzXTbTNbvKomLvRoHupOquqTjf1KsrM70eFEWN9WMVL_dz";

    /* This value is stored and retrieved from the database but setting to 0 here to force a refresh of "accessToken */
    private static long tokenExpiration = 0;

    private static final String FROM_EMAIL_ADDRESS = "<FromEmail>@gmail.com";
    private static final String FROM_NAME = "<From Name>";
    
    /* Hard coded list of recipients for simplicity */
    private static String[] recipientNames = new String[] { "ToEmail@gmail.com" };
    
    public static void main(String args[]) {
        Properties props = new Properties();

        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
        props.put("mail.smtp.port", 587);

        props.put("mail.debug", "true");
        props.put("mail.debug.auth", "true");

        try {
            Session session = Session.getInstance(props);
            MimeMessage msg = createMessage(session);
            Transport transport = session.getTransport("smtp");

            transport.connect("smtp.gmail.com", FROM_EMAIL_ADDRESS, getAccessToken());
            msg.saveChanges();
            transport.sendMessage(msg, msg.getAllRecipients());
            transport.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static MimeMessage createMessage(Session session) throws UnsupportedEncodingException, MessagingException {
        MimeMessage msg = new MimeMessage(session);

        msg.setFrom(new InternetAddress(FROM_EMAIL_ADDRESS, FROM_NAME));

        InternetAddress[] toAddresses = new InternetAddress[recipientNames.length];

        for (int i = 0; i < recipientNames.length; i++) {
            toAddresses[i] = new InternetAddress(recipientNames[i]);
        }
        msg.setRecipients(Message.RecipientType.TO, toAddresses);
        msg.setSubject("My email subject", "UTF-8"); //$NON-NLS-1$
        msg.setContent("Hello world!", "plain");
        msg.setSentDate(new Date());

        return msg;
    }

    /*
     * Return the access token, renewing if expired
     */
    private static String getAccessToken() throws IOException {
        if (System.currentTimeMillis() > tokenExpiration) {
            refreshAccessToken();
        }
        return accessToken;
    }

    // For parsing using json
    private static class RefreshTokenReply {
        private String access_token;
        private String expires_in;
    }

    /*
     * Renew access token
     */
    private static void refreshAccessToken() throws IOException {
        String data = "refresh_token=" + REFRESH_TOKEN + "&client_id=" + APP_CLIENT_ID
                + "&client_secret=" + APP_CLIENT_SECRET + "&grant_type=refresh_token";

        URL url = new URL(TOKEN_URL);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        byte[] body = data.getBytes();

        conn.setDoOutput(true);
        conn.setFixedLengthStreamingMode(body.length);
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.getOutputStream().write(body);

        BufferedReader reader = new BufferedReader(
                new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
        String reply = reader.lines().collect(Collectors.joining(System.lineSeparator()));
        
        System.out.println("Token refresh reply:" + System.lineSeparator() + reply);
        
        Gson jsonParser = new Gson();
        RefreshTokenReply refreshReply = jsonParser.fromJson(reply, RefreshTokenReply.class);

        reader.close();

        accessToken = refreshReply.access_token;

        if (accessToken == null) {
            throw new IOException("Refresh token yielded no access token");
        }
        tokenExpiration = System.currentTimeMillis() + Integer.parseInt(refreshReply.expires_in) * 1000;
    }
}

Вот результат:

      DEBUG: JavaMail version 1.4.7
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
Token refresh reply:
{
  "access_token": "ya29.a0AfH6SMBYeEk1DSDyS2pwBW0mNjOPUVVWqZjAOAD9CdWAB_a5229D9bZZXm123uQV20ZuQxyK38YytTGNDtnsuT8_HdS_y_PS4yzg_MNtC8jrfaYYGDiT0MNF87hE1sEaJmeSTzjsfc4OyFojbf1quILt1o-6XQ",
  "expires_in": 3599,
  "scope": "https://mail.google.com/",
  "token_type": "Bearer"
}
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 587, isSSL false
220 smtp.gmail.com ESMTP x19sm6016872oor.45 - gsmtp
DEBUG SMTP: connected to host "smtp.gmail.com", port: 587

EHLO Ricks-Laptop
250-smtp.gmail.com at your service, [71.229.130.76]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
STARTTLS
220 2.0.0 Ready to start TLS
EHLO Ricks-Laptop
250-smtp.gmail.com at your service, [71.229.130.76]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: XOAUTH2
DEBUG SMTP: no authenticator for mechanism XOAUTH2
javax.mail.AuthenticationFailedException: No authentication mechansims supported by both server and client
    at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:765)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:685)
    at javax.mail.Service.connect(Service.java:295)
    at javax.mail.Service.connect(Service.java:176)
    at MailTest.main(MailTest.java:56)

0 ответов

Другие вопросы по тегам