Files
office365-mail/README.md

117 lines
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Office 365 Mail Console
一个最小化的 Web 控制台,用于:
- 列出租户中的成员账号
- 点击账号后读取该账号收件箱中的最新一封邮件
## 环境要求
- Node.js 18+
- Microsoft Entra 应用注册
- 已授予并管理员同意以下 Microsoft Graph Application Permissions:
- `Mail.Read`
- `User.Read.All`
- `User.ReadWrite.All`
- `LicenseAssignment.ReadWrite.All`
## 配置
1. 复制 `.env.example``.env`
2. 填入以下值:
```env
TENANT_ID=your-tenant-id
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secret
MAILBOX_ADDRESS=
DEFAULT_DOMAIN=
DEFAULT_LICENSE_SKU_ID=
DEFAULT_USAGE_LOCATION=US
ACCESS_PASSWORD=change-this-password
PORT=3000
```
说明:
- `MAILBOX_ADDRESS` 为可选默认选中账号。页面首次加载完成后,如果能在租户中找到这个邮箱地址,会自动展示它的最新邮件。
- `DEFAULT_DOMAIN` 为创建随机用户时使用的域名。未填写时,程序会尝试从 `MAILBOX_ADDRESS` 提取域名。
- `DEFAULT_LICENSE_SKU_ID` 为创建用户后自动分配的许可证 SKU ID。留空时程序会自动从租户已订阅且仍有剩余可用数的 SKU 中选择一个。
- `DEFAULT_USAGE_LOCATION` 为许可证分配前写入的使用地区,默认 `US`
- `ACCESS_PASSWORD` 为访问控制台所需的口令。设置后,用户必须先输入该密码才能打开页面和访问 API。
- 读取租户账号和邮件实际依赖的是 `TENANT_ID``CLIENT_ID``CLIENT_SECRET`
### Entra ID (Azure AD) 应用配置参数说明
| 参数名 | 必填 | 说明 | 获取方式 |
| --- | --- | --- | --- |
| `TENANT_ID` | 是 | Entra 租户 ID用于向租户申请 Graph 访问令牌 | Azure AD 应用注册概览页 |
| `CLIENT_ID` | 是 | 应用程序(客户端) ID用于标识当前应用 | Azure AD 应用注册概览页 |
| `CLIENT_SECRET` | 是 | 应用客户端密钥,用于应用身份认证 | Azure AD「证书和密码」 |
| `Mail.Read` | 是 | 读取邮箱内容所需的 Microsoft Graph 应用程序权限 | Azure AD「API 权限」 |
| `User.Read.All` | 是 | 列出租户成员账号所需的 Microsoft Graph 应用程序权限 | Azure AD「API 权限」 |
| `User.ReadWrite.All` | 是 | 创建随机用户所需的 Microsoft Graph 应用程序权限 | Azure AD「API 权限」 |
| `LicenseAssignment.ReadWrite.All` | 是 | 为新用户分配许可证所需的 Microsoft Graph 应用程序权限 | Azure AD「API 权限」 |
| `ACCESS_PASSWORD` | 可选 | 控制台访问密码,设置后访问页面前必须先登录 | 自定义 |
补充说明:
- 这四个 Graph 权限都要选择「应用程序权限」,并完成管理员同意。
- 本项目采用 `client_credentials` 模式,不需要配置重定向 URI。
- 如果只配置 `Mail.Read`,页面可以读邮件,但无法列出所有账号;如果只配置 `User.Read.All`,页面可以列出账号,但无法读取邮件正文。
- 创建随机用户需要 `User.ReadWrite.All``LicenseAssignment.ReadWrite.All`,并且目标域名必须是租户可用域名。
- `DEFAULT_LICENSE_SKU_ID` 如果填写,优先使用该值;如果留空,程序会自动选择租户内一个已启用且仍可分配的 `skuId`
## 运行
```bash
npm install
npm start
```
启动后访问:`http://localhost:3000`
如果已设置 `ACCESS_PASSWORD`,首次访问会先进入登录页。
## Docker Compose 部署
```bash
# 1. 复制配置文件
cp .env.example .env
# 2. 填入 .env 中的 TENANT_ID / CLIENT_ID / CLIENT_SECRET / ACCESS_PASSWORD
# 3. 构建并启动
docker compose up -d --build
# 4. 查看日志
docker compose logs -f
# 5. 停止服务
docker compose down
```
默认映射端口:`3000`
如果需要修改外部端口,调整 `docker-compose.yml` 中的 `ports` 映射即可。
## 接口
- `GET /api/users`
- 返回租户成员账号列表
- `GET /api/users/:userId/latest-email`
- 返回该账号收件箱最新一封邮件
- `GET /api/users/:userId/latest-email/body`
- 返回该账号收件箱最新一封邮件正文
- `POST /api/users/random`
- 自动创建一个随机用户名的新用户,设置使用地区并分配许可证,然后返回用户主体与临时密码
## 注意事项
- 账号列表依赖 `User.Read.All`,否则无法拉取租户用户。
- 某些账号虽然存在于租户中,但不一定拥有 Exchange 邮箱;这类账号读取邮件时可能返回空结果或权限错误。
- 当前页面以邮件全文为主,保留发件人和接收时间,并显示完整 HTML / 纯文本正文。
- 当前版本使用基于 Cookie 的本地访问验证;更换 `ACCESS_PASSWORD` 后,旧登录会话会失效。
- 建号接口会在创建用户后立即分配许可证;如果指定的 `DEFAULT_LICENSE_SKU_ID` 不可用,或租户中没有可自动选择的可用 SKU接口会返回错误。
- 如果许可证分配最终失败,接口会自动删除刚创建的用户,避免留下无授权的脏账号。