outlook邮箱授权和java mail访问
微软的文档真的又乱又稀碎,光找文档就就找了挺久的,对接完后,其实就是完整的oAuth2的授权流程。
1、前言
微软的文档真的又乱又稀碎,光找文档就就找了挺久的,对接完后,其实就是完整的oAuth2的授权流程
主题文章参考:Authenticate an IMAP, POP or SMTP connection using OAuth
2、Azure注册oAuth2应用
2.1、找到应用注册
azure网址:https://portal.azure.com
注册就自己搞定了,需要visa或者master card才可以注册成功。
进入找到Azure 服务,点击更多服务,进入如下图所示的界面,找到应用注册
2.2、注册应用

1、选择任何组织目录(任何 Microsoft Entra ID 租户 - 多租户)中的帐户和个人 Microsoft 帐户(例如 Skype、Xbox)
2、选择web,填入你要的回调地址,这里只是演示,写本地的地址https://localhost,地址只能是https
3、点注册即可
2.3、添加客户端凭证

1、点击添加客户端密码
2、点击新客户端密码
3、输入说明和选择期限
生成了密钥的值,后续使用
2.4、添加权限
选择左侧的api权限项,点击添加权限,在右侧点击Microsoft Graph,点击委托权限,分别搜索,IMAP、SMTP、POP添加下拉文件夹下的权限,即权限:IMAP.AccessAsUser.All、SMTP.Send、POP.AccessAsUser.All,完成应用的全部设置
3、oAuth2授权流程
3.1、构建授权链接
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=你注册应用的id&response_type=code&redirect_uri=注册应用中填写的回调网址&response_mode=query&scope=https%3a%2f%2foutlook.office.com%2fIMAP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fPOP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fSMTP.Send+offline_access&state=12345
这里的你注册应用的id在应用的概述tab找到应用程序(客户端) ID就是
我测试的授权地址为:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=2ff805be-946e-4d7e-9abb-90a74e9f18fc&response_type=code&redirect_uri=https%3a%2f%2flocalhost&response_mode=query&scope=https%3a%2f%2foutlook.office.com%2fIMAP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fPOP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fSMTP.Send+offline_access&state=12345

登录后,第一次授权会弹出权限列表,后面就不会提示了。点击接受
跳转到回调的地址,例如:
https://localhost/?code=M.C507_BAY.2.U.8e34a898-7a77-f074-3232-8622a6ff1447&state=12345
3.2、使用授权码获取accessToken
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=你注册应用的id
&scope=https%3a%2f%2foutlook.office.com%2fIMAP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fPOP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fSMTP.Send+offline_access
&code=重定向后获取的code的值
&redirect_uri=https%3a%2f%2flocalhost
&grant_type=authorization_code
&client_secret=前面添加客户端凭证章节获取的密码的值,不是密码的id
curl案例:
curl --location --request POST 'https://login.microsoftonline.com/common/oauth2/v2.0/token' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Accept: */*' \
--header 'Host: login.microsoftonline.com' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=2ff805be-946e-4d7e-9abb-90a74e9f18fc' \
--data-urlencode 'code=M.C507_BAY.2.U.8e34a898-7a77-f074-3232-8622a6ff1447' \
--data-urlencode 'redirect_uri=https://localhost' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_secret=你的secret'
这里获取accessToken的redirect_uri需要与获取授权码的redirect_uri一致
返回值:
{
"token_type": "Bearer",
"scope": "https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
"expires_in": 3600,
"ext_expires_in": 3600,
"access_token": "EwAIBOl3BAAUcDnR9grBJokeAHaUV8R3+rVHX+IAAXiGwZejLrPgf5bpxZWoRw6UpPPBe7lXGqrIEUxgCfWGeZYS65d35znANXYo1c5LJF0dOIDvvqVQXc9LuDb8ZVmHjY/dOOkUs3QuPXoBYrgJ22hJEXeLkSka0oZgfdprj7TipiHY/Qx8WrtPr48snVf6uFEa/eg1Efnb4YLAcU7IgzrmibxiMokjsjUYq8jwForxWWBDNwT13fZG5xX4I7sKRNxZyM2Y2q7Q0AUSL3zT0U16A4hVDJYzLGdJ7xiOsxwn5l9A3tjj+ReL98EH7lh02BT+vMsqRDavt6sHX3t3ROIsxJP9+cmbh1DbjhafKHZ9Gk0EseeCcnHGQE/3nWwQZgAAEAqD2w2C/o4Gp0TvDeuVVubQAgFYQnu7m+D+/CZUewnlykoVLZqkC9Fg5dDvgVROeTvh/bI3rIeeALzf+yMTax+VxWdgkWcIC4na20sU7At188x6XAVQn3FvnlJt4PVjdsbk83dEtHGFgI7VrH4/PuVHVVCxsp7NqYdM6mLEmHNnPVNUFaG9MslHipo0l/Hr66jx75DNjOxgpnrwtjZeH8dsM2wsxTNm/GeFAkY6GHwvoSHBebbcRJ1vQURNf5dgRmtD2V09Gu6lRZBdPmxSMXhsy6RqRaPXAPDbQJd7B9LiC4m5ImNSeAO3kGh0uBvhhBGri+DQYj2qmGgfWE/aSGLl0Q+aDrKaXudUgFx627PE5YkHD0a3KtYj7h8FxQBnLSu1umOYXK0dOU5Lwrx0SYpo7yZbYCX1gPvRjD9KXuz9Bg4jStRW0TB3hH4eTZpEevbyqQYwOOVWrJ5UUy65b1eo3C7UkamLeJ8v3x8gCEiRWy5RkCID9DhfnVA2dp6Dm9TEmANWqN/NKu7ROQlT0Eq0XlCPNePYAozfHdMa06tHjFR5IkoQPIMjIRp4duVunXoAGPjPTcZ8olKgZEsFCnkz9WLaZxZO6GlbLVbqdwZWyshh9JMn8GKxQrhyPMvtjdAiBjbV16nruoYtRzNi2i7cIYyzqCM4SPrzaDMe9Xfianv0yP6W8bCI1RtEkLEjtv2I+R8VVXgg7EzkR/dMCZUeySmhFdLT5gYva7ThJ1SG6L7jflbqo3QqHG801JfpryhJWep3VSNxo2S18GU6jegx9cxaM0uqrL5UQNg1gkFRuPtP5BR09w7sbvQ3ZkobyeFwo4m6Akhru2h5ZzEerFzeukaPOMgi8MGuE01AdI9froW+yixWSimRhU3S5Faf8njwg7CMqL/A/x+Mxdhkm84m6Erl3xjzSDUA5CKk14u/gBatOmO9L4ASTM9R4wYyZh4i/8re562/H0Aq6JqqHDQRpvkC",
"refresh_token": "M.C507_BAY.0.U.-CurRsOr9QXEUuPjshw0ZaHzZb2Fcy1U*40U8P*MuX9IC!8fRQN20s4SMeGqKrU7PjrvTERX4GsrkZ1RNo2fg*BVHJFWeU7nA0ziU5!SLZO79vPgt8Sm6Wl!DH8Gss1VhU3kVsnb8rIAy8IFuZvTPSM1flc0tYjbJgROSHeV9WuxfsSAf0jMNA*uxJzQM97HdbnY7VYaPl5*wS65bBpG5ixRkCUgLpCwI*CI8g19n0TxyNb1MR3gmjXLzYNOblqYn8QZ!N5FceJFwH!UxYlWcZnAsLCTSPTp88oMB*3Vb7TJjlkLUhQNo5HJ5B74K1gzPkLAmLxjeenZGheSFJePMBG!MNblSrOl4McpWIsuaQbp26vAAUQBN5WuE801CjorEzelx!n8yyHUBdTHR3WNshCVDxZmBxklde9OH6ePljoXO"
}
3.3、使用refresh_token续期授权
使用refresh_token调用刷新,可以获取一个新的access_token,用于使用
curl实例:
curl --location --request POST 'https://login.microsoftonline.com/common/oauth2/v2.0/token' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Accept: */*' \
--header 'Host: login.microsoftonline.com' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: fpc=AslLOhYVqzpBgXnjVan37rzuuKLzAQAAABvJQ98OAAAA; x-ms-gateway-slice=estsfd; stsservicecookie=estsfd' \
--data-urlencode 'client_id=2ff805be-946e-4d7e-9abb-90a74e9f18fc' \
--data-urlencode 'refresh_token=M.C507_BAY.0.U.-CurRsOr9QXEUuPjshw0ZaHzZb2Fcy1U*40U8P*MuX9IC!8fRQN20s4SMeGqKrU7PjrvTERX4GsrkZ1RNo2fg*BVHJFWeU7nA0ziU5!SLZO79vPgt8Sm6Wl!DH8Gss1VhU3kVsnb8rIAy8IFuZvTPSM1flc0tYjbJgROSHeV9WuxfsSAf0jMNA*uxJzQM97HdbnY7VYaPl5*wS65bBpG5ixRkCUgLpCwI*CI8g19n0TxyNb1MR3gmjXLzYNOblqYn8QZ!N5FceJFwH!UxYlWcZnAsLCTSPTp88oMB*3Vb7TJjlkLUhQNo5HJ5B74K1gzPkLAmLxjeenZGheSFJePMBG!MNblSrOl4McpWIsuaQbp26vAAUQBN5WuE801CjorEzelx!n8yyHUBdTHR3WNshCVDxZmBxklde9OH6ePljoXO' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'client_secret=你的secret'
完成了,授权的授权的全部流程了,也是一个标准的oAuth2的授权流程。
3.5、取消授权
这里:https://account.microsoft.com/privacy/app-access
或者这里:https://account.live.com/consent/Manage
3.6、开启outlook的imap权限
登陆授权的邮箱,进入设置,点击邮箱项,点击转发和imap,去到pop和imap,开启“允许设备和应用使用 POP”、“允许设备和应用使用 IMAP”
4、java使用access_token访问邮箱
增加maven依赖:
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
SMTP代码:
import jakarta.mail.Message;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.Properties;
public class OutlookSmtpXOAUTH2 {
public static void main(String[] args) {
String userEmail = "授权的邮箱"; // Outlook邮箱地址
String accessToken = "你的accessToken";
String receiveEmail = "接收的邮箱";
Properties props = new Properties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", "smtp.office365.com"); // Outlook SMTP服务器
props.put("mail.smtp.port", "587"); // TLS端口
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
props.put("mail.smtp.auth.xoauth2.disable", "false");
props.put("mail.smtp.auth.login.disable","true");
props.put("mail.smtp.auth.plain.disable","true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true); // 开启调试日志
try {
Transport transport = session.getTransport();
transport.connect(userEmail, accessToken); // 使用令牌登录
// 创建邮件
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(userEmail));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiveEmail));
message.setSubject("Java SMTP XOAUTH2 测试邮件");
message.setText("这是一封通过 Java XOAUTH2 发送的测试邮件。");
transport.sendMessage(message, message.getAllRecipients());
System.out.println("邮件发送成功!");
transport.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
IMAP接受邮件代码:
import jakarta.mail.Folder;
import jakarta.mail.Message;
import jakarta.mail.Session;
import jakarta.mail.Store;
import java.util.Properties;
public class OutlookImapXOAUTH2 {
public static void main(String[] args) {
String userEmail = "授权的邮箱"; // Outlook邮箱地址
String accessToken = "你的accessToken";
Properties props = new Properties();
props.put("mail.imap.ssl.enable", "true");
props.put("mail.imap.auth.mechanisms", "XOAUTH2");
props.put("mail.imap.auth.xoauth2.disable", "false");
props.put("mail.imap.host", "outlook.office365.com");
props.put("mail.imap.port", "993");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true); // 开启调试日志
try {
Store store = session.getStore("imap");
store.connect(userEmail, accessToken); // 使用访问令牌登录
System.out.println("成功连接到邮箱!");
// 操作邮箱(例如读取收件箱)
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);
Message[] messages = inbox.getMessages();
System.out.println("收件箱邮件数:" + messages.length);
inbox.close(false);
store.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
参考文章:
Authenticate an IMAP, POP or SMTP connection using OAuth
使用 OAuth 对 IMAP、POP 或 SMTP 连接进行身份验证-上一个参考的中文版本
用于 IMAP 和 SMTP 身份验证的 Office 365 XOAUTH2 失败
更多推荐




所有评论(0)