Automatisierte Migration von Microsoft-Daten nach Notion
Diese Suite migriert Daten aus Microsoft 365 (Planner, OneNote, Teams) in strukturierte Notion-Datenbanken.
- ✅ Automatisiert: Keine manuellen Copy-Paste-Arbeiten
- ✅ Modular: Einfach neue Quellen hinzufügen
- ✅ Idempotent: Sichere Resume-Funktionalität
- ✅ Rich-Content: Bilder, Tabellen, To-Dos werden korrekt importiert
- 💬 Teams-Channels: Komplette Verläufe inkl. Replies, Reactions, @Mentions und Anhänge
# Repository klonen
git clone <repository-url>
cd ms_notion_migration
# Umgebung
python3 -m venv .venv
source .venv/bin/activate
# Dependencies
pip install -r requirements.txt
# Konfiguration
cp .env.example .env
# .env mit Ihren Zugangsdaten füllen# Microsoft
MS_CLIENT_ID=your-client-id
MS_TENANT_ID=common
MS_GRAPH_SCOPES=Notes.Read.All,Sites.Read.All
# Notion (einzelner Token)
NOTION_TOKEN=secret_your_token
NOTION_DATABASE_ID=default-database-id
# Notion (Multi-Token fuer hoeheren Durchsatz, optional)
# NOTION_TOKEN=secret_token_1,secret_token_2,secret_token_3
# Optional
ON2N_STATE=~/.onenote2notion/state.jsonModerne Weboberfläche für alle Migrations-Tools mit grafischer Benutzerführung.
# Web-Server starten
cd web
python app.py
# → http://localhost:8080Features:
- 🔐 Microsoft OAuth-Authentifizierung
- 🔍 Overview-Dashboard mit Gruppen, Notebooks, Planner-Plänen und Teams-Channels
- 📓 OneNote-Migration mit grafischer Notebook-Auswahl
- 📋 Planner-Migration mit Status-Anzeige
- 💬 Teams-Migration mit Team- und Channel-Picker
- 📊 Live-Fortschrittsanzeige während der Migration
- 🎨 Responsive UI für Desktop und Mobile
📖 Vollständige Anleitung | Quick Start
# Image bauen
docker build -t move2notion .
# Container starten (.env muss existieren)
docker run -d --name move2notion \
--env-file .env \
-p 8080:8080 \
move2notion
# → http://localhost:8080Alle Microsoft 365-Gruppen im Tenant mit ihren OneNote-Notebooks und Planner-Boards auflisten.
# Alle Gruppen mit Notebooks und Plans
python -m tools.overview.cli
# Nur Gruppen (schneller bei großen Tenants)
python -m tools.overview.cli --groups-only
# Maschinenlesbare Ausgabe
python -m tools.overview.cli --jsonFeatures:
- Teams-Gruppen mit IDs auflisten
- OneNote-Notebooks pro Gruppe entdecken
- Planner-Pläne pro Gruppe entdecken
- JSON-Export für Weiterverarbeitung
📖 Details
API-basierte Aufgabenmigration mit Personen-Mapping.
python -m tools.planner_migration.cli \
--csv "tasks.csv" \
--database "NOTION_DATABASE_ID"Features:
- CSV-Delimiter-Erkennung
- Deutsche Datumsformate
- Personen-Mapping
- Multi-Select Konvertierung
- Upsert-Modus
📖 Details
Rich-Content-Migration aus SharePoint OneNote.
python -m tools.onenote_migration.cli \
--site-url "https://tenant.sharepoint.com/sites/Site" \
--notebook "Notizbuch" \
--database-id "NOTION_DATABASE_ID" \
--resumeFeatures:
- HTML-Parsing: Überschriften, Listen, Code, Tabellen
- Text-Formatierungen: Bold, Italic, Underline, Strikethrough (HTML + CSS)
- To-Do-Erkennung: Automatische Checkbox-Erkennung
- Bild/Datei-Upload: Permanente Notion-Assets (File Upload API)
- Idempotente Synchronisation: Resume-Modus mit Checksummen
- Smart Updates: Alte Seite archivieren statt Blöcke einzeln löschen (95% schneller)
- Zeitfilter:
--since 2025-01-01für inkrementelle Imports
📖 Details
Migration von Microsoft Teams Channels mit allen Beiträgen, Replies, Reactions, @Mentions und Anhängen.
# Alle Channels eines Teams migrieren
python -m tools.teams_migration.cli \
--team-id "TEAM_ID" \
--database-id "NOTION_DATABASE_ID"
# Nur einen bestimmten Channel
python -m tools.teams_migration.cli \
--team-id "TEAM_ID" \
--channel-id "CHANNEL_ID" \
--database-id "NOTION_DATABASE_ID"Features:
- Pro Channel eine Notion-Page mit chronologischem Chat-Verlauf
- Toggle-Bloecke pro Beitrag (Header: Absender · Datum · Vorschau)
- Replies als nested Toggles unter dem Parent-Beitrag
- Reactions, @Mentions, Inline-Bilder (hostedContents werden hochgeladen)
- Datei-Anhänge als Bookmark-Blocks (kein Re-Upload)
- Rebuild-Idempotenz: Bei Wiederholung wird die Channel-Page komplett neu aufgebaut
⚠ Voraussetzung: Der eingeloggte Benutzer braucht eine M365-Lizenz mit Teams (z. B. Business Basic, E3, E5). Dedizierte Admin-Accounts ohne zugewiesene Lizenz erhalten
403 Forbidden — Failed to get license information for the user. Pay-per-API gilt nur für Application-Only-Zugriffe und ist hier nicht relevant.
📖 Details
| Feature | CLI | Web-GUI |
|---|---|---|
| Authentifizierung | Device Code Flow | OAuth Code Flow |
| Notebook-Auswahl | Manuell (ID angeben) | Grafische Auswahl |
| Fortschritt | Terminal-Output | Live-Dashboard |
| Benutzerfreundlichkeit | Fortgeschritten | Einsteigerfreundlich |
| Automatisierung | ✅ Skriptbar | ❌ Interaktiv |
| Mehrbenutzer | ❌ | ❌ (Single-User) |
Empfehlung:
- Web-GUI für gelegentliche, interaktive Migrationen
- CLI für Automatisierung und Batch-Verarbeitung
Für automatisierte Pipelines ohne User-Login:
# .env
MS_AUTH_MODE=application
MS_CLIENT_SECRET=ihr-client-secret
# Für Web-GUI zusätzlich:
ADMIN_PASSWORD=sicheres-passwortErfordert Azure AD Application Permissions mit Admin Consent.
Siehe Application Permissions für Details.
ms_notion_migration/
├── core/ # Gemeinsame Abstraktionen
│ ├── auth.py # MSAL + Notion (CLI + Web + Application)
│ ├── notion_client.py # Notion API mit Retry & Rate Limiting
│ ├── ms_graph_client.py # Microsoft Graph (OneNote, Planner, Groups)
│ ├── state_manager.py # Idempotenz via Checksummen
│ └── utils.py # Hilfsfunktionen
│
├── tools/ # Migrationstools (CLI)
│ ├── overview/ # M365-Gruppen/Notebooks/Plans Discovery
│ ├── planner_migration/ # Planner → Notion
│ └── onenote_migration/ # OneNote → Notion (HTML-Parser, Bilder)
│
├── web/ # Flask Web-GUI
│ ├── app.py # Flask-Anwendung (Port 8080)
│ ├── task_manager.py # Background-Tasks mit SSE-Fortschritt
│ ├── templates/ # HTML-Templates
│ ├── static/ # CSS & JavaScript
│ ├── README.md # Web-GUI Dokumentation
│ └── QUICKSTART.md # 5-Minuten-Setup
│
└── documentation/ # Dokumentation
├── OVERVIEW.md
├── PLANNER.md
├── ONENOTE.md
├── WEB_GUI.md
└── APPLICATION_PERMISSIONS.md
# Tests
pytest tests/
# Code-Stil
black core/ tools/
ruff check core/ tools/
# Type-Check
mypy core/ tools/- Modul in
tools/erstellen - CLI mit
argparseimplementieren - Core-Abstraktionen (
auth,notion_client,ms_graph_client) nutzen - Dokumentation in
docs/erstellen
Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) © 2025 LOUPZ GmbH & Co. KG
Sie dürfen:
- ✅ Das Material teilen und weiterverbreiten
- ✅ Das Material remixen, verändern und darauf aufbauen
Unter folgenden Bedingungen:
- Attribution — Namensnennung erforderlich
- NonCommercial — Keine kommerzielle Nutzung erlaubt (kein Wiederverkauf)
Siehe LICENSE für Details.
F: Wie funktioniert Resume?
A: Der Tool speichert Checksummen in ~/.onenote2notion/state.json. Mit --resume werden unveränderte Seiten übersprungen.
F: Was ist mit Bildern? A: Bilder werden heruntergeladen und direkt zu Notion hochgeladen.
F: Kann ich Fehler beheben und erneut ausführen?
A: Ja! Mit --resume (oder ohne, um zu überschreiben).
F: Welche Properties braucht die Notion-Datenbank?
A: Fehlende Properties werden automatisch ergänzt (ensure_database_schema). In der Web-GUI kann man auch direkt eine neue Datenbank mit passendem Schema erstellen ("+ Neue DB"). Die erwarteten Properties:
- Planner: Aufgabenname (title), LPH/Aufgabentyp (select), Status (status), Priorität (select), Fachdisziplin (multi_select), Tags (multi_select), verantwortlich (people), Fälligkeitsdatum (date)
- OneNote: Name (title), Section/Bereich (select), SectionGroup/Unterbereich (select), Notebook (rich_text), OneNotePageId (rich_text), SourceURL (url), LastEditedUtc (date)
F: Kann ich mehrere Migrationen parallel ausfuehren? A: Ja! Notion erlaubt ~3 Requests/Sekunde pro API Key. Bei parallelen Migrationen teilen sich alle Prozesse dieses Budget. Fuer hoeheren Durchsatz koennen mehrere Tokens konfiguriert werden:
# .env - Kommasepariert, Round-Robin-Verteilung
NOTION_TOKEN=secret_token_1,secret_token_2Jeder Token entspricht einer Notion-Integration. Alle Integrations muessen Zugriff auf die Ziel-Datenbank haben (in Notion: Datenbank oeffnen → "..." → "Add connections"). 2 Tokens = ~6 req/s, 3 Tokens = ~9 req/s.
Für Details: siehe documentation/ oder Issue öffnen.