Вопрос или проблема
Причина в том, что Microsoft ранее внесла изменения в аутентификацию электронной почты, что привело к сбою в отправке. При поиске ответов в Интернете необходимо применить регистрацию в Azure и добавить разрешения в соответствии с процессом ответа. После этих операций аутентификация не удалась при использовании аутентификации OAuth2. Кодовые шаги, используемые для сравнения ответов, полностью совпадают, но неясно, настроен ли вопрос в Azure или что-то другое.
Вот код:
package com.tianrun.common.email;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class OAuth2Helper {
public static void main(String[] args) throws Exception {
String accessToken = getAccessToken();
sendEmail(accessToken, "****@outlook.com", "******", "Тема", "Тело письма");
}
private static String getAccessToken() throws Exception {
String clientId = "****";
String clientSecret = "****";
String tenantId = "*****";
String scope = "https://outlook.office365.com/.default";
String authUrl = "https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token";
URL url = new URL(authUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
String postParams = "client_id=" + clientId +
"&scope=" + scope +
"&client_secret=" + clientSecret +
"&grant_type=client_credentials";
conn.getOutputStream().write(postParams.getBytes());
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
conn.disconnect();
// Разбор JSON-ответа для получения токена доступа
String accessToken = content.toString().split("\"access_token\":\"")[1].split("\"")[0];
System.out.println(accessToken);
return accessToken;
}
private static void sendEmail(String accessToken, String sender, String recipient, String subject, String body)
throws MessagingException {
Properties props = new Properties();
props.setProperty("mail.debug", "true");
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.host", "smtp.office365.com");
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.smtp.port", "587");
props.put("mail.smtp.ssl.protocols", "TLSv1.2");
props.put("mail.smtp.starttls.enable", "true");
// Создание пользовательского аутентификатора с токеном доступа OAuth2
Session session = Session.getInstance(props, null);
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(sender));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));
message.setSubject(subject);
message.setText(body);
Transport.send(message);
}
}
Это журнал ошибок
javax.mail.AuthenticationfailedException: 535 5.7.3 Аутентификация не удалась [SI2PR6CA0e12.apcprd6.prod.outlook.com 224-11-1T96:16:51.8952 809172787151CE]
Ответ или решение
Как использовать сервер электронной почты Outlook для отправки писем с использованием OAuth2
Вопрос использования сервера электронной почты Outlook для отправки сообщений через OAuth2 становится всё более актуальным, особенно в условиях недавних изменений в процессе аутентификации от Microsoft. Рассмотрим основные шаги и возможные проблемы, с которыми вы можете столкнуться, а также приведем оптимальный код для отправки писем.
Шаг 1: Регистрация приложения в Azure
Перед тем как использовать OAuth2 для отправки электронной почты, необходимо зарегистрировать ваше приложение в Azure. Это позволит получить необходимые идентификаторы, такие как clientId
, clientSecret
и tenantId
. Процесс регистрации включает следующие этапы:
- Перейдите в Azure Portal.
- Создайте новое приложение, выбрав "App registrations".
- Задайте имя приложения и выберите соответствующий тип учетной записи.
- В разделе "API permissions" добавьте разрешения для API Microsoft Graph, такие как
Mail.Send
. - Убедитесь, что вы имеете назначенные разрешения Admin consent, если это необходимо.
Шаг 2: Получение токена доступа
Ваш код для получения токена выглядит основательно, однако важно убедиться, что в запросе включены правильные параметры и использован верный формат. Следует обратить внимание на следующую часть вашего кода:
String postParams = "client_id=" + clientId +
"&scope=" + scope +
"&client_secret=" + clientSecret +
"&grant_type=client_credentials";
Проверьте, что вы используете правильный scope
и что все значения переменных корректны. Кроме того, имейте в виду, что в URL исключен аналог &
, вам нужно использовать просто &
.
Шаг 3: Отправка email через SMTP
Ваша настройка параметров электронной почты выглядит почти верно, однако аутентификация с использованием OAuth2 требует специального механизма. Вместо использования стандартной аутентификации, следует создать кастомный Authenticator
, который будет принимать ваш токен доступа. Однако, в данной версии вашего кода это не реализовано.
Исправленный код отправки email
Убедитесь, что вы используете правильный подход для аутентификации с использованием токена. Вот оптимизированный фрагмент для отправки сообщения:
private static void sendEmail(String accessToken, String sender, String recipient, String subject, String body)
throws Exception {
Properties props = new Properties();
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.host", "smtp.office365.com");
props.setProperty("mail.smtp.port", "587");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props);
// Здесь добавляем интеграцию OAuth2 для авторизации
session.setDebug(true);
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(sender));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));
message.setSubject(subject);
message.setText(body);
// Для отправки необходимо указать токен в заголовках
Transport transport = session.getTransport("smtp");
transport.connect("smtp.office365.com", sender, accessToken);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
Ошибки аутентификации
Ошибка javax.mail.AuthenticationFailedException: 535 5.7.3 Authentication unsuccessful
указывает на проблемы с аутентификацией. Это может произойти из-за:
- Неправильного токена доступа. Убедитесь, что вы получаете токен правильно.
- Неверных параметров идентификации в Azure.
- Недостаточных разрешений для вашего приложения. Проверьте, что все необходимые разрешения назначены и согласованы.
Заключение
Использование OAuth2 для отправки электронной почты через сервер Outlook является современным и безопасным подходом, однако требует тщательной настройки как в Azure, так и в самом коде. Следуя приведенным шагам и рекомендациям, вы сможете успешно настроить отправку писем без необходимости вводить пароли, основываясь на аутентификации через токены. Убедитесь, что используете актуальный и правильно настроенный код, чтобы избежать повторных ошибок аутентификации.