No description
Find a file
2026-06-10 20:07:46 +02:00
.env.example first commit 2026-06-09 15:09:34 +02:00
.gitignore first commit 2026-06-09 15:09:34 +02:00
config.py first commit 2026-06-09 15:09:34 +02:00
graph_client.py Speichere Informationen über den User 2026-06-09 18:08:47 +02:00
README.md first commit 2026-06-09 15:09:34 +02:00
requirements.txt first commit 2026-06-09 15:09:34 +02:00
sync.py first commit 2026-06-09 15:09:34 +02:00
sync_org_contacts.py first commit 2026-06-09 15:09:34 +02:00
sync_user_data.py Select für die User-Fields setzen 2026-06-10 20:07:46 +02:00

Microsoft Graph API M365 Sync

Synchronisiert M365-Daten lokal als JSON-Dateien. Source of Truth ist Microsoft 365.

Ressource Graph-Endpunkt Lokaler Pfad
Organizational Contacts /contacts/delta objects/global/{id}.json
Persönliche Kontakte (alle User) /users/{uid}/contacts/delta objects/user/{uid}/contacts/{id}.json
Kalendereinträge (alle User) /users/{uid}/events/delta objects/user/{uid}/calendar/{id}.json
  • Erster Lauf: vollständiger Sync
  • Folgeläufe: inkrementell via Graph Delta API
  • Gelöschte Einträge werden lokal entfernt
  • State wird nach jedem User gespeichert (resilient bei Abbruch)

Voraussetzungen

  • Python 3.10+
  • Azure App Registration mit folgenden Application Permissions (Admin Consent erforderlich):
Permission Zweck
OrgContact.Read.All Organizational Contacts lesen
User.Read.All Alle Tenant-User enumerieren
Contacts.Read Persönliche Kontakte aller User
Calendars.Read Kalender aller User

Einrichtung

1. Azure App Registration

  1. Azure PortalAzure Active DirectoryApp registrationsNew registration
  2. Name vergeben, Account type: Accounts in this organizational directory only
  3. Certificates & secretsNew client secret → Secret kopieren
  4. API permissionsAdd a permissionMicrosoft GraphApplication permissions
    → Die vier Permissions oben hinzufügen
  5. Grant admin consent for [Tenant] klicken

2. Projekt einrichten

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env

.env ausfüllen:

TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
CLIENT_SECRET=your-client-secret-here

Verwendung

.venv/bin/python sync.py

Der erste Lauf führt einen vollständigen Sync durch. Jeder weitere Lauf synchronisiert nur Änderungen seit dem letzten Lauf.

Für automatische Ausführung per Cron:

# Täglich um 03:00 Uhr
0 3 * * * /pfad/zum/projekt/.venv/bin/python /pfad/zum/projekt/sync.py

Dateistruktur

.
├── sync.py                  # Einstiegspunkt und Orchestrierung
├── sync_org_contacts.py     # Sync: Organizational Contacts
├── sync_user_data.py        # Sync: User-Kontakte und Kalender
├── graph_client.py          # Graph API Auth + Pagination
├── config.py                # Konfiguration (lädt .env)
├── requirements.txt
├── .env                     # Credentials (nicht committen!)
├── .env.example
├── objects/
│   ├── global/
│   │   └── {id}.json        # Organizational Contacts
│   └── user/
│       └── {uid}/
│           ├── contacts/
│           │   └── {id}.json
│           └── calendar/
│               └── {id}.json
└── state/
    └── sync_state.json      # Delta-Links aller Ressourcen

State-Datei

{
  "org_contacts": {
    "delta_link": "https://graph.microsoft.com/v1.0/contacts/delta?$deltatoken=..."
  },
  "users": {
    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx": {
      "contacts_delta_link": "https://...",
      "calendar_delta_link": "https://..."
    }
  }
}

Hinweise

  • User ohne Exchange-Mailbox (keine Lizenz, Service Accounts) werden automatisch übersprungen (HTTP 403/404).
  • Die State-Datei wird nach jedem User gespeichert. Ein Abbruch führt beim nächsten Lauf nur zu einem Teilsync der verbleibenden User.
  • Alte State-Dateien im v1-Format ({"delta_link": "..."}) werden automatisch migriert.