Zum Inhalt springen
covey

Microsoft 365

Ein Runbook für das Plugin m365. Der Agent bekommt einen eigenen Microsoft-365-Benutzer und arbeitet darin wie ein Kollege: Er liest und beantwortet seine Mail, führt seinen Kalender und findet, bearbeitet und legt Dokumente in OneDrive und SharePoint ab. Alles läuft über die Microsoft Graph API mit einer App-Registrierung in Entra ID.

Kurzfassung: ein lizenzierter Benutzer für den Agenten, eine App-Registrierung mit Anwendungsberechtigungen, ein Exchange-Scope, der die App in dieses eine Postfach einzäunt, das System in covey aktiviert, zwei Secrets, eine Zeile in ACCESS.md, drei Egress-Hosts. Abschnitt 2 geht jeden Klick durch.

Wie es sich von den Nachbarn unterscheidet:

m365 email sharepoint
Mail Exchange Online über Graph jeder IMAP/SMTP-Server, Passwort-Anmeldung —
Kalender ja — —
Dateien eigenes OneDrive + jede Site, die die App erreichen darf — eine Bibliothek hinter einem Freigabelink

Exchange Online nimmt über IMAP keine Passwort-Anmeldung mehr an; für ein Microsoft-365-Postfach ist deshalb m365 der Weg, nicht email.


1. Was der Agent kann

  • Mail — einen Ordner auflisten (nur Ungelesene oder nach Suchwörtern), eine Nachricht als Text mit ihrer Anhangsliste lesen, einen Anhang in die Sandbox legen, antworten oder allen antworten (mit Dateien aus der Sandbox), eine neue Mail senden, einen Entwurf hinterlegen, den ein Mensch prüft und abschickt, eine Mail in einen Ordner verschieben, als gelesen markieren.
  • Kalender — den Kalender zwischen zwei Zeitpunkten lesen (Serien aufgelöst), einen Termin mit Teilnehmenden oder als Teams-Besprechung anlegen, eine Einladung annehmen / ablehnen / mit Vorbehalt annehmen, einen eigenen Termin absagen, die Frei/Gebucht-Zeiten von Kolleginnen und Kollegen abfragen.
  • Dateien — SharePoint-Sites finden, die Bibliotheken einer Site auflisten, eine Bibliothek oder das eigene OneDrive (drive_id me) auflisten und durchsuchen, eine Textdatei lesen, eine Datei in die Sandbox laden, eine aus ihr hochladen, eine Textdatei schreiben, Ordner anlegen. Eine Löschaktion gibt es absichtlich nicht.
  • Links — open_link nimmt einen SharePoint-, OneDrive- oder Teams-Dateien- Link (einen Freigabelink oder die normale Adresse einer Datei oder eines Ordners) und antwortet mit Laufwerk und Pfad, mit denen die Dateiaktionen arbeiten. „Bitte das Protokoll hier ergänzen: “ ist ein vollständiger Auftrag.
  • Office-Dokumente — das Plugin zerlegt sie nicht. Der Agent lädt eine .docx, .xlsx oder .pptx herunter, bearbeitet sie in der Sandbox mit python3 (docx, openpyxl, pptx liegen im Basis-Arbeitsplatz) und lädt sie auf denselben Pfad zurück.

Mail senden und Leute einladen erreicht echte Menschen. Die Guard-Rail-Subjekte sind eines je Aktion (m365:send_mail, m365:create_event, …); eine Organisation, die einen Menschen vorher draufschauen lassen will, setzt require_approval genau auf diese und lässt das Lesen frei.


2. Einrichtung

Die Arbeit von zwei Rollen, in dieser Reihenfolge: zuerst ein Microsoft-365- Admin (Benutzer, App, Exchange-Scope, SharePoint), dann ein covey-Admin (aktivieren, Secrets, Egress, einstellen). Rechnet mit einer halben Stunde. Haltet eine Notiz offen für fünf Werte, die unterwegs anfallen:

Wert Aus Gebraucht in
Adresse des Agenten 2.1 m365_url, Exchange-Scope
Verzeichnis-ID (Mandant) 2.2 m365_token
Anwendungs-ID (Client) 2.2 m365_token, Exchange, SharePoint
Wert des Clientgeheimnisses 2.2 m365_token
Objekt-ID der Unternehmensanwendung 2.3 New-ServicePrincipal

2.1 Ein Benutzer für den Agenten (Microsoft 365 Admin Center)

  1. admin.microsoft.com → Benutzer → Aktive Benutzer → Benutzer hinzufügen.
  2. Nach seiner Aufgabe benennen (z. B. Office Agent), Benutzername z. B. office@contoso.com. Eine Lizenz mit Exchange Online und OneDrive zuweisen (Microsoft 365 Business Basic genügt).
  3. Das Passwort benutzt covey nie — ein langes zufälliges setzen und nicht weitergeben. Der Agent meldet sich als App an, nicht als dieser Benutzer.
  4. Einmal als dieser Benutzer bei outlook.office.com anmelden (oder das Postfach als Admin öffnen) und die Ordner anlegen, die das Playbook nennt, z. B. Erledigt. Mailordner legt das Plugin nicht an.

Ein freigegebenes Postfach reicht für Mail und Kalender, hat aber kein OneDrive; soll der Agent eigene Dateien haben, einen lizenzierten Benutzer nehmen.

2.2 Die App-Registrierung (Entra ID)

  1. entra.microsoft.com → Anwendungen → App-Registrierungen → Neue Registrierung. Name: z. B. covey office agent. Unterstützte Kontotypen: nur Konten in diesem Organisationsverzeichnis. Umleitungs-URI: leer lassen. Registrieren.

  2. Auf der Übersichtsseite Anwendungs-ID (Client) und Verzeichnis-ID (Mandant) kopieren.

  3. API-Berechtigungen → Berechtigung hinzufügen → Microsoft Graph → Anwendungsberechtigungen (nicht Delegierte). Hinzufügen:

    Berechtigung Wofür
    Mail.ReadWrite, Mail.Send das Postfach
    Calendars.ReadWrite der Kalender
    Files.ReadWrite.All OneDrive und Dokumentbibliotheken
    Sites.ReadWrite.All oder Sites.Selected Sites finden — siehe 2.4

    Dann Administratorzustimmung für erteilen. Jede Zeile muss grün Gewährt zeigen; eine Berechtigung ohne Zustimmung bewirkt nichts.

  4. Zertifikate & Geheimnisse → Geheime Clientschlüssel → Neuer geheimer Clientschlüssel. Beschreibung covey, Ablauf so lang wie eure Richtlinie erlaubt (höchstens 24 Monate). Die Spalte Wert sofort kopieren — sie wird nur einmal angezeigt. Die Geheimnis-ID daneben ist nicht das Geheimnis; mit ihr kommt invalid_client (AADSTS7000215).

  5. Das Ablaufdatum in einen Kalender eintragen. Danach scheitert jede Aktion mit invalid_client; auf derselben Seite erneuern und m365_token in covey ersetzen.

2.3 Die App in das Postfach des Agenten einzäunen (Exchange-Online-PowerShell)

Anwendungsberechtigungen gelten mandantenweit: Nach 2.2 könnte die App aus jedem Postfach der Organisation lesen und senden. RBAC for Applications in Exchange begrenzt Mail und Kalender auf den einen Benutzer. Diesen Schritt nicht auslassen.

  1. Die Objekt-ID der Unternehmensanwendung holen: Entra ID → Anwendungen → Unternehmensanwendungen → nach dem Namen der App suchen → Objekt-ID. Das ist eine andere ID als die auf der Seite der App-Registrierung; mit der Objekt-ID der Registrierung scheitert New-ServicePrincipal oder bindet das falsche Objekt.

  2. PowerShell (Windows PowerShell 5.1 oder PowerShell 7) als Exchange-Admin öffnen:

    Install-Module ExchangeOnlineManagement -Scope CurrentUser   # einmalig
    Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
    
  3. Scope anlegen, die App bei Exchange bekannt machen und ihr die drei Rollen innerhalb des Scopes geben:

    New-ManagementScope -Name "covey-office" `
      -RecipientRestrictionFilter "PrimarySmtpAddress -eq 'office@contoso.com'"
    
    New-ServicePrincipal -AppId <client-id> -ObjectId <objekt-id-der-unternehmensanwendung> `
      -DisplayName "covey office agent"
    
    New-ManagementRoleAssignment -App <client-id> -Role "Application Mail.ReadWrite" `
      -CustomResourceScope "covey-office"
    New-ManagementRoleAssignment -App <client-id> -Role "Application Mail.Send" `
      -CustomResourceScope "covey-office"
    New-ManagementRoleAssignment -App <client-id> -Role "Application Calendars.ReadWrite" `
      -CustomResourceScope "covey-office"
    
  4. Zurück in Entra ID → die App-Registrierung → API-Berechtigungen: dort Mail.ReadWrite, Mail.Send und Calendars.ReadWrite entfernen. Rechte aus Entra ID und aus Exchange addieren sich — solange die mandantenweiten stehen, begrenzt der Scope nichts.

  5. Prüfen:

    Test-ServicePrincipalAuthorization -Identity <client-id> -Resource office@contoso.com
    Test-ServicePrincipalAuthorization -Identity <client-id> -Resource jemand.anderes@contoso.com
    

    Das erste antwortet für die drei Rollen InScope : True, das zweite False. Bis Exchange die Änderung anwendet, können bis zu zwei Stunden vergehen; ein 403 direkt nach diesem Schritt ist meist diese Verzögerung.

Das Plugin selbst spricht nur das Postfach aus m365_url an. Das ist eine Konvention des Codes, keine Grenze: Die Grenze ist dieser Schritt.

2.4 SharePoint: welche Sites der Agent erreicht

Zuerst entscheiden, wo der Agent arbeiten wird, und vor allem, wohin die Links zeigen werden, die man ihm schickt. Der Agent öffnet einen Link als App, nicht als sein Benutzer: Eine Datei mit office@contoso.com zu teilen, lässt die App nicht hinein.

Wahl Wirkung
Sites.ReadWrite.All jede Site und jeder Link im Mandanten öffnet sich. Am einfachsten; die App erreicht den ganzen SharePoint-Bestand
Sites.Selected nur Sites, die der App einzeln freigegeben sind. Ein Link in eine andere Site endet mit einem 403, der das sagt

Mit Sites.Selected jede Site freigeben. Beide Wege unten funktionieren; dafür braucht es einen SharePoint-Admin.

PnP PowerShell (am kürzesten):

Install-Module PnP.PowerShell -Scope CurrentUser   # einmalig
Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/Team -Interactive -ClientId <eure PnP-Admin-App>
Grant-PnPAzureADAppSitePermission -AppId <client-id> -DisplayName "covey office agent" `
  -Site https://contoso.sharepoint.com/sites/Team -Permissions Write

Graph Explorer (aka.ms/ge, angemeldet als Admin, der dort Sites.FullControl.All zugestimmt hat):

  1. Site-ID: GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/Team → id kopieren (drei Teile, durch Kommas getrennt).

  2. Freigeben:

    POST https://graph.microsoft.com/v1.0/sites/{site-id}/permissions
    { "roles": ["write"],
      "grantedToIdentities": [{ "application": { "id": "<client-id>", "displayName": "covey office agent" } }] }
    

Je Site wiederholen. list_sites zeigt in covey dann genau diese Sites. Das eigene OneDrive des Agenten braucht keine Freigabe — Files.ReadWrite.All deckt es ab.

2.5 In covey

  1. Das System für die Organisation aktivieren: Zielsysteme → Microsoft 365 → Aktivieren. Ein einkompiliertes Plugin ist pro Organisation bis dahin aus, und die Zeile in der ACCESS.md eines Agenten schaltet es nicht ein.

  2. Die Secrets beim Agenten hinterlegen: Agent → Einstellungen → Secrets:

    m365_url   = office@contoso.com
    m365_token = <tenant-id>:<client-id>:<wert-des-clientgeheimnisses>
    

    Für nationale Clouds nimmt m365_url die Endpunkte hinter der Adresse: office@contoso.us graph=https://graph.microsoft.us login=https://login.microsoftonline.us.

  3. Zugriff — in der ACCESS.md des Agenten:

    - system: m365   scope: read,write
    
  4. Egress — Egress → Templates: Microsoft 365 aus dem Katalog übernehmen und auf der Agenten-Seite im Reiter Egress ankreuzen. Oder die Hosts als eigene des Agenten eintragen:

    Host Warum
    graph.microsoft.com die API
    login.microsoftonline.com das Token
    *.sharepoint.com Datei-Downloads: /content leitet auf den SharePoint-Host des Mandanten weiter

2.6 Testen

  1. Verbindungstest (Zielsysteme → Microsoft 365 → Verbindung testen): Er liest den Posteingang und antwortet mailbox office@contoso.com reachable: 3 unread of 41 in the inbox.
  2. Den Agenten einstellen und seiner Adresse aus dem Postfach eines Kollegen einen kleinen Auftrag schicken. Innerhalb des Herzschlag-Intervalls startet ein Lauf; seine Aufzeichnung zeigt list_mail, get_mail und die Antwort, die er geschickt hat.
  3. In einer zweiten Mail einen SharePoint-Link schicken („bitte in diesem Dokument eine Zeile ergänzen: “), um open_link und die Site-Freigaben zu prüfen.

2.7 Wenn etwas scheitert

Symptom Ursache Abhilfe
entra id token: HTTP 401 … invalid_client / AADSTS7000215 falsches Geheimnis (die Geheimnis-ID kopiert) oder abgelaufen neues Clientgeheimnis, dessen Wert kopieren, m365_token ersetzen (2.2)
AADSTS700016 Client-ID gibt es in diesem Mandanten nicht Reihenfolge und Werte in tenant-id:client-id prüfen
HTTP 403 … ErrorAccessDenied bei Mail oder Kalender Rollenzuweisung fehlt, Scope deckt die Adresse nicht ab, oder die Änderung greift noch nicht Test-ServicePrincipalAuthorization (2.3); nach einer Änderung bis zu zwei Stunden warten
HTTP 403 bei jedem Postfach, auch dem des Agenten Administratorzustimmung fehlt, oder die Graph-Mailrechte wurden entfernt, bevor die Exchange-Rollen da waren 2.2 Schritt 3, 2.3 Schritt 3
HTTP 403 von open_link oder list_drives Sites.Selected ohne Freigabe für diese Site Site freigeben (2.4)
list_sites leer Sites.Selected, noch keine Site freigegeben mindestens eine Site freigeben (2.4)
Auflisten geht, download_file endet mit Forbidden Egress sperrt den SharePoint-Download-Host *.sharepoint.com (2.5 Schritt 4); das Egress-Protokoll zeigt den abgelehnten CONNECT
m365 is not activated, oder im Prompt des Agenten stehen keine Microsoft-365-Aktionen System für die Organisation nicht aktiviert 2.5 Schritt 1
no m365_token stored for this agent Secrets angelegt, aber nicht bei diesem Agenten 2.5 Schritt 2

3. Eingang

Einen Webhook gibt es nicht: Graph-Änderungsbenachrichtigungen brauchen ein öffentlich validiertes Abonnement, das alle paar Tage erneuert werden muss. Der Eingang ist ein Herzschlag mit einer Vorprüfung, die einen Aufruf kostet:

- alle: 10m nur-wenn: m365 titel: Das Postfach betreuen
  aufgabe: Lies die ungelesene Mail (list_mail unread:true) und bearbeite sie nach dem Playbook.

nur-wenn: m365 fragt nach der ungelesenen Mail im Posteingang (nur-wenn: m365:<ordner> für einen anderen Ordner). Es meldet einen Eintrag je Nachricht (mail:<id>@<zuletzt geändert>): Es feuert, wenn eine Mail ankommt oder sich ändert, bleibt still, solange der Posteingang stillsteht, und ein Ablauf mit only_if: m365 führt einen Vorgang je Mail. Die eigenen mark_read, move_mail und reply_mail des Agenten sind als signaturverändernd bekannt und wecken ihn nicht erneut.

Ids sind die unveränderlichen Ids von Graph: Eine Mail behält ihre Id, wenn sie verschoben wird; eine Notiz oder ein Vorgang, der sie nennt, bleibt richtig.


4. Grenzen

Was Grenze
Anhänge einer ausgehenden Mail 3 MB zusammen (Graph lehnt eine Anfrage über 4 MB ab) — eine größere Datei geht mit upload_file ins OneDrive, und die Mail trägt ihren Link
Ein Anhang, der in die Sandbox geladen wird COVEY_M365_ATTACHMENT_MAX_MB, Standard 25
Ein Upload COVEY_M365_UPLOAD_MAX_MB, Standard und Höchstwert 250 (einfacher Upload)
read_file Text bis 1 MB; alles andere über download_file
list_mail 50 je Aufruf