原因是微软之前对邮件身份验证进行了更改,导致发送失败。在线寻找答案时,需要在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", "******", "Subject", "Body of the email");
}
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();
// Parse the JSON response to get the access token
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");
// Create a custom Authenticator with the OAuth2 access token
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 Authentication unsuccesful [SI2PR6CA0e12.apcprd6.prod.outlook.com 224-11-1T96:16:51.8952 809172787151CE]
我尝试使用以下 Java 代码使用
Mail.Send
范围向 Outlook 帐户发送电子邮件,并成功将电子邮件发送到 Outlook 帐户。
OutlookMailSender.java :
import com.azure.identity.InteractiveBrowserCredential;
import com.azure.identity.InteractiveBrowserCredentialBuilder;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.models.*;
import com.microsoft.graph.requests.GraphServiceClient;
import java.util.Arrays;
public class OutlookMailSender {
private static final String CLIENT_ID = "<clientID>";
private static final String TENANT_ID = "common";
private static final String[] SCOPES = {"Mail.Send"};
public static void main(String[] args) {
try {
InteractiveBrowserCredential credential = new InteractiveBrowserCredentialBuilder()
.clientId(CLIENT_ID)
.tenantId(TENANT_ID)
.build();
TokenCredentialAuthProvider authProvider = new TokenCredentialAuthProvider(Arrays.asList(SCOPES), credential);
GraphServiceClient<?> graphClient = GraphServiceClient
.builder()
.authenticationProvider(authProvider)
.buildClient();
Message message = new Message();
message.subject = "Holiday Notice";
ItemBody body = new ItemBody();
body.contentType = BodyType.TEXT;
body.content = "I am currently on holiday and will respond to your email upon my return.";
message.body = body;
Recipient toRecipient = new Recipient();
toRecipient.emailAddress = new EmailAddress();
toRecipient.emailAddress.address = "[email protected]";
Recipient ccRecipient = new Recipient();
ccRecipient.emailAddress = new EmailAddress();
ccRecipient.emailAddress.address = "[email protected]";
message.toRecipients = Arrays.asList(toRecipient);
message.ccRecipients = Arrays.asList(ccRecipient);
UserSendMailParameterSet sendMailParameterSet = new UserSendMailParameterSet();
sendMailParameterSet.message = message;
sendMailParameterSet.saveToSentItems = Boolean.FALSE;
graphClient.me().sendMail(sendMailParameterSet).buildRequest().post();
System.out.println("Email sent successfully!");
} catch (Exception e) {
System.err.println("Error sending email: " + e.getMessage());
}
}
}
pom.xml:
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph</artifactId>
<version>5.13.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.0-alpha1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0-alpha1</version>
</dependency>
</dependencies>
我已在 Azure AD 应用程序的 Authentication 下的
Mobile and desktop applications
下添加了以下 URL。
http://localhost
我启用了
public client flow
,如下所示。
我在API权限和Granted admin consent
中添加了
Mail.Send范围,如下所示。
输出:
当我运行代码时,它会重定向我以登录我的 Outlook 帐户,如下所示。
我已成功验证我的 Outlook 帐户。
邮件发送成功,如下图。
电子邮件已发送至 Outlook,如下所示。