Files
janssen/EmailsImport/inbox_full_sync_v1.1.md

177 lines
6.2 KiB
Markdown

# inbox_full_sync_v1.1
**Název:** inbox_full_sync_v1.1.py
**Verze:** 1.1.0
**Datum:** 2026-06-08
**Autor:** vladimir.buzalka
---
## Účel
Jednorázový skript pro úplný přenos **Inboxu i Sent Items** z JNJ Outlooku (MAPI) do osobní schránky `vladimir.buzalka@buzalka.cz` přes Microsoft Graph API.
Spouštět ručně jako záchranná síť nebo iniciální sync. Bezpečné opakovat — duplicity se automaticky přeskočí.
---
## Co dělá
1. Připojí se k Outlooku přes MAPI (`win32com`)
2. Projde rekurzivně obě výchozí složky včetně všech podsložek:
- **Inbox** — `GetDefaultFolder(6)`
- **Sent Items** — `GetDefaultFolder(5)`
3. Pro každý email zkontroluje SQLite DB — pokud už je přenesen, přeskočí ho
4. Nový email uloží jako `.msg` do temp složky, **zašifruje** (Fernet/AES) a odešle jako `.emsg` na `msgs.buzalka.cz/upload`
5. Server (`app.py`) dešifruje, parsuje `.msg`, importuje do Graph API a vrátí `graph_id`
6. Záznam se uloží do DB (`messages`, `log`)
7. Každých 100 přenesených emailů + na konci uploaduje DB na server
Složky k synchronizaci jsou v konstantě `SYNC_FOLDERS = [(6, "Inbox"), (5, "Sent Items")]`.
**Online Archive se nepřenáší**`GetDefaultFolder(5/6)` vrátí pouze primární schránku.
---
## Šifrování (Zscaler bypass)
JNJ síť používá **Zscaler DLP** — blokuje upload souborů s medicínským obsahem (ECG reporty, klinická data) na externí URL.
Řešení: soubor se před odesláním zašifruje pomocí **Fernet** (AES-128 CBC + HMAC). Zscaler vidí pouze šifrovaný bináč a nerozpozná obsah.
- Šifrovací klíč se odvozuje z `TOKEN` přes SHA-256 — žádná extra konstanta, obě strany derivují klíč samostatně
- Soubor se odesílá s příponou `.emsg` místo `.msg`
- Server (app.py v1.6+) automaticky detekuje `.emsg`, dešifruje a dále zpracuje standardně
---
## Konfigurace
Konstanty jsou přímo v kódu:
| Konstanta | Hodnota |
|---|---|
| `TOKEN` | Bearer token pro msgs.buzalka.cz (slouží i jako základ šifrovacího klíče) |
| `UPLOAD_URL` | `https://msgs.buzalka.cz/upload` |
| `DB_UPLOAD_URL` | `https://msgs.buzalka.cz/upload-db` |
| `DB_PATH` | `C:\Users\vbuzalka\SQLITE\jnjemails.db` |
| `LOG_PATH` | `C:\Users\vbuzalka\SQLITE\inbox_full_sync_errors.log` |
| `SYNC_FOLDERS` | `[(6, "Inbox"), (5, "Sent Items")]` |
---
## Závislosti
- Python 3.10+, Windows
- Outlook musí být spuštěn
- `pywin32`, `requests`, `cryptography`
- Server `msgs.buzalka.cz` musí běžet (app.py v1.6+)
---
## SQLite DB (`jnjemails.db`)
### Tabulka `messages`
Jeden záznam na každý přenesený email.
| Sloupec | Popis |
|---|---|
| `message_id` | Internet Message-ID (nebo `entryid:...` jako fallback) |
| `entry_id` | Outlook EntryID — pro zpětné dohledání v MAPI |
| `graph_id` | ID zprávy v Graph API — pro sync operace |
| `is_read` | Stav přečtení při přenosu (0/1) |
| `jnj_folder` | Složka v JNJ při přenosu (Inbox i Sent Items podstrom) |
| `source` | Vždy `inbox_full_sync` |
### Tabulka `runs`
Jeden záznam na každý běh skriptu.
| Sloupec | Popis |
|---|---|
| `script` | `inbox_full_sync` |
| `version` | verze skriptu |
| `started_at` / `finished_at` | časy běhu |
| `transferred` | počet nově přenesených emailů |
| `skipped` | počet přeskočených (již v DB) |
| `errors` | počet chyb |
### Tabulka `log`
Flat event log — každý console výstup i interní událost jako řádek.
| Sloupec | Popis |
|---|---|
| `run_id` | FK na `runs.id` |
| `level` | `INFO` / `ERROR` |
| `event` | typ události (viz níže) |
| `subject` | předmět emailu (pokud relevantní) |
| `folder` | složka (pokud relevantní) |
| `graph_id` | Graph ID (pokud relevantní) |
| `detail` | pro `upload_saved`: `size=XKB`; pro `upload_error`: `error=... \| size=XKB \| body=... \| sender=... \| received=... \| entry_id=... \| message_id=...` |
#### Události (`log.event`)
| Event | Popis |
|---|---|
| `run_start` | start skriptu |
| `mailbox` | název schránky + kořenová složka (Inbox / Sent Items) |
| `folder_start` | vstup do složky (detail = počet položek) |
| `folder_done` | konec složky (detail = přeneseno/skip) |
| `upload_saved` | nový email úspěšně přenesen (detail = size=XKB) |
| `upload_exists` | email již v DB, přeskočen |
| `upload_error` | chyba při uploadu — detail obsahuje sender, received, entry_id, message_id pro dohledání v Outlooku |
| `progress` | každých 100 přenesených emailů |
| `db_upload` | úspěšný upload DB na server |
| `db_upload_error` | chyba uploadu DB |
| `run_done` | konec skriptu (detail = souhrn) |
---
## Užitečné dotazy
**Poslední běh — kompletní log:**
```sql
SELECT r.script, r.version, r.started_at,
l.level, l.event, l.subject, l.folder, l.detail, l.created_at
FROM log l JOIN runs r ON r.id = l.run_id
WHERE l.run_id = (SELECT MAX(id) FROM runs)
ORDER BY l.created_at
```
**Přehled všech běhů:**
```sql
SELECT id, script, version, started_at, finished_at,
transferred, skipped, errors
FROM runs ORDER BY started_at DESC
```
**Chyby z posledního běhu:**
```sql
SELECT l.event, l.subject, l.folder, l.detail, l.created_at
FROM log l
WHERE l.run_id = (SELECT MAX(id) FROM runs)
AND l.level = 'ERROR'
ORDER BY l.created_at
```
---
## Návaznost
- Sdílí DB s `janssenpc_email_send_new_v1.5.py` — záznamy jsou kompatibilní
- Emaily přenesené tímto skriptem mají `graph_id` a jsou od té chvíle hlídány sync průchodem v1.5
- Server endpoint: `msgs.buzalka.cz/upload` musí vracet `graph_id` (app.py v1.6+)
- nginx `client_max_body_size` nastaven na **200M** (SWAG `msgreceiver.subdomain.conf`)
---
## Historie verzí
| Verze | Datum | Změna |
|---|---|---|
| 1.0.0 | 2026-06-01 | Základní funkce: Inbox full scan, dedup přes DB, entry_id/graph_id/is_read |
| 1.0.1 | 2026-06-01 | DB upload každých 100 emailů + finální upload |
| 1.0.2 | 2026-06-01 | SQLite tabulky runs + log |
| 1.0.3 | 2026-06-01 | Kompletní konzolový výstup zrcadlen do log tabulky, skipped counter |
| 1.0.4 | 2026-06-01 | Šifrování Fernet (.emsg) pro bypass Zscaler DLP; rozšířený error detail |
| 1.1.0 | 2026-06-08 | Synchronizace i složky **Sent Items** (`GetDefaultFolder(5)`) vedle Inboxu |