使用 PHP 访问 Exchange/Office 365

长期宣布-现在成为现实:从 2022 年 9 月起,Microsoft 已关闭 Exchange Online 中某些协议的密码身份验证,转而使用 oAuth2。 许多备份脚本的 GitHub 问题清楚地表明,这种转换让许多管理员感到意外。 下面我们展示了一种方法,您可以如何在 oAuth2 的帮助下通过 PHP 通过 IMAP 继续访问您的 Exchange 邮箱的内容。


从安全的角度来看,微软的举动是非常正确的,但是以编程方式访问其电子邮件的复杂性增加了不少。 例如,如果你使用广泛使用的barbushin/php-imap 库,访问曾经如下:

734a82898010e2fcb02c72c3cd9702c2

它只是不再起作用了。 为了通过oAuth2建立连接,第一个困难是获取访问令牌。 为此,您必须克服两个障碍。

Azure 活动目录

以下步骤在 Azure Active Directory 中注册新应用:

登录到https://portal.azure.com
打开“Azure 活动目录”
选择“应用注册”和“新注册”。
复制“应用程序 ID(客户端)”(=客户端 ID)和“目录 ID(租户)”(=租户 ID)。
“API 权限”和“添加权限”
“我的组织使用的 API”和“Office 365 Exchange Online”
“应用程序权限”和“IMAP.AccessAsApp”
授予管理员同意
“证书和机密” & “客户机密” & “新客户机密”
选择描述并设置有效期
将“Secret ID”(客户端密码)复制到剪贴板
开放企业应用
复制“对象 ID”。

电源外壳

现在我们将应用程序转入 微软PowerShell (管理员模式)并为各个邮箱分配权限(<TENANTID>, <CLIENTID>, <OBJECTID>, <EMAIL> 必须在每种情况下更换):

Install-Module -Name ExchangeOnlineManagement
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -Organization <TENANTID>

New-ServicePrincipal -AppId <CLIENTID> -ServiceId <OBJECTID>
Add-MailboxPermission -Identity "<EMAIL>" -User <OBJECTID> -AccessRights FullAccess
...

一旦你做到了,剩下的就不是火箭科学了。 由于barbushin/php-imap不支持 oAuth2,因此您可以使用替代库Webklex/php-imap连接(它还有不需要PHP IMAP 模块的优点)。:

734a82898010e2fcb02c72c3cd9702c2

但是,官方不支持 oAuth2 的库也可以与代理一起使用,例如 西蒙罗布/电子邮件-oauth2-代理 使其可行。 在这之后 下载 并通过安装 python -m pip install -r requirements-no-gui.txt (需要 Python ≥3.6)您编辑文件 emailproxy.config 例如如下(更换本次 <TENANTID>, <CLIENTID>, <CLIENTSECRET><EMAIL>):

[Server setup]

[IMAP-1993]
local_address = localhost
server_address = outlook.office365.com
server_port = 993

[Account setup]

[<EMAIL>]
token_url = https://login.microsoftonline.com/<TENANTID>/oauth2/v2.0/token
oauth2_scope = https://outlook.office365.com/.default
redirect_uri = http://localhost:8080
client_id = <CLIENTID>
client_secret = <CLIENTSECRET>

然后你启动代理 python emailproxy.py --no-gui 现在可以访问未加密的 IP localhost 在港口 1993 通过常规基本身份验证(和任何密码集)进行连接。 如果要在启动系统时将代理作为服务在后台启动,可以使用,例如 系统:

sudo systemctl edit --force --full emailproxy.service

[Unit]
Description=Email OAuth 2.0 Proxy
[Service]
ExecStart=/usr/bin/python /path/to/emailproxy.py --no-gui
Restart=always
[Install]
WantedBy=multi-user.target

sudo systemctl enable emailproxy.service --now
sudo systemctl status emailproxy.service
sudo systemctl start emailproxy.service

如果需要加密连接,这也是可能的 - 为此您首先创建一个私钥和一个自签名证书:

openssl genrsa -out key.pem 3072
openssl req -new -x509 -key key.pem -out cert.pem -days 360

然后参考在 emailproxy.config 这两个文件:

local_key_path = /path/to/key.pem
local_certificate_path = /path/to/cert.pem

电子邮件发送

任何想要通过 Microsoft Exchange Online 以编程方式发送电子邮件的用户都将面临一项根本性的变化:Microsoft 已在 Exchange Online 中禁用 SMTP 的经典用户名和密码身份验证。过去只需几行代码即可完成的操作,现在需要通过 OAuth2 进行转换——包括在 Azure Active Directory 中注册应用程序、证书和令牌管理。除了接收电子邮件之外,我们也可以相应地实现发送功能。

“API 权限”和“添加权限”
“我的组织使用的 API”和“Office 365 Exchange Online”
“应用程序权限”和“SMTP.SendAsApp”
授予管理员同意

通过 Microsoft Exchange 365 发送 SMTP 邮件遵循与 IMAP 访问相同的原理:由于基本身份验证已停用,因此只能使用 OAuth2。在 Azure 应用注册中添加“SMTP.SendAsApp”权限并授予管理员批准后,即可通过例如以下方式发送邮件: PHPMailer 此功能已实现。现在,与以前简单地提交用户名和密码不同,对 SMTP 服务器的身份验证使用访问令牌。 smtp.office365.com:

734a82898010e2fcb02c72c3cd9702c2

额外的设置工作起初可能看起来令人生畏,但从长远来看是值得的:基于 OAuth2 的身份验证安全性更高,因为无需在配置文件或脚本中存储明文密码——而且访问令牌还可以设置时间限制,并对其权限进行精细控制。此外,值得一提的是mailhelper库,它提供了一个便捷的 API,用于收发电子邮件。

背部