OutlookDelegateSkill outlook-delegate

利用 Microsoft Graph API 作为代理人访问和管理 Outlook 电子邮件和日历,支持三种发送模式:作为自己、作为所有者(Send As)或代表所有者(Send on Behalf)。

AI应用 0 次安装 0 次浏览 更新于 2/24/2026

Outlook Delegate 技能

作为 代理人 通过 Microsoft Graph API 访问另一用户的 Outlook/Microsoft 365 电子邮件和日历。支持三种发送模式:作为自己、作为所有者或代表所有者。

代理架构

此技能适用于以下场景:

  • 你的 AI 助手(代理人)拥有自己的 Microsoft 365 账户
  • 所有者 已授予助手对其邮箱/日历的代理访问权限
  • 助手可以作为自己、作为所有者或代表所有者发送电子邮件

发送模式解释

所有三种模式使用相同的 Graph API 调用(/users/{delegate}/sendMail 并将 from 字段设置)。Send As 和 Send on Behalf 之间的区别完全由授予的 Exchange 权限决定,而不是 API 端点。

模式 命令 需要的 Exchange 权限 from 字段 sender 字段 收件人看到的
作为自己 send (不需要额外的) 代理人 代理人 “From: Assistant”
作为所有者(Send As) send-as 仅 SendAs 所有者 所有者 “From: Owner”
代表所有者 send-behalf 仅 SendOnBehalf 所有者 代理人 “From: Assistant on behalf of Owner”

⚠️ 重要: 不要同时授予 SendAs 和 SendOnBehalf 权限。如果同时授予,Exchange 总是使用 SendAs,并且永远不会显示 “on behalf of” 指示。根据你期望的行为选择一个。

工作原理

当你调用 send-assend-behalf 时,技能会进行相同的 API 调用:通过代理人的端点发送,并将所有者放在 from 字段中。Microsoft Graph 自动将 sender 属性设置为经过身份验证的用户(代理人)。收件人是否看到 “on behalf of” 完全取决于 Exchange 权限:

  • SendAs 权限 → Graph 将 senderfrom 都设置为所有者。没有代理指示。
  • SendOnBehalf 权限 → Graph 保持 sender 为代理人,from 为所有者。收件人看到 “on behalf of.”

配置

配置文件:~/.outlook-mcp/config.json

{
  "client_id": "你的应用客户端 ID",
  "client_secret": "你的应用客户端密钥",
  "tenant_id": "你的租户 ID",
  "owner_email": "owner@yourdomain.com",
  "owner_name": "所有者显示名称",
  "delegate_email": "assistant@yourdomain.com",
  "delegate_name": "AI Assistant",
  "timezone": "America/New_York"
}
字段 描述
client_id Microsoft Entra ID 应用注册客户端 ID
client_secret Microsoft Entra ID 应用注册客户端密钥
tenant_id 你的 Microsoft Entra 租户 ID(设置过程中自动检测)
owner_email 助手作为代理访问的邮箱
owner_name 所有者的显示名称(用于 From 字段)
delegate_email 助手自己的电子邮件地址
delegate_name 助手的显示名称
timezone 日历操作的 IANA 时区(例如 America/New_York, Europe/London, UTC

设置要求

1. Microsoft Entra ID 应用注册

在 Azure 门户中创建应用注册:

  1. 访问 portal.azure.com → Microsoft Entra ID → 应用注册
  2. 新注册:
    • 名称:“AI Assistant Mail Access”
    • 支持的账户类型:“仅限此组织目录中的账户”(单一租户)
    • 重定向 URI:http://localhost:8400/callback
  3. 记录 应用程序(客户端)ID目录(租户)ID

2. 配置 API 权限

在你的应用 → API 权限 → 添加权限 → Microsoft Graph → 委托权限:

所有模式都需要:

  • Mail.ReadWrite — 读取/写入助手自己的邮件
  • Mail.Send — 作为助手发送邮件
  • Calendars.ReadWrite — 读取/写入日历
  • User.Read — 读取自己的个人资料
  • offline_access — 刷新令牌

代理访问需要:

  • Mail.ReadWrite.Shared — 读取/写入共享邮箱
  • Mail.Send.Shared — 代表他人发送
  • Calendars.ReadWrite.Shared — 读取/写入共享日历

点击 “授予管理员同意”(需要管理员)。

3. 创建客户端密钥

  1. 证书和密钥 → 新客户端密钥
  2. 描述:“AI Assistant”
  3. 过期时间:选择适当的时长
  4. 立即复制值(仅显示一次)

4. 授予 Exchange 代理权限

所有者(或管理员)必须通过 PowerShell 授予助手访问权限。

首先选择你的发送模式,然后授予适当的权限:

# 连接到 Exchange Online
Install-Module -Name ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName admin@yourdomain.com

# 必需:完整邮箱访问权限(用于阅读所有者的邮件)
Add-MailboxPermission -Identity "owner@yourdomain.com" `
    -User "assistant@yourdomain.com" `
    -AccessRights FullAccess `
    -InheritanceType All `
    -AutoMapping $false

# 必需:日历代理访问权限
Add-MailboxFolderPermission -Identity "owner@yourdomain.com:\Calendar" `
    -User "assistant@yourdomain.com" `
    -AccessRights Editor `
    -SharingPermissionFlags Delegate

然后选择以下之一 — 不要同时授予:

# 选项 A:作为发送(电子邮件直接显示为所有者,没有指示)
Add-RecipientPermission -Identity "owner@yourdomain.com" `
    -Trustee "assistant@yourdomain.com" `
    -AccessRights SendAs `
    -Confirm:$false
# 选项 B:代表发送(电子邮件显示为 "助手代表所有者")
Set-Mailbox -Identity "owner@yourdomain.com" `
    -GrantSendOnBehalfTo "assistant@yourdomain.com"

验证权限:

# 检查邮箱权限
Get-MailboxPermission -Identity "owner@yourdomain.com" | Where-Object {$_.User -like "*assistant*"}

# 检查 Send As
Get-RecipientPermission -Identity "owner@yourdomain.com" | Where-Object {$_.Trustee -like "*assistant*"}

# 检查 Send on Behalf
Get-Mailbox "owner@yourdomain.com" | Select-Object GrantSendOnBehalfTo

# 检查日历权限
Get-MailboxFolderPermission -Identity "owner@yourdomain.com:\Calendar"

5. 权限总结

操作 Graph 权限 Exchange 权限
读取所有者的邮件 Mail.ReadWrite.Shared FullAccess
作为自己发送 Mail.Send (不需要)
作为所有者发送 Mail.Send.Shared SendAs
代表所有者发送 Mail.Send.Shared SendOnBehalf
读取/写入所有者的日历 Calendars.ReadWrite.Shared Editor

使用方法

令牌管理

./scripts/outlook-token.sh refresh   # 刷新过期的令牌
./scripts/outlook-token.sh test      # 测试连接到两个账户
./scripts/outlook-token.sh get       # 打印访问令牌
./scripts/outlook-token.sh info      # 显示配置信息

读取所有者的电子邮件

./scripts/outlook-mail.sh inbox [count]           # 所有者的收件箱
./scripts/outlook-mail.sh unread [count]          # 所有者未读邮件
./scripts/outlook-mail.sh search "query" [count]  # 搜索所有者的邮件
./scripts/outlook-mail.sh from <email> [count]    # 来自发件人的邮件
./scripts/outlook-mail.sh read <id>               # 阅读邮件内容
./scripts/outlook-mail.sh attachments <id>        # 列出附件

管理所有者的电子邮件

./scripts/outlook-mail.sh mark-read <id>          # 标记为已读
./scripts/outlook-mail.sh mark-unread <id>        # 标记为未读
./scripts/outlook-mail.sh flag <id>               # 标记为重要
./scripts/outlook-mail.sh unflag <id>             # 移除标记
./scripts/outlook-mail.sh delete <id>             # 移动到垃圾箱
./scripts/outlook-mail.sh archive <id>            # 移动到归档
./scripts/outlook-mail.sh move <id> <folder>      # 移动到文件夹

发送电子邮件

作为助手(自己):

./scripts/outlook-mail.sh send <to> <subject> <body>
./scripts/outlook-mail.sh reply <id> "body"
./scripts/outlook-mail.sh forward <id> <to> [message]

收件人看到:“From: AI Assistant assistant@domain.com

作为所有者(Send As — 需要 SendAs 权限,无指示):

./scripts/outlook-mail.sh send-as <to> <subject> <body>
./scripts/outlook-mail.sh reply-as <id> "body"
./scripts/outlook-mail.sh forward-as <id> <to> [message]

收件人看到:“From: Owner owner@domain.com

代表所有者(需要 SendOnBehalf 权限):

./scripts/outlook-mail.sh send-behalf <to> <subject> <body>
./scripts/outlook-mail.sh reply-behalf <id> "body"
./scripts/outlook-mail.sh forward-behalf <id> <to> [message]

收件人看到:“From: AI Assistant on behalf of Owner owner@domain.com

草稿

./scripts/outlook-mail.sh draft <to> <subject> <body>  # 在所有者的邮箱中创建草稿
./scripts/outlook-mail.sh drafts [count]               # 列出所有者的草稿
./scripts/outlook-mail.sh send-draft <id>              # 作为自己发送草稿
./scripts/outlook-mail.sh send-draft-as <id>           # 作为所有者发送草稿
./scripts/outlook-mail.sh send-draft-behalf <id>       # 代表所有者发送草稿

文件夹 & 统计

./scripts/outlook-mail.sh folders                 # 列出邮件文件夹
./scripts/outlook-mail.sh stats                   # 收件箱统计信息
./scripts/outlook-mail.sh whoami                  # 显示代理人信息

日历

查看事件:

./scripts/outlook-calendar.sh events [count]      # 所有者即将发生的事件(仅限未来)
./scripts/outlook-calendar.sh today               # 今天的事件(时区感知)
./scripts/outlook-calendar.sh week                # 本周的事件
./scripts/outlook-calendar.sh read <id>           # 事件详情
./scripts/outlook-calendar.sh calendars           # 列出所有日历
./scripts/outlook-calendar.sh free <start> <end>  # 检查可用性

创建事件:

./scripts/outlook-calendar.sh create <subject> <start> <end> [location]
./scripts/outlook-calendar.sh quick <subject> [time]

日期格式:YYYY-MM-DDTHH:MM(例如,2026-01-26T10:00

管理事件:

./scripts/outlook-calendar.sh update <id> <field> <value>
./scripts/outlook-calendar.sh delete <id>

字段:subject, location, start, end

发送项目行为

发送副本保存的位置取决于使用的端点,而不是发送模式:

命令 使用的端点 保存到
send(作为自己) /users/{delegate}/sendMail 代理人的已发送项目
send-as /users/{delegate}/sendMail 代理人的已发送项目 *
send-behalf /users/{delegate}/sendMail 代理人的已发送项目 *
所有草稿发送 /users/{owner}/messages/{id}/send 所有者的已发送项目

* 管理员可以配置 Exchange 以在所有者的已发送项目中也保存一份副本:

Set-Mailbox -Identity "owner@yourdomain.com" -MessageCopyForSentAsEnabled $true -MessageCopyForSendOnBehalfEnabled $true

故障排除

“访问被拒绝” 或 “403 禁止” → 检查助手是否对所有者的邮箱有 MailboxPermission

“ErrorSendAsDenied” → 缺少 SendAs 或 SendOnBehalf 权限。运行上述 PowerShell 命令。

电子邮件不显示 “on behalf of” → 你可能同时授予了 SendAs 和 SendOnBehalf。当两者都存在时,Exchange 总是使用 SendAs(隐藏代理人)。如果你想让 “on behalf of” 出现,请移除 SendAs 权限。

“找不到邮箱” → 验证 config.json 中的 owner_email 是否正确

“AADSTS90002: 找不到租户” → 检查 config.json 中的 tenant_id 是否与你 Microsoft Entra 租户匹配

“令牌过期” → 运行 outlook-token.sh refresh

日历时区错误 → 更新 config.json 中的 timezone(使用 IANA 格式如 America/New_York

安全考虑

  1. 凭证保护~/.outlook-mcp/ 目录自动设置为 700,凭证文件设置为 600
  2. 无进程泄露:令牌刷新和交换操作通过 stdin 传递秘密,而不是命令行参数
  3. 输入清理:所有用户输入通过 jq JSON 转义以防止注入
  4. 审计跟踪:所有操作都记录在所有者的邮箱审计日志中
  5. 范围限制:助手仅能访问明确授予的内容
  6. 撤销:所有者可以通过 Exchange PowerShell 或 Outlook 设置撤销访问权限

撤销访问权限

# 移除所有权限
Remove-MailboxPermission -Identity "owner@yourdomain.com" -User "assistant@yourdomain.com" -AccessRights FullAccess -Confirm:$false

# 移除 Send As(如果授予)
Remove-RecipientPermission -Identity "owner@yourdomain.com" -Trustee "assistant@yourdomain.com" -AccessRights SendAs -Confirm:$false

# 移除 Send on Behalf(如果授予)
Set-Mailbox -Identity "owner@yourdomain.com" -GrantSendOnBehalfTo @{Remove="assistant@yourdomain.com"}

# 移除日历访问权限
Remove-MailboxFolderPermission -Identity "owner@yourdomain.com:\Calendar" -User "assistant@yourdomain.com" -Confirm:$false

文件

  • ~/.outlook-mcp/config.json — 配置(客户端 ID,租户 ID,电子邮件,时区)
  • ~/.outlook-mcp/credentials.json — OAuth 令牌(访问 + 刷新)

更新日志

v1.1.0

  • FIXED: Reply 命令不再发送重复的电子邮件(移除发送垃圾邮件的死代码)
  • FIXED: 所有回复/转发变体现在使用适当的 Graph API 线程(createReply/createForward → patch from → send)
  • FIXED: send-as 和 send-behalf 现在正确记录 — 行为取决于 Exchange 权限,而不是 API 端点
  • FIXED: send-draft-behalf 不再在发送前删除草稿(防止发送失败时数据丢失)
  • FIXED: 所有用户输入现在通过 jq JSON 转义以防止注入和畸形负载
  • FIXED: 每次写入时强制执行凭证文件权限(chmod 600
  • FIXED: 配置目录权限强制执行(chmod 700
  • FIXED: 客户端秘密不再在进程列表中可见(通过 stdin 发送)
  • FIXED: 日历 events 命令现在仅显示未来事件
  • FIXED: 发送项目行为准确记录
  • FIXED: 版本号更正
  • 更新 Microsoft Entra ID 命名(以前称为 Azure Active Directory)
  • 设置指南现在明确警告不要同时授予 SendAs 和 SendOnBehalf
  • 撤销命令更新(GrantSendOnBehalfTo 使用 @{Remove=…} 语法)

v1.0.0

  • 三种发送模式:作为自己、作为所有者(Send As)、代表所有者
  • 租户特定的认证(没有 /common 端点)
  • 可配置的日历操作时区
  • 所有者和代理人的显示名称
  • 保存到所有者邮箱的草稿
  • 全面的 PowerShell 设置命令
  • 基于 outlook v1.3.0 由 jotamed(https://clawhub.ai/jotamed/outlook)开发