Microsoft Teams (Plugin)

„Lasst, die ihr eintretet, alle Hoffnung fahren.”

Aktualisiert: 2026-01-21

Status: Text + DM-Anhänge werden unterstützt; Kanal-/Gruppen-Dateiversand erfordert sharePointSiteId + Graph-Berechtigungen (siehe Dateien in Gruppenchats senden). Umfragen werden über Adaptive Cards gesendet.

Plugin erforderlich

Microsoft Teams wird als Plugin ausgeliefert und ist nicht in der Kerninstallation enthalten.

Breaking Change (2026.1.15): MS Teams wurde aus dem Kern verschoben. Wenn du es verwendest, musst du das Plugin installieren.

Begründung: hält Kerninstallationen schlanker und ermöglicht unabhängige Updates der MS Teams-Abhängigkeiten.

Installation über CLI (npm-Registry):

openclaw plugins install @openclaw/msteams

Lokaler Checkout (wenn aus einem Git-Repo ausgeführt):

openclaw plugins install ./extensions/msteams

Wenn du Teams während der Konfiguration/des Onboardings auswählst und ein Git-Checkout erkannt wird, bietet OpenClaw automatisch den lokalen Installationspfad an.

Details: Plugins

Schnelleinrichtung (Einsteiger)

  1. Installiere das Microsoft Teams-Plugin.
  2. Erstelle einen Azure Bot (App-ID + Client-Secret + Tenant-ID).
  3. Konfiguriere OpenClaw mit diesen Zugangsdaten.
  4. Exponiere /api/messages (Standard Port 3978) über eine öffentliche URL oder einen Tunnel.
  5. Installiere das Teams-App-Paket und starte das Gateway.

Minimale Konfiguration:

{
  channels: {
    msteams: {
      enabled: true,
      appId: "<APP_ID>",
      appPassword: "<APP_PASSWORD>",
      tenantId: "<TENANT_ID>",
      webhook: { port: 3978, path: "/api/messages" },
    },
  },
}

Hinweis: Gruppenchats sind standardmäßig blockiert (channels.msteams.groupPolicy: "allowlist"). Um Gruppenantworten zu erlauben, setze channels.msteams.groupAllowFrom (oder verwende groupPolicy: "open", um jedes Mitglied zuzulassen, mit Mention-Gating).

Ziele

  • Mit OpenClaw über Teams-DMs, Gruppenchats oder Kanäle kommunizieren.
  • Routing deterministisch halten: Antworten gehen immer zum Kanal zurück, über den sie angekommen sind.
  • Sicheres Kanalverhalten als Standard (Erwähnungen erforderlich, sofern nicht anders konfiguriert).

Konfigurationsschreibvorgänge

Standardmäßig darf Microsoft Teams Konfigurationsupdates schreiben, die durch /config set|unset ausgelöst werden (erfordert commands.config: true).

Deaktivieren mit:

{
  channels: { msteams: { configWrites: false } },
}

Zugriffssteuerung (DMs + Gruppen)

DM-Zugriff

  • Standard: channels.msteams.dmPolicy = "pairing". Unbekannte Absender werden ignoriert, bis sie genehmigt werden.
  • channels.msteams.allowFrom sollte stabile AAD-Objekt-IDs verwenden.
  • UPNs/Anzeigenamen sind veränderlich; direktes Matching ist standardmäßig deaktiviert und nur mit channels.msteams.dangerouslyAllowNameMatching: true aktiviert.
  • Der Assistent kann bei entsprechenden Berechtigungen Namen über Microsoft Graph zu IDs auflösen.

Gruppenzugriff

  • Standard: channels.msteams.groupPolicy = "allowlist" (blockiert, es sei denn, du fügst groupAllowFrom hinzu). Verwende channels.defaults.groupPolicy, um den Standard zu überschreiben, wenn nicht gesetzt.
  • channels.msteams.groupAllowFrom steuert, welche Absender in Gruppenchats/Kanälen auslösen können (Fallback auf channels.msteams.allowFrom).
  • Setze groupPolicy: "open", um jedes Mitglied zuzulassen (standardmäßig weiterhin mit Mention-Gating).
  • Um keine Kanäle zu erlauben, setze channels.msteams.groupPolicy: "disabled".

Beispiel:

{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["[email protected]"],
    },
  },
}

Teams + Kanal-Allowlist

  • Begrenze Gruppen-/Kanalantworten, indem du Teams und Kanäle unter channels.msteams.teams auflistest.
  • Schlüssel sollten stabile Team-IDs und Kanal-Konversations-IDs verwenden.
  • Wenn groupPolicy="allowlist" und eine Teams-Allowlist vorhanden ist, werden nur gelistete Teams/Kanäle akzeptiert (mit Mention-Gating).
  • Der Konfigurationsassistent akzeptiert Team/Channel-Einträge und speichert sie für dich.
  • Beim Start löst OpenClaw Team-/Kanal- und Benutzer-Allowlist-Namen zu IDs auf (wenn Graph-Berechtigungen dies erlauben) und protokolliert die Zuordnung; nicht aufgelöste Team-/Kanalnamen werden wie eingegeben beibehalten, aber standardmäßig beim Routing ignoriert, es sei denn, channels.msteams.dangerouslyAllowNameMatching: true ist aktiviert.

Beispiel:

{
  channels: {
    msteams: {
      groupPolicy: "allowlist",
      teams: {
        "My Team": {
          channels: {
            General: { requireMention: true },
          },
        },
      },
    },
  },
}

Funktionsweise

  1. Installiere das Microsoft Teams-Plugin.
  2. Erstelle einen Azure Bot (App-ID + Secret + Tenant-ID).
  3. Erstelle ein Teams-App-Paket, das den Bot referenziert und die unten aufgeführten RSC-Berechtigungen enthält.
  4. Lade die Teams-App in ein Team hoch oder installiere sie (oder im persönlichen Bereich für DMs).
  5. Konfiguriere msteams in ~/.openclaw/openclaw.json (oder Umgebungsvariablen) und starte das Gateway.
  6. Das Gateway lauscht standardmäßig auf Bot Framework-Webhook-Traffic auf /api/messages.

Azure Bot-Einrichtung (Voraussetzungen)

Bevor du OpenClaw konfigurierst, musst du eine Azure Bot-Ressource erstellen.

Schritt 1: Azure Bot erstellen

  1. Gehe zu Create Azure Bot

  2. Fülle den Tab Basics aus:

    FeldWert
    Bot handleDein Bot-Name, z. B. openclaw-msteams (muss eindeutig sein)
    SubscriptionWähle dein Azure-Abonnement
    Resource groupNeu erstellen oder vorhandene verwenden
    Pricing tierFree für Entwicklung/Tests
    Type of AppSingle Tenant (empfohlen – siehe Hinweis unten)
    Creation typeCreate new Microsoft App ID

Hinweis zur Einstellung: Die Erstellung neuer Multi-Tenant-Bots wurde nach dem 31.07.2025 eingestellt. Verwende Single Tenant für neue Bots.

  1. Klicke auf Review + createCreate (ca. 1-2 Minuten warten)

Schritt 2: Zugangsdaten abrufen

  1. Gehe zu deiner Azure Bot-Ressource → Configuration
  2. Kopiere die Microsoft App ID → dies ist deine appId
  3. Klicke auf Manage Password → gehe zur App-Registrierung
  4. Unter Certificates & secretsNew client secret → kopiere den Value → dies ist dein appPassword
  5. Gehe zu Overview → kopiere die Directory (tenant) ID → dies ist deine tenantId

Schritt 3: Messaging-Endpunkt konfigurieren

  1. In Azure Bot → Configuration
  2. Setze den Messaging endpoint auf deine Webhook-URL:
    • Produktion: https://your-domain.com/api/messages
    • Lokale Entwicklung: Verwende einen Tunnel (siehe Lokale Entwicklung unten)

Schritt 4: Teams-Kanal aktivieren

  1. In Azure Bot → Channels
  2. Klicke auf Microsoft Teams → Configure → Save
  3. Akzeptiere die Nutzungsbedingungen

Lokale Entwicklung (Tunneling)

Teams kann localhost nicht erreichen. Verwende einen Tunnel für die lokale Entwicklung:

Option A: ngrok

ngrok http 3978
# Kopiere die https-URL, z. B. https://abc123.ngrok.io
# Setze den Messaging-Endpunkt auf: https://abc123.ngrok.io/api/messages

Option B: Tailscale Funnel

tailscale funnel 3978
# Verwende deine Tailscale-Funnel-URL als Messaging-Endpunkt

Teams Developer Portal (Alternative)

Anstatt manuell eine Manifest-ZIP-Datei zu erstellen, kannst du das Teams Developer Portal verwenden:

  1. Klicke auf + New app
  2. Fülle die Basisinformationen aus (Name, Beschreibung, Entwicklerinfo)
  3. Gehe zu App featuresBot
  4. Wähle Enter a bot ID manually und füge deine Azure Bot App-ID ein
  5. Aktiviere die Bereiche: Personal, Team, Group Chat
  6. Klicke auf DistributeDownload app package
  7. In Teams: AppsManage your appsUpload a custom app → wähle die ZIP-Datei

Dies ist oft einfacher als das manuelle Bearbeiten von JSON-Manifesten.

Bot testen

Option A: Azure Web Chat (zuerst Webhook verifizieren)

  1. Im Azure Portal → deine Azure Bot-Ressource → Test in Web Chat
  2. Sende eine Nachricht – du solltest eine Antwort sehen
  3. Dies bestätigt, dass dein Webhook-Endpunkt funktioniert, bevor du Teams einrichtest

Option B: Teams (nach App-Installation)

  1. Installiere die Teams-App (Sideload oder Organisationskatalog)
  2. Finde den Bot in Teams und sende eine DM
  3. Prüfe die Gateway-Logs auf eingehende Aktivität

Einrichtung (minimaler Textmodus)

  1. Microsoft Teams-Plugin installieren

    • Von npm: openclaw plugins install @openclaw/msteams
    • Aus einem lokalen Checkout: openclaw plugins install ./extensions/msteams
  2. Bot-Registrierung

    • Erstelle einen Azure Bot (siehe oben) und notiere:
      • App-ID
      • Client-Secret (App-Passwort)
      • Tenant-ID (Single-Tenant)
  3. Teams-App-Manifest

    • Einen bot-Eintrag mit botId = <App ID> einfügen.
    • Bereiche: personal, team, groupChat.
    • supportsFiles: true (erforderlich für Dateibehandlung im persönlichen Bereich).
    • RSC-Berechtigungen hinzufügen (unten).
    • Icons erstellen: outline.png (32x32) und color.png (192x192).
    • Alle drei Dateien zusammenzippen: manifest.json, outline.png, color.png.
  4. OpenClaw konfigurieren

    {
      "msteams": {
        "enabled": true,
        "appId": "<APP_ID>",
        "appPassword": "<APP_PASSWORD>",
        "tenantId": "<TENANT_ID>",
        "webhook": { "port": 3978, "path": "/api/messages" }
      }
    }

    Du kannst auch Umgebungsvariablen anstelle von Konfigurationsschlüsseln verwenden:

    • MSTEAMS_APP_ID
    • MSTEAMS_APP_PASSWORD
    • MSTEAMS_TENANT_ID
  5. Bot-Endpunkt

    • Setze den Azure Bot Messaging-Endpunkt auf:
      • https://<host>:3978/api/messages (oder deinen gewählten Pfad/Port).
  6. Gateway starten

    • Der Teams-Kanal startet automatisch, wenn das Plugin installiert ist und eine msteams-Konfiguration mit Zugangsdaten existiert.

Historienkontext

  • channels.msteams.historyLimit steuert, wie viele kürzliche Kanal-/Gruppennachrichten in den Prompt eingebunden werden.
  • Fallback auf messages.groupChat.historyLimit. Setze 0 zum Deaktivieren (Standard 50).
  • DM-Historie kann mit channels.msteams.dmHistoryLimit (Benutzer-Turns) begrenzt werden. Pro-Benutzer-Überschreibungen: channels.msteams.dms["<user_id>"].historyLimit.

Aktuelle Teams RSC-Berechtigungen (Manifest)

Dies sind die bestehenden resourceSpecific-Berechtigungen in unserem Teams-App-Manifest. Sie gelten nur innerhalb des Teams/Chats, in dem die App installiert ist.

Für Kanäle (Team-Bereich):

  • ChannelMessage.Read.Group (Application) – alle Kanalnachrichten ohne @Mention empfangen
  • ChannelMessage.Send.Group (Application)
  • Member.Read.Group (Application)
  • Owner.Read.Group (Application)
  • ChannelSettings.Read.Group (Application)
  • TeamMember.Read.Group (Application)
  • TeamSettings.Read.Group (Application)

Für Gruppenchats:

  • ChatMessage.Read.Chat (Application) – alle Gruppenchat-Nachrichten ohne @Mention empfangen

Beispiel-Teams-Manifest (anonymisiert)

Minimales, gültiges Beispiel mit den erforderlichen Feldern. Ersetze IDs und URLs.

{
  "$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-Hinweise (Pflichtfelder)

  • bots[].botId muss mit der Azure Bot App-ID übereinstimmen.
  • webApplicationInfo.id muss mit der Azure Bot App-ID übereinstimmen.
  • bots[].scopes muss die Oberflächen enthalten, die du verwenden möchtest (personal, team, groupChat).
  • bots[].supportsFiles: true ist für die Dateibehandlung im persönlichen Bereich erforderlich.
  • authorization.permissions.resourceSpecific muss Kanal-Lese-/Sendeberechtigungen enthalten, wenn du Kanalverkehr möchtest.

Bestehende App aktualisieren

Um eine bereits installierte Teams-App zu aktualisieren (z. B. um RSC-Berechtigungen hinzuzufügen):

  1. Aktualisiere dein manifest.json mit den neuen Einstellungen
  2. Erhöhe das version-Feld (z. B. 1.0.01.1.0)
  3. Erneut zippen – das Manifest mit Icons (manifest.json, outline.png, color.png)
  4. Die neue ZIP-Datei hochladen:
    • Option A (Teams Admin Center): Teams Admin Center → Teams apps → Manage apps → finde deine App → Upload new version
    • Option B (Sideload): In Teams → Apps → Manage your apps → Upload a custom app
  5. Für Team-Kanäle: Installiere die App in jedem Team neu, damit neue Berechtigungen wirksam werden
  6. Teams vollständig beenden und neu starten (nicht nur das Fenster schließen), um zwischengespeicherte App-Metadaten zu löschen

Fähigkeiten: Nur RSC vs. Graph

Mit nur Teams RSC (App installiert, keine Graph-API-Berechtigungen)

Funktioniert:

  • Text-Inhalt von Kanalnachrichten lesen.
  • Text-Inhalt von Kanalnachrichten senden.
  • Persönliche (DM)-Dateianhänge empfangen.

Funktioniert NICHT:

  • Kanal-/Gruppen-Bild- oder Dateiinhalte (Payload enthält nur HTML-Stub).
  • Anhänge aus SharePoint/OneDrive herunterladen.
  • Nachrichtenhistorie lesen (über das Live-Webhook-Event hinaus).

Mit Teams RSC + Microsoft Graph Application-Berechtigungen

Zusätzlich:

  • Gehostete Inhalte herunterladen (in Nachrichten eingefügte Bilder).
  • Dateianhänge aus SharePoint/OneDrive herunterladen.
  • Kanal-/Chat-Nachrichtenhistorie über Graph lesen.

RSC vs. Graph API

FähigkeitRSC-BerechtigungenGraph API
EchtzeitnachrichtenJa (über Webhook)Nein (nur Polling)
Historische Nachr.NeinJa (Historie abfragen)
Setup-KomplexitätNur App-ManifestAdmin-Consent + Token-Flow erforderlich
Funktioniert offlineNein (muss laufen)Ja (jederzeit abfragen)

Fazit: RSC ist für Echtzeit-Listening; Graph API ist für historischen Zugriff. Um versäumte Nachrichten während Offline-Zeiten nachzuholen, benötigst du die Graph API mit ChannelMessage.Read.All (erfordert Admin-Consent).

Graph-fähige Medien + Historie (erforderlich für Kanäle)

Wenn du Bilder/Dateien in Kanälen benötigst oder Nachrichtenhistorie abrufen möchtest, musst du Microsoft Graph-Berechtigungen aktivieren und Admin-Consent erteilen.

  1. In Entra ID (Azure AD) App Registration, füge Microsoft Graph Application-Berechtigungen hinzu:
    • ChannelMessage.Read.All (Kanalanhänge + Historie)
    • Chat.Read.All oder ChatMessage.Read.All (Gruppenchats)
  2. Admin-Consent für den Mandanten erteilen.
  3. Die Teams-App Manifest-Version erhöhen, erneut hochladen und die App in Teams neu installieren.
  4. Teams vollständig beenden und neu starten, um zwischengespeicherte App-Metadaten zu löschen.

Zusätzliche Berechtigung für Benutzer-Erwähnungen: Benutzer-@Mentions funktionieren standardmäßig für Benutzer in der Konversation. Wenn du jedoch Benutzer dynamisch suchen und erwähnen möchtest, die nicht in der aktuellen Konversation sind, füge die User.Read.All (Application)-Berechtigung hinzu und erteile Admin-Consent.

Bekannte Einschränkungen

Webhook-Timeouts

Teams liefert Nachrichten über HTTP-Webhooks. Wenn die Verarbeitung zu lange dauert (z. B. langsame LLM-Antworten), können folgende Probleme auftreten:

  • Gateway-Timeouts
  • Teams wiederholt die Nachricht (verursacht Duplikate)
  • Verworfene Antworten

OpenClaw behandelt dies, indem es schnell zurückkehrt und Antworten proaktiv sendet, aber sehr langsame Antworten können trotzdem Probleme verursachen.

Formatierung

Teams-Markdown ist eingeschränkter als Slack oder Discord:

  • Grundlegende Formatierung funktioniert: fett, kursiv, Code, Links
  • Komplexes Markdown (Tabellen, verschachtelte Listen) wird möglicherweise nicht korrekt dargestellt
  • Adaptive Cards werden für Umfragen und beliebige Card-Sends unterstützt (siehe unten)

Konfiguration

Wichtige Einstellungen (siehe /gateway/configuration für gemeinsame Kanalmuster):

  • channels.msteams.enabled: Kanal aktivieren/deaktivieren.
  • channels.msteams.appId, channels.msteams.appPassword, channels.msteams.tenantId: Bot-Zugangsdaten.
  • channels.msteams.webhook.port (Standard 3978)
  • channels.msteams.webhook.path (Standard /api/messages)
  • channels.msteams.dmPolicy: pairing | allowlist | open | disabled (Standard: pairing)
  • channels.msteams.allowFrom: DM-Allowlist (AAD-Objekt-IDs empfohlen). Der Assistent löst Namen während des Setups zu IDs auf, wenn Graph-Zugriff verfügbar ist.
  • channels.msteams.dangerouslyAllowNameMatching: Notfall-Schalter, um veränderliches UPN-/Anzeigenamen-Matching und direktes Team-/Kanalnamen-Routing wieder zu aktivieren.
  • channels.msteams.textChunkLimit: Ausgehende Text-Chunk-Größe.
  • channels.msteams.chunkMode: length (Standard) oder newline, um an Leerzeilen (Absatzgrenzen) vor dem Längen-Chunking aufzuteilen.
  • channels.msteams.mediaAllowHosts: Allowlist für eingehende Anhang-Hosts (Standard: Microsoft/Teams-Domains).
  • channels.msteams.mediaAuthAllowHosts: Allowlist für das Anhängen von Authorization-Headern bei Medien-Retries (Standard: Graph + Bot Framework-Hosts).
  • channels.msteams.requireMention: @Mention in Kanälen/Gruppen erfordern (Standard true).
  • channels.msteams.replyStyle: thread | top-level (siehe Antwortstil).
  • channels.msteams.teams.<teamId>.replyStyle: Pro-Team-Überschreibung.
  • channels.msteams.teams.<teamId>.requireMention: Pro-Team-Überschreibung.
  • channels.msteams.teams.<teamId>.tools: Standard-Pro-Team-Tool-Richtlinienüberschreibungen (allow/deny/alsoAllow), die verwendet werden, wenn eine Kanalüberschreibung fehlt.
  • channels.msteams.teams.<teamId>.toolsBySender: Standard-Pro-Team-Pro-Absender-Tool-Richtlinienüberschreibungen ("*" Wildcard unterstützt).
  • channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle: Pro-Kanal-Überschreibung.
  • channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention: Pro-Kanal-Überschreibung.
  • channels.msteams.teams.<teamId>.channels.<conversationId>.tools: Pro-Kanal-Tool-Richtlinienüberschreibungen (allow/deny/alsoAllow).
  • channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender: Pro-Kanal-Pro-Absender-Tool-Richtlinienüberschreibungen ("*" Wildcard unterstützt).
  • toolsBySender-Schlüssel sollten explizite Präfixe verwenden: id:, e164:, username:, name: (Legacy-Schlüssel ohne Präfix werden weiterhin nur auf id: abgebildet).
  • channels.msteams.sharePointSiteId: SharePoint-Site-ID für Datei-Uploads in Gruppenchats/Kanälen (siehe Dateien in Gruppenchats senden).

Routing & Sessions

  • Session-Schlüssel folgen dem Standard-Agent-Format (siehe /concepts/session):
    • Direktnachrichten teilen die Hauptsession (agent:<agentId>:<mainKey>).
    • Kanal-/Gruppennachrichten verwenden die Konversations-ID:
      • agent:<agentId>:msteams:channel:<conversationId>
      • agent:<agentId>:msteams:group:<conversationId>

Antwortstil: Threads vs. Posts

Teams hat kürzlich zwei Kanal-UI-Stile über dasselbe zugrunde liegende Datenmodell eingeführt:

StilBeschreibungEmpfohlener replyStyle
Posts (klassisch)Nachrichten erscheinen als Karten mit Threaded-Antworten darunterthread (Standard)
Threads (Slack-ähnlich)Nachrichten fließen linear, ähnlich wie Slacktop-level

Das Problem: Die Teams-API gibt nicht preis, welchen UI-Stil ein Kanal verwendet. Wenn du den falschen replyStyle verwendest:

  • thread in einem Threads-Stil-Kanal → Antworten erscheinen unpassend verschachtelt
  • top-level in einem Posts-Stil-Kanal → Antworten erscheinen als separate Top-Level-Posts statt im Thread

Lösung: Konfiguriere replyStyle pro Kanal basierend auf der Kanaleinrichtung:

{
  "msteams": {
    "replyStyle": "thread",
    "teams": {
      "19:[email protected]": {
        "channels": {
          "19:[email protected]": {
            "replyStyle": "top-level"
          }
        }
      }
    }
  }
}

Anhänge & Bilder

Aktuelle Einschränkungen:

  • DMs: Bilder und Dateianhänge funktionieren über Teams Bot File APIs.
  • Kanäle/Gruppen: Anhänge befinden sich im M365-Speicher (SharePoint/OneDrive). Der Webhook-Payload enthält nur einen HTML-Stub, nicht die tatsächlichen Datei-Bytes. Graph-API-Berechtigungen sind erforderlich, um Kanalanhänge herunterzuladen.

Ohne Graph-Berechtigungen werden Kanalnachrichten mit Bildern als reiner Text empfangen (der Bildinhalt ist für den Bot nicht zugänglich). Standardmäßig lädt OpenClaw nur Medien von Microsoft/Teams-Hostnamen herunter. Überschreibe mit channels.msteams.mediaAllowHosts (verwende ["*"], um jeden Host zu erlauben). Authorization-Header werden nur für Hosts in channels.msteams.mediaAuthAllowHosts angehängt (Standard: Graph + Bot Framework-Hosts). Halte diese Liste strikt (vermeide Multi-Tenant-Suffixe).

Dateien in Gruppenchats senden

Bots können Dateien in DMs über den FileConsentCard-Ablauf senden (integriert). Allerdings erfordert das Senden von Dateien in Gruppenchats/Kanälen zusätzliche Einrichtung:

KontextWie Dateien gesendet werdenBenötigtes Setup
DMsFileConsentCard → Benutzer akzeptiert → Bot lädt hochFunktioniert sofort
Gruppenchats/KanäleUpload zu SharePoint → Freigabelink teilenErfordert sharePointSiteId + Graph-Berechtigungen
Bilder (jeder Kontext)Base64-kodiert inlineFunktioniert sofort

Warum Gruppenchats SharePoint benötigen

Bots haben kein persönliches OneDrive-Laufwerk (der /me/drive Graph-API-Endpunkt funktioniert nicht für Application-Identitäten). Um Dateien in Gruppenchats/Kanälen zu senden, lädt der Bot auf eine SharePoint-Site hoch und erstellt einen Freigabelink.

Einrichtung

  1. Graph-API-Berechtigungen hinzufügen in Entra ID (Azure AD) → App Registration:

    • Sites.ReadWrite.All (Application) – Dateien zu SharePoint hochladen
    • Chat.Read.All (Application) – optional, ermöglicht Pro-Benutzer-Freigabelinks
  2. Admin-Consent für den Mandanten erteilen.

  3. SharePoint-Site-ID abrufen:

    # Via Graph Explorer oder curl mit einem gültigen Token:
    curl -H "Authorization: Bearer $TOKEN" \
      "https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}"
    
    # Beispiel: für eine Site unter "contoso.sharepoint.com/sites/BotFiles"
    curl -H "Authorization: Bearer $TOKEN" \
      "https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles"
    
    # Antwort enthält: "id": "contoso.sharepoint.com,guid1,guid2"
  4. OpenClaw konfigurieren:

    {
      channels: {
        msteams: {
          // ... andere Konfiguration ...
          sharePointSiteId: "contoso.sharepoint.com,guid1,guid2",
        },
      },
    }

Freigabeverhalten

BerechtigungFreigabeverhalten
Nur Sites.ReadWrite.AllOrganisationsweiter Freigabelink (jeder in der Org kann zugreifen)
Sites.ReadWrite.All + Chat.Read.AllPro-Benutzer-Freigabelink (nur Chat-Mitglieder können zugreifen)

Pro-Benutzer-Freigabe ist sicherer, da nur die Chat-Teilnehmer auf die Datei zugreifen können. Wenn die Chat.Read.All-Berechtigung fehlt, fällt der Bot auf organisationsweite Freigabe zurück.

Fallback-Verhalten

SzenarioErgebnis
Gruppenchat + Datei + sharePointSiteId konfiguriertUpload zu SharePoint, Freigabelink senden
Gruppenchat + Datei + kein sharePointSiteIdOneDrive-Upload-Versuch (kann fehlschlagen), nur Text senden
Persönlicher Chat + DateiFileConsentCard-Ablauf (funktioniert ohne SharePoint)
Jeder Kontext + BildBase64-kodiert inline (funktioniert ohne SharePoint)

Dateispeicherort

Hochgeladene Dateien werden in einem /OpenClawShared/-Ordner in der Standard-Dokumentbibliothek der konfigurierten SharePoint-Site gespeichert.

Umfragen (Adaptive Cards)

OpenClaw sendet Teams-Umfragen als Adaptive Cards (es gibt keine native Teams-Umfrage-API).

  • CLI: openclaw message poll --channel msteams --target conversation:<id> ...
  • Stimmen werden vom Gateway in ~/.openclaw/msteams-polls.json aufgezeichnet.
  • Das Gateway muss online bleiben, um Stimmen aufzuzeichnen.
  • Umfragen veröffentlichen noch keine automatischen Ergebniszusammenfassungen (bei Bedarf die Store-Datei inspizieren).

Adaptive Cards (beliebig)

Sende beliebiges Adaptive Card-JSON an Teams-Benutzer oder -Konversationen über das message-Tool oder CLI.

Der card-Parameter akzeptiert ein Adaptive Card-JSON-Objekt. Wenn card angegeben ist, ist der Nachrichtentext optional.

Agent-Tool:

{
  "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:[email protected]" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello!"}]}'

Siehe Adaptive Cards documentation für Card-Schema und Beispiele. Für Details zum Zielformat siehe Zielformate unten.

Zielformate

MSTeams-Ziele verwenden Präfixe, um zwischen Benutzern und Konversationen zu unterscheiden:

ZieltypFormatBeispiel
Benutzer (nach ID)user:<aad-object-id>user:40a1a0ed-4ff2-4164-a219-55518990c197
Benutzer (nach Name)user:<display-name>user:John Smith (erfordert Graph API)
Gruppe/Kanalconversation:<conversation-id>conversation:19:[email protected]
Gruppe/Kanal (roh)<conversation-id>19:[email protected] (wenn @thread enthalten)

CLI-Beispiele:

# An einen Benutzer nach ID senden
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"

# An einen Benutzer nach Anzeigename senden (löst Graph-API-Suche aus)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"

# An einen Gruppenchat oder Kanal senden
openclaw message send --channel msteams --target "conversation:19:[email protected]" --message "Hello"

# Eine Adaptive Card an eine Konversation senden
openclaw message send --channel msteams --target "conversation:19:[email protected]" \
  --card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'

Agent-Tool-Beispiele:

{
  "action": "send",
  "channel": "msteams",
  "target": "user:John Smith",
  "message": "Hello!"
}
{
  "action": "send",
  "channel": "msteams",
  "target": "conversation:19:[email protected]",
  "card": {
    "type": "AdaptiveCard",
    "version": "1.5",
    "body": [{ "type": "TextBlock", "text": "Hello" }]
  }
}

Hinweis: Ohne das user:-Präfix werden Namen standardmäßig als Gruppe/Team aufgelöst. Verwende immer user:, wenn du Personen nach Anzeigename adressierst.

Proaktive Nachrichten

  • Proaktive Nachrichten sind nur nachdem ein Benutzer interagiert hat möglich, da wir zu diesem Zeitpunkt Konversationsreferenzen speichern.
  • Siehe /gateway/configuration für dmPolicy und Allowlist-Gating.

Team- und Kanal-IDs (häufiger Fehler)

Der groupId-Query-Parameter in Teams-URLs ist NICHT die Team-ID, die für die Konfiguration verwendet wird. Extrahiere IDs stattdessen aus dem URL-Pfad:

Team-URL:

https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
                                    └────────────────────────────┘
                                    Team-ID (URL-dekodieren)

Kanal-URL:

https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
                                      └─────────────────────────┘
                                      Kanal-ID (URL-dekodieren)

Für die Konfiguration:

  • Team-ID = Pfadsegment nach /team/ (URL-dekodiert, z. B. 19:[email protected])
  • Kanal-ID = Pfadsegment nach /channel/ (URL-dekodiert)
  • groupId-Query-Parameter ignorieren

Private Kanäle

Bots haben eingeschränkte Unterstützung in privaten Kanälen:

FeatureStandard-KanälePrivate Kanäle
Bot-InstallationJaEingeschränkt
Echtzeitnachrichten (Webhook)JaFunktioniert evtl. nicht
RSC-BerechtigungenJaKann anders reagieren
@MentionsJaWenn Bot erreichbar
Graph API-HistorieJaJa (mit Berechtigungen)

Workarounds, wenn private Kanäle nicht funktionieren:

  1. Standard-Kanäle für Bot-Interaktionen verwenden
  2. DMs verwenden – Benutzer können den Bot immer direkt anschreiben
  3. Graph API für historischen Zugriff verwenden (erfordert ChannelMessage.Read.All)

Fehlerbehebung

Häufige Probleme

  • Bilder werden in Kanälen nicht angezeigt: Graph-Berechtigungen oder Admin-Consent fehlen. Teams-App neu installieren und Teams vollständig beenden/neu öffnen.
  • Keine Antworten im Kanal: Erwähnungen sind standardmäßig erforderlich; setze channels.msteams.requireMention=false oder konfiguriere pro Team/Kanal.
  • Versionskonflikt (Teams zeigt noch altes Manifest): App entfernen + erneut hinzufügen und Teams vollständig beenden, um zu aktualisieren.
  • 401 Unauthorized vom Webhook: Erwartet beim manuellen Testen ohne Azure JWT – bedeutet, der Endpunkt ist erreichbar, aber die Authentifizierung ist fehlgeschlagen. Verwende Azure Web Chat zum ordnungsgemäßen Testen.

Manifest-Upload-Fehler

  • „Icon file cannot be empty”: Das Manifest referenziert Icon-Dateien mit 0 Bytes. Erstelle gültige PNG-Icons (32x32 für outline.png, 192x192 für color.png).
  • „webApplicationInfo.Id already in use”: Die App ist noch in einem anderen Team/Chat installiert. Zuerst finden und deinstallieren, oder 5-10 Minuten auf Propagierung warten.
  • „Something went wrong” beim Upload: Lade stattdessen über https://admin.teams.microsoft.com hoch, öffne die Browser-DevTools (F12) → Netzwerk-Tab und prüfe den Response-Body auf den tatsächlichen Fehler.
  • Sideload schlägt fehl: Versuche „Upload an app to your org’s app catalog” anstelle von „Upload a custom app” – dies umgeht oft Sideload-Einschränkungen.

RSC-Berechtigungen funktionieren nicht

  1. Überprüfe, ob webApplicationInfo.id exakt mit der Bot-App-ID übereinstimmt
  2. App erneut hochladen und im Team/Chat neu installieren
  3. Prüfe, ob dein Org-Admin RSC-Berechtigungen blockiert hat
  4. Bestätige, dass du den richtigen Bereich verwendest: ChannelMessage.Read.Group für Teams, ChatMessage.Read.Chat für Gruppenchats

Referenzen