Skip to main content

Microsoft Teams(外掛)

“Abandon all hope, ye who enter here.”
更新日期:2026-01-21 狀態:支援文字與私訊附件;頻道/群組檔案發送需要 sharePointSiteId 與 Graph 權限(參見在群組聊天中傳送檔案)。投票功能透過 Adaptive Cards 發動。

需要外掛

Microsoft Teams 以外掛形式發布,未隨核心安裝捆綁。 重大變更(2026.1.15): MS Teams 已移出核心。若你使用它,必須安裝外掛。 透過 CLI 安裝(npm registry):
openclaw plugins install @openclaw/msteams
本地 checkout(從 git repo 執行時):
openclaw plugins install ./extensions/msteams
若你在設定/上線過程中選擇 Teams 且偵測到 git checkout,OpenClaw 將自動提供本地安裝路徑。 詳情:Plugins

快速設定(初學者)

  1. 安裝 Microsoft Teams 外掛。
  2. 建立 Azure Bot(取得 App ID、用戶端 secret 和租戶 ID)。
  3. 以這些憑證設定 OpenClaw。
  4. 透過公開 URL 或 tunnel 暴露 /api/messages(預設埠 3978)。
  5. 安裝 Teams App 套件並啟動 gateway。
最小設定:
{
  channels: {
    msteams: {
      enabled: true,
      appId: "<APP_ID>",
      appPassword: "<APP_PASSWORD>",
      tenantId: "<TENANT_ID>",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}
注意:群組聊天預設被封鎖(channels.msteams.groupPolicy: "allowlist")。若要允許群組回覆,請設定 channels.msteams.groupAllowFrom(或使用 groupPolicy: "open" 以允許任何成員,仍需 mention)。

目標

  • 透過 Teams 私訊、群組聊天或頻道與 OpenClaw 對話。
  • 保持路由確定性:回覆始終回到訊息來源的頻道。
  • 預設安全的頻道行為(除非另行設定,否則需要 mention)。

設定寫入

預設情況下,Microsoft Teams 允許由 /config set|unset 觸發的設定寫入(需要 commands.config: true)。 停用:
{
  channels: { msteams: { configWrites: false } },
}

存取控制(DM + 群組)

DM 存取
  • 預設:channels.msteams.dmPolicy = "pairing"。未知發送者在核准前被忽略。
  • channels.msteams.allowFrom 應使用穩定的 AAD 物件 ID。
  • UPN/顯示名稱是可變的;直接匹配預設停用,只有在 channels.msteams.dangerouslyAllowNameMatching: true 時才啟用。
  • 精靈在憑證允許時可以透過 Microsoft Graph 將名稱解析為 ID。
群組存取
  • 預設:channels.msteams.groupPolicy = "allowlist"(除非新增 groupAllowFrom,否則封鎖)。使用 channels.defaults.groupPolicy 在未設定時覆蓋預設。
  • channels.msteams.groupAllowFrom 控制哪些發送者可以在群組聊天/頻道中觸發(退回到 channels.msteams.allowFrom)。
  • 設定 groupPolicy: "open" 允許任何成員(預設仍需 mention)。
  • 若要不允許任何頻道,設定 channels.msteams.groupPolicy: "disabled"
範例:
{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["user@org.com"],
    },
  },
}
Teams + 頻道 allowlist
  • channels.msteams.teams 下列出 teams 和頻道,限制群組/頻道回覆範圍。
  • 鍵應使用穩定的 team ID 和頻道 conversation ID。
  • groupPolicy="allowlist" 且存在 teams allowlist 時,只有列出的 teams/頻道被接受(需要 mention)。
  • 設定精靈接受 Team/Channel 條目並為你儲存。
  • 啟動時,OpenClaw 將 team/頻道和用戶 allowlist 名稱解析為 ID(當 Graph 權限允許時)並記錄對應;未解析的 team/頻道名稱保留原樣但預設不用於路由,除非啟用 channels.msteams.dangerouslyAllowNameMatching: true
範例:
{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      teams: {
        "My Team": {
          channels: {
            General: { requireMention: true },
          },
        },
      },
    },
  },
}

運作原理

  1. 安裝 Microsoft Teams 外掛。
  2. 建立 Azure Bot(App ID + secret + 租戶 ID)。
  3. 建立引用 bot 並包含 RSC 權限的 Teams App 套件(見下方)。
  4. 將 Teams App 上傳/安裝到 team(或個人範圍用於私訊)。
  5. ~/.openclaw/openclaw.json(或環境變數)中設定 msteams 並啟動 gateway。
  6. Gateway 預設監聽 /api/messages 上的 Bot Framework webhook 流量。

Azure Bot 設定(前置條件)

設定 OpenClaw 前,你需要建立 Azure Bot 資源。

步驟 1:建立 Azure Bot

  1. 前往 Create Azure Bot
  2. 填寫 Basics 分頁:
    欄位
    Bot handle你的 bot 名稱,例如 openclaw-msteams(需唯一)
    Subscription選擇你的 Azure 訂閱
    Resource group建立新的或使用現有的
    Pricing tierFree(用於開發/測試)
    Type of AppSingle Tenant(建議,見下方說明)
    Creation typeCreate new Microsoft App ID
棄用說明: 2025-07-31 後,新的多租戶 bot 建立已棄用。新 bot 請使用 Single Tenant
  1. 點擊 Review + createCreate(等待約 1-2 分鐘)

步驟 2:取得憑證

  1. 前往你的 Azure Bot 資源 → Configuration
  2. 複製 Microsoft App ID → 這是你的 appId
  3. 點擊 Manage Password → 前往 App Registration
  4. Certificates & secretsNew client secret → 複製 Value → 這是你的 appPassword
  5. 前往 Overview → 複製 Directory (tenant) ID → 這是你的 tenantId

步驟 3:設定 Messaging Endpoint

  1. 在 Azure Bot → Configuration
  2. Messaging endpoint 設定為你的 webhook URL:

步驟 4:啟用 Teams 頻道

  1. 在 Azure Bot → Channels
  2. 點擊 Microsoft Teams → Configure → Save
  3. 接受服務條款

本地開發(Tunneling)

Teams 無法連接到 localhost。本地開發請使用 tunnel: 方案 A:ngrok
ngrok http 3978
# 複製 https URL,例如 https://abc123.ngrok.io
# 將 messaging endpoint 設定為:https://abc123.ngrok.io/api/messages
方案 B:Tailscale Funnel
tailscale funnel 3978
# 使用你的 Tailscale funnel URL 作為 messaging endpoint

Teams Developer Portal(替代方案)

除了手動建立 manifest ZIP,你也可以使用 Teams Developer Portal
  1. 點擊 + New app
  2. 填寫基本資訊(名稱、描述、開發者資訊)
  3. 前往 App featuresBot
  4. 選擇 Enter a bot ID manually 並貼上 Azure Bot App ID
  5. 勾選範圍:PersonalTeamGroup Chat
  6. 點擊 DistributeDownload app package
  7. 在 Teams:AppsManage your appsUpload a custom app → 選擇 ZIP
這通常比手動編輯 JSON manifest 更容易。

測試 Bot

方案 A:Azure Web Chat(先驗證 webhook)
  1. 在 Azure Portal → 你的 Azure Bot 資源 → Test in Web Chat
  2. 傳送訊息——你應該看到回覆
  3. 這確認在設定 Teams 前你的 webhook 端點能正常運作
方案 B:Teams(安裝 App 後)
  1. 安裝 Teams App(sideload 或 org catalog)
  2. 在 Teams 中找到 bot 並傳送私訊
  3. 確認 gateway 日誌中的入站活動

設定(最小文字模式)

  1. 安裝 Microsoft Teams 外掛
    • 從 npm:openclaw plugins install @openclaw/msteams
    • 從本地 checkout:openclaw plugins install ./extensions/msteams
  2. Bot 註冊
    • 建立 Azure Bot(見上方)並記下:
      • App ID
      • 用戶端 secret(App password)
      • 租戶 ID(single-tenant)
  3. Teams App Manifest
    • 包含帶有 botId = <App ID>bot 條目。
    • Scopes:personalteamgroupChat
    • supportsFiles: true(個人範圍檔案處理必要)。
    • 新增 RSC 權限(見下方)。
    • 建立圖示:outline.png(32x32)和 color.png(192x192)。
    • 將三個檔案壓縮:manifest.jsonoutline.pngcolor.png
  4. 設定 OpenClaw
    {
      "msteams": {
        "enabled": true,
        "appId": "<APP_ID>",
        "appPassword": "<APP_PASSWORD>",
        "tenantId": "<TENANT_ID>",
        "webhook": { "port": 3978, "path": "/api/messages" }
      }
    }
    
    也可以使用環境變數:
    • MSTEAMS_APP_ID
    • MSTEAMS_APP_PASSWORD
    • MSTEAMS_TENANT_ID
  5. Bot 端點
    • 將 Azure Bot Messaging Endpoint 設定為:
      • https://<host>:3978/api/messages(或你選擇的路徑/埠)。
  6. 執行 gateway
    • 安裝外掛且存在帶有憑證的 msteams 設定時,Teams 頻道自動啟動。

歷史記錄上下文

  • channels.msteams.historyLimit 控制將多少條最近的頻道/群組訊息包裝到 prompt 中。
  • 退回到 messages.groupChat.historyLimit。設定 0 停用(預設 50)。
  • DM 歷史可用 channels.msteams.dmHistoryLimit 限制(用戶回合)。每用戶覆蓋:channels.msteams.dms["<user_id>"].historyLimit

目前的 Teams RSC 權限(Manifest)

這些是我們 Teams App manifest 中現有的 resourceSpecific 權限。它們只適用於安裝 App 的 team/聊天中。 頻道(team 範圍):
  • ChannelMessage.Read.Group(Application)- 無需 @mention 接收所有頻道訊息
  • ChannelMessage.Send.Group(Application)
  • Member.Read.Group(Application)
  • Owner.Read.Group(Application)
  • ChannelSettings.Read.Group(Application)
  • TeamMember.Read.Group(Application)
  • TeamSettings.Read.Group(Application)
群組聊天:
  • ChatMessage.Read.Chat(Application)- 無需 @mention 接收所有群組聊天訊息

Teams Manifest 範例(部分省略)

最小有效範例,包含必填欄位。請替換 ID 和 URL。
{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.23/MicrosoftTeams.schema.json",
  "manifestVersion": "1.23",
  "version": "1.0.0",
  "id": "00000000-0000-0000-0000-000000000000",
  "name": { "short": "OpenClaw" },
  "developer": {
    "name": "Your Org",
    "websiteUrl": "https://example.com",
    "privacyUrl": "https://example.com/privacy",
    "termsOfUseUrl": "https://example.com/terms"
  },
  "description": { "short": "OpenClaw in Teams", "full": "OpenClaw in Teams" },
  "icons": { "outline": "outline.png", "color": "color.png" },
  "accentColor": "#5B6DEF",
  "bots": [
    {
      "botId": "11111111-1111-1111-1111-111111111111",
      "scopes": ["personal", "team", "groupChat"],
      "isNotificationOnly": false,
      "supportsCalling": false,
      "supportsVideo": false,
      "supportsFiles": true
    }
  ],
  "webApplicationInfo": {
    "id": "11111111-1111-1111-1111-111111111111"
  },
  "authorization": {
    "permissions": {
      "resourceSpecific": [
        { "name": "ChannelMessage.Read.Group", "type": "Application" },
        { "name": "ChannelMessage.Send.Group", "type": "Application" },
        { "name": "Member.Read.Group", "type": "Application" },
        { "name": "Owner.Read.Group", "type": "Application" },
        { "name": "ChannelSettings.Read.Group", "type": "Application" },
        { "name": "TeamMember.Read.Group", "type": "Application" },
        { "name": "TeamSettings.Read.Group", "type": "Application" },
        { "name": "ChatMessage.Read.Chat", "type": "Application" }
      ]
    }
  }
}

Manifest 注意事項(必填欄位)

  • bots[].botId 必須符合 Azure Bot App ID。
  • webApplicationInfo.id 必須符合 Azure Bot App ID。
  • bots[].scopes 必須包含你計劃使用的服務(personalteamgroupChat)。
  • bots[].supportsFiles: true 是個人範圍檔案處理的必要條件。
  • authorization.permissions.resourceSpecific 若你想要頻道流量,必須包含頻道讀/寫。

更新現有 App

若要更新已安裝的 Teams App(例如新增 RSC 權限):
  1. 用新設定更新 manifest.json
  2. 遞增 version 欄位(例如 1.0.01.1.0
  3. 重新壓縮 manifest 和圖示(manifest.jsonoutline.pngcolor.png
  4. 上傳新的 zip:
    • 方案 A(Teams Admin Center): Teams Admin Center → Teams apps → Manage apps → 找到你的 App → Upload new version
    • 方案 B(Sideload): 在 Teams → Apps → Manage your apps → Upload a custom app
  5. 對於 team 頻道: 在每個 team 中重新安裝 App 以使新權限生效
  6. 完全退出並重新啟動 Teams(不只是關閉視窗)以清除快取的 App metadata

功能:僅 RSC vs Graph

只有 Teams RSC(已安裝 App,無 Graph API 權限)

可用:
  • 讀取頻道訊息文字內容。
  • 傳送頻道訊息文字內容。
  • 接收**個人(DM)**檔案附件。
不可用:
  • 頻道/群組圖片或檔案內容(payload 只包含 HTML 存根)。
  • 下載儲存在 SharePoint/OneDrive 中的附件。
  • 讀取訊息歷史(超出即時 webhook 事件範圍)。

Teams RSC + Microsoft Graph 應用程式權限

新增:
  • 下載已託管的內容(貼入訊息的圖片)。
  • 下載儲存在 SharePoint/OneDrive 中的檔案附件。
  • 透過 Graph 讀取頻道/聊天訊息歷史。

RSC vs Graph API

功能RSC 權限Graph API
即時訊息是(透過 webhook)否(僅輪詢)
歷史訊息是(可查詢歷史)
設定複雜度僅需 App manifest需要管理員同意 + token 流程
離線時可用否(必須執行中)是(隨時查詢)
結論: RSC 用於即時監聽;Graph API 用於歷史存取。若需要補齊離線時錯過的訊息,你需要帶有 ChannelMessage.Read.All 的 Graph API(需要管理員同意)。

Graph 媒體 + 歷史(頻道必需)

若需要頻道中的圖片/檔案或想要獲取訊息歷史,必須啟用 Microsoft Graph 權限並授予管理員同意。
  1. 在 Entra ID(Azure AD)App Registration 中,新增 Microsoft Graph Application 權限
    • ChannelMessage.Read.All(頻道附件 + 歷史)
    • Chat.Read.AllChatMessage.Read.All(群組聊天)
  2. 為租戶授予管理員同意
  3. 遞增 Teams App manifest version,重新上傳,並在 Teams 中重新安裝 App
  4. 完全退出並重新啟動 Teams 以清除快取的 App metadata。
用戶 @mention 的額外權限: 對話中的用戶 @mention 直接可用。但若你想動態搜尋和 mention 不在目前對話中的用戶,需新增 User.Read.All(Application)權限並授予管理員同意。

已知限制

Webhook 逾時

Teams 透過 HTTP webhook 傳遞訊息。若處理時間過長(例如 LLM 回覆緩慢),可能出現:
  • Gateway 逾時
  • Teams 重試訊息(導致重複)
  • 回覆遺失
OpenClaw 透過快速返回並主動傳送回覆來處理此問題,但非常慢的回覆仍可能造成問題。

格式化

Teams Markdown 比 Slack 或 Discord 更有限:
  • 基本格式可用:粗體斜體code、連結
  • 複雜 Markdown(表格、巢狀列表)可能無法正確渲染
  • 支援 Adaptive Cards 用於投票和任意卡片傳送(見下方)

設定

主要設定(共享頻道模式請參閱 /gateway/configuration):
  • channels.msteams.enabled:啟用/停用頻道。
  • channels.msteams.appIdchannels.msteams.appPasswordchannels.msteams.tenantId:bot 憑證。
  • channels.msteams.webhook.port(預設 3978
  • channels.msteams.webhook.path(預設 /api/messages
  • channels.msteams.dmPolicypairing | allowlist | open | disabled(預設:pairing)
  • channels.msteams.allowFrom:DM allowlist(建議使用 AAD 物件 ID)。精靈在 Graph 存取可用時設定期間將名稱解析為 ID。
  • channels.msteams.dangerouslyAllowNameMatching:緊急切換,重新啟用可變的 UPN/顯示名稱匹配和直接 team/頻道名稱路由。
  • channels.msteams.textChunkLimit:出站文字分塊大小。
  • channels.msteams.chunkModelength(預設)或 newline,在長度分塊前按空白行(段落邊界)分割。
  • channels.msteams.mediaAllowHosts:入站附件主機 allowlist(預設為 Microsoft/Teams 域名)。
  • channels.msteams.mediaAuthAllowHosts:在媒體重試時附加 Authorization 標頭的主機 allowlist(預設為 Graph + Bot Framework 主機)。
  • channels.msteams.requireMention:在頻道/群組中需要 @mention(預設 true)。
  • channels.msteams.replyStylethread | top-level(見回覆樣式:Thread vs Post)。
  • channels.msteams.teams.<teamId>.replyStyle:每 team 覆蓋。
  • channels.msteams.teams.<teamId>.requireMention:每 team 覆蓋。
  • channels.msteams.teams.<teamId>.tools:預設每 team 工具政策覆蓋(allow/deny/alsoAllow)。
  • channels.msteams.teams.<teamId>.toolsBySender:預設每 team 每發送者工具政策覆蓋(支援 "*" 萬用字元)。
  • channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle:每頻道覆蓋。
  • channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention:每頻道覆蓋。
  • channels.msteams.teams.<teamId>.channels.<conversationId>.tools:每頻道工具政策覆蓋。
  • channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender:每頻道每發送者工具政策覆蓋。
  • toolsBySender 鍵應使用明確前綴:id:e164:username:name:(舊版無前綴鍵仍只對應到 id:)。
  • channels.msteams.sharePointSiteId:用於群組聊天/頻道中上傳檔案的 SharePoint 站台 ID(見在群組聊天中傳送檔案)。

路由與工作階段

  • 工作階段金鑰遵循標準 Agent 格式(見 /concepts/session):
    • 私訊共享主要工作階段(agent:<agentId>:<mainKey>)。
    • 頻道/群組訊息使用 conversation id:
      • agent:<agentId>:msteams:channel:<conversationId>
      • agent:<agentId>:msteams:group:<conversationId>

回覆樣式:Thread vs Post

Teams 最近在相同底層資料模型上引入了兩種頻道 UI 樣式:
樣式描述建議 replyStyle
Posts(傳統)訊息顯示為卡片,下方有巢狀回覆thread(預設)
Threads(類 Slack)訊息線性流動,更像 Slacktop-level
問題: Teams API 不揭露頻道使用哪種 UI 樣式。若使用了錯誤的 replyStyle
  • 在 Threads 樣式頻道使用 thread → 回覆顯示在巢狀位置,看起來很奇怪
  • 在 Posts 樣式頻道使用 top-level → 回覆顯示為單獨的頂層文章而非串中
解決方案: 根據頻道設定方式,每頻道設定 replyStyle
{
  "msteams": {
    "replyStyle": "thread",
    "teams": {
      "19:abc...@thread.tacv2": {
        "channels": {
          "19:xyz...@thread.tacv2": {
            "replyStyle": "top-level"
          }
        }
      }
    }
  }
}

附件與圖片

目前限制:
  • 私訊: 圖片和檔案附件透過 Teams bot 檔案 API 運作。
  • 頻道/群組: 附件存放在 M365 儲存(SharePoint/OneDrive)中。Webhook payload 只包含 HTML 存根,不含實際檔案位元組。下載頻道附件需要 Graph API 權限
若無 Graph 權限,包含圖片的頻道訊息將以純文字接收(圖片內容無法存取)。 預設情況下,OpenClaw 只從 Microsoft/Teams 主機名稱下載媒體。使用 channels.msteams.mediaAllowHosts 覆蓋(使用 ["*"] 允許任何主機)。 Authorization 標頭只附加到 channels.msteams.mediaAuthAllowHosts 中的主機(預設為 Graph + Bot Framework 主機)。請保持此清單嚴格(避免多租戶後綴)。

在群組聊天中傳送檔案

Bot 可以使用 FileConsentCard 流程在私訊中傳送檔案(內建)。但在群組聊天/頻道中傳送檔案需要額外設定:
情境傳送方式所需設定
私訊FileConsentCard → 用戶接受 → bot 上傳直接可用
群組聊天/頻道上傳至 SharePoint → 分享連結需要 sharePointSiteId + Graph 權限
圖片(任何情境)Base64 編碼內嵌直接可用

為什麼群組聊天需要 SharePoint

Bot 沒有個人 OneDrive 磁碟機(/me/drive Graph API 端點對應用程式身份不適用)。若要在群組聊天/頻道中傳送檔案,bot 需上傳至 SharePoint 站台並建立分享連結。

設定

  1. 在 Entra ID(Azure AD)→ App Registration 中新增 Graph API 權限
    • Sites.ReadWrite.All(Application)- 上傳檔案至 SharePoint
    • Chat.Read.All(Application)- 選用,啟用每用戶分享連結
  2. 為租戶授予管理員同意
  3. 取得你的 SharePoint 站台 ID:
    # 透過 Graph Explorer 或帶有有效 token 的 curl:
    curl -H "Authorization: Bearer $TOKEN" \
      "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}"
    
    # 範例:位於 "contoso.sharepoint.com/sites/BotFiles" 的站台
    curl -H "Authorization: Bearer $TOKEN" \
      "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles"
    
    # 回應包含:"id": "contoso.sharepoint.com,guid1,guid2"
    
  4. 設定 OpenClaw:
    {
      channels: {
        msteams: {
          // ... 其他設定 ...
          sharePointSiteId: "contoso.sharepoint.com,guid1,guid2",
        },
      },
    }
    

分享行為

權限分享行為
Sites.ReadWrite.All整個組織分享連結(組織中任何人都可存取)
Sites.ReadWrite.All + Chat.Read.All每用戶分享連結(只有聊天成員可存取)
每用戶分享更安全,因為只有聊天參與者可以存取檔案。若缺少 Chat.Read.All 權限,bot 退回到整個組織分享。

備援行為

情境結果
群組聊天 + 檔案 + 已設定 sharePointSiteId上傳至 SharePoint,傳送分享連結
群組聊天 + 檔案 + 未設定 sharePointSiteId嘗試 OneDrive 上傳(可能失敗),僅傳文字
個人聊天 + 檔案FileConsentCard 流程(無需 SharePoint)
任何情境 + 圖片Base64 編碼內嵌(無需 SharePoint)

檔案儲存位置

上傳的檔案儲存在已設定 SharePoint 站台預設文件庫的 /OpenClawShared/ 資料夾中。

投票(Adaptive Cards)

OpenClaw 以 Adaptive Cards 傳送 Teams 投票(無原生 Teams 投票 API)。
  • CLI:openclaw message poll --channel msteams --target conversation:<id> ...
  • 投票由 gateway 記錄在 ~/.openclaw/msteams-polls.json
  • Gateway 必須保持在線才能記錄投票。
  • 投票不會自動張貼結果摘要(如需請檢查儲存檔案)。

Adaptive Cards(任意)

使用 message 工具或 CLI 向 Teams 用戶或對話傳送任意 Adaptive Card JSON。 card 參數接受 Adaptive Card JSON 物件。提供 card 時,訊息文字是選用的。 Agent 工具:
{
  "action": "send",
  "channel": "msteams",
  "target": "user:<id>",
  "card": {
    "type": "AdaptiveCard",
    "version": "1.5",
    "body": [{ "type": "TextBlock", "text": "Hello!" }]
  }
}
CLI:
openclaw message send --channel msteams \
  --target "conversation:19:abc...@thread.tacv2" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello!"}]}'
請參閱 Adaptive Cards 文件 了解卡片結構和範例。目標格式詳情請見下方目標格式

目標格式

MSTeams 目標使用前綴區分用戶和對話:
目標類型格式範例
用戶(依 ID)user:<aad-object-id>user:40a1a0ed-4ff2-4164-a219-55518990c197
用戶(依名稱)user:<display-name>user:John Smith(需要 Graph API)
群組/頻道conversation:<conversation-id>conversation:19:abc123...@thread.tacv2
群組/頻道(原始)<conversation-id>19:abc123...@thread.tacv2(若含 @thread
CLI 範例:
# 依 ID 傳送給用戶
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"

# 依顯示名稱傳送給用戶(觸發 Graph API 查詢)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"

# 傳送至群組聊天或頻道
openclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" --message "Hello"

# 傳送 Adaptive Card 至對話
openclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'
注意:沒有 user: 前綴時,名稱預設為群組/team 解析。依顯示名稱指定人員時請始終使用 user:

主動訊息

  • 主動訊息只有在用戶互動後才可能發送,因為我們在那時儲存了對話引用。
  • DM 政策和 allowlist 限制請參閱 /gateway/configuration

Team 和 Channel ID(常見陷阱)

Teams URL 中的 groupId 查詢參數不是用於設定的 team ID。請從 URL 路徑中提取 ID: Team URL:
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
                                    └────────────────────────────┘
                                    Team ID(URL 解碼此部分)
Channel URL:
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
                                      └─────────────────────────┘
                                      Channel ID(URL 解碼此部分)
用於設定:
  • Team ID = /team/ 後的路徑段(URL 解碼,例如 19:Bk4j...@thread.tacv2
  • Channel ID = /channel/ 後的路徑段(URL 解碼)
  • 忽略 groupId 查詢參數

私人頻道

Bot 在私人頻道中的支援有限:
功能標準頻道私人頻道
Bot 安裝有限
即時訊息(webhook)可能無法運作
RSC 權限行為可能不同
@mention若 bot 可存取則可
Graph API 歷史是(需要權限)
私人頻道不運作時的替代方案:
  1. 使用標準頻道進行 bot 互動
  2. 使用 DM——用戶可以隨時直接訊息 bot
  3. 使用 Graph API 進行歷史存取(需要 ChannelMessage.Read.All

疑難排解

常見問題

  • 頻道中圖片不顯示: 缺少 Graph 權限或管理員同意。重新安裝 Teams App 並完全退出/重新開啟 Teams。
  • 頻道中無回覆: 預設需要 mention;設定 channels.msteams.requireMention=false 或按 team/頻道設定。
  • 版本不匹配(Teams 仍顯示舊 manifest): 移除並重新新增 App,然後完全退出 Teams 以重新整理。
  • Webhook 的 401 Unauthorized: 手動測試時(無 Azure JWT)為預期行為,意味著端點可達但驗證失敗。請使用 Azure Web Chat 進行正確測試。

Manifest 上傳錯誤

  • “Icon file cannot be empty”: Manifest 引用的圖示檔案大小為 0。請建立有效的 PNG 圖示(outline.png 為 32x32,color.png 為 192x192)。
  • “webApplicationInfo.Id already in use”: App 仍安裝在另一個 team/聊天中。先找到並卸載它,或等待 5-10 分鐘讓變更傳播。
  • 上傳時”Something went wrong”: 改由 https://admin.teams.microsoft.com 上傳,開啟瀏覽器 DevTools(F12)→ Network 分頁,檢查回應主體以獲取實際錯誤。
  • Sideload 失敗: 嘗試「Upload an app to your org’s app catalog」而非「Upload a custom app」——這通常可以繞過 sideload 限制。

RSC 權限不運作

  1. 確認 webApplicationInfo.id 完全符合你的 bot App ID
  2. 重新上傳 App 並在 team/聊天中重新安裝
  3. 檢查你的組織管理員是否封鎖了 RSC 權限
  4. 確認你使用了正確的範圍:teams 使用 ChannelMessage.Read.Group,群組聊天使用 ChatMessage.Read.Chat

參考資料