PAYATHON 2026

如何使用 Microsoft Graph API 恢复已删除的日历事件?

数据小许

结论

根据 Microsoft Graph v1.0 公开文档,Graph 无法直接复现 EWS 中“搜索 RecoverableItemsPurges,再将日历项目 move 回 Calendar”的流程。公开的 event 方法没有对应的 restore 或 move 操作,也没有受支持的端点可以枚举 Recoverable Items 中已删除的日历事件。更换 mailFolderId 也无法实现这一流程。event 资源文档

当前查询还存在对象类型不匹配:删除的是日历 event,查询的却是邮件 messages 集合,使用的过滤条件也是邮件的 internetMessageId。即使底层仍保留着日历项目,这样查询也找不到它。

如果必须恢复原有日历项目,可以在项目仍可恢复且具备相应 Exchange 管理权限的前提下,使用 Get-RecoverableItems 和 Restore-RecoverableItems。若应用必须完全使用 Graph,则需要调整“删除后恢复”的业务设计。

permanentDelete() 和 delete() 的去向有什么区别?

permanentDelete() 的文档明确说明,事件会进入邮箱 Recoverable Items 中的 Purges 文件夹。因此,不能将查询不到事件归因于 Graph 把它放到了另一个完全不同的位置。项目之后是否仍保留,取决于邮箱保留设置及 hold 等条件。event: permanentDelete

delete() 是普通删除,去向与 permanentDelete() 不同。Exchange 的普通删除通常先将项目移至 Deleted Items;从 Deleted Items 再次删除,才属于进入 Recoverable Items/Deletions 的软删除。Graph 的 Delete event 文档说明,该操作会从所属日历移除事件,但没有提供配套的恢复接口。Exchange 删除术语与存储结构、Delete event

排查时应分别验证普通删除和永久删除,不能对两者都只搜索 Purges。

为什么按 internetMessageId 查询不到?

这里涉及三个不同的对象:

  • event:日历中的约会或会议,使用事件 id、iCalUId 等属性。
  • eventMessage:会议邀请、取消通知或参会响应等邮件,可以关联到 event。
  • message:邮件资源,internetMessageId 是其邮件标识属性。

EWS 示例先通过 getAssociatedAppointmentId() 找到 Appointment,再删除 Appointment。Graph 示例删除的同样是 event,但恢复查询切换到了 messages。会议通知邮件与对应的日历事件是不同资源,不能把通知邮件的 internetMessageId 当作恢复日历事件的查询键。eventMessage 资源文档

GET /users/{id}/mailFolders/{id}/messages 返回 Message 集合,不是 EWS FindItems 那样的通用项目集合。将过滤条件换成 subject 或去掉过滤条件,都不能让这个端点枚举已删除的日历事件。List messages

哪个 mailFolderId 可以使用?

Graph 文档列出了 deleteditems 和 recoverableitemsdeletions 这两个 well-known folder name,但没有列出 recoverableitemspurges。EWS 的 WellKnownFolderName 名称不能直接转换为 Graph 支持的文件夹别名。

即使拿到了某个文件夹的实际 ID,访问其 messages 集合仍是在查询邮件,不能据此恢复日历 event。mailFolder 的文件夹名称与关系

排查时还应记录实际 HTTP 状态码和错误响应。200 OK 且集合为空,与文件夹名称无效、权限不足或 SDK 异常被上层吞掉,属于不同的问题。现有材料不足以确定每次查询的具体原因。

如何恢复仍保留的日历项目?

如果所在 Exchange 环境支持相关 cmdlet,可以在连接 Exchange PowerShell 并取得所需管理角色后,按日历项目类型查找。下面的邮箱、主题和 EntryID 都需要替换为实际值:

$mailbox = "user@contoso.com"

Get-RecoverableItems -Identity $mailbox `
    -FilterItemType IPM.Appointment `
    -SubjectContains "Meeting subject" `
    -ResultSize Unlimited |
    Format-List

这里不指定 SourceFolder,默认搜索 Deleted Items、Recoverable Items/Deletions 和 Recoverable Items/Purges。如果只排查永久删除后的项目,可以增加 -SourceFolder PurgedItems。PurgedItems 是 Exchange PowerShell 的参数值,不是 Graph 的 mailFolderId。Get-RecoverableItems

核对查询结果后,使用目标项目的 EntryID 恢复,避免仅凭相同主题恢复错误的会议:

Restore-RecoverableItems -Identity $mailbox `
    -EntryID "<EntryID returned by Get-RecoverableItems>"

EntryID 应从上述查询结果取得,不要直接填入 Graph eventId。原文件夹信息可用时,Restore-RecoverableItems 会将项目恢复到原位置;否则,会议和约会会恢复到默认 Calendar 文件夹。能否成功仍取决于项目是否保留及当前权限。Restore-RecoverableItems

迁移代码和业务流程需要注意什么?

删除调用可以采用文档列出的用户事件路径。沿用问题中的 Java SDK 调用风格,普通删除示例如下:

graphClient.users()
    .byUserId(mailboxBeingScanned)
    .events()
    .byEventId(eventId)
    .delete();

这段代码只能完成删除,不会增加恢复能力。Delete event

对于应用内的“撤销删除”,可以先在应用数据层记录删除状态,延后执行 Exchange 删除。如果必须立即删除,则需要提前保存重建所需的数据。重建得到的是新事件,不能承诺保留原事件身份与全部会议状态。

还要注意,在组织者日历上删除会议会向参会者发送取消通知。之后恢复邮箱项目,不能直接视为已经撤销这些通知;恢复后的参会者状态和周期会议行为需要单独验证。会议删除行为

备注:内容仅供参考。