103 lines
5.5 KiB
Markdown
103 lines
5.5 KiB
Markdown
# jnj_mailbox_sync v1.5.0
|
|
|
|
**Soubor:** `jnj_mailbox_sync_v1.5.py`
|
|
**Datum:** 2026-06-16
|
|
**Autor:** vladimir.buzalka
|
|
**Běží:** JNJ stroj (Outlook MAPI), Python z Thonny.
|
|
|
|
## Co to je
|
|
|
|
Synchronizace JNJ Outlooku (MAPI) → osobní schránka (přes msgreceiver) + bookkeeping
|
|
v SQLite (`C:\Users\vbuzalka\SQLITE\jnjemails.db`). Sleduje přesuny e-mailů mezi
|
|
složkami a příznak „už není ve schránce" — bez opětovného přenosu těla.
|
|
Skenované složky: **Inbox + Sent Items + Deleted Items + Archive** (vč. podsložek).
|
|
|
|
## Novinka v1.5 — provenance verze skriptu na úrovni entry
|
|
|
|
Do tabulky `messages` přidány dva sloupce (jen pro náhled, **Tower je nezpracovává** —
|
|
nejsou v mirroru do `jnj_messages`):
|
|
|
|
| Sloupec | Význam |
|
|
|---|---|
|
|
| `captured_by_version` | verze skriptu, která entry **poprvé zachytila/odeslala** (set při INSERT) |
|
|
| `last_upload_version` | verze, která naposledy **re-uploadla tělo** (set při INSERT i při re-uploadu) |
|
|
|
|
Smysl: kdykoliv se podívat (`jnjemails` SQL), kterou verzí byl daný e-mail přenesen.
|
|
**Pravidlo:** při jakékoliv změně skriptu vždy bumpni verzi (`SCRIPT_VERSION`) — jinak
|
|
tahle stopa ztrácí smysl. Migrace přes `ALTER TABLE` (staré řádky = NULL).
|
|
|
|
## Novinka v1.4 — skenování složky Archive (primární schránka)
|
|
|
|
Přidána složka **Archive** (jednoklikové archivování v Outlooku) v **primární** schránce.
|
|
Archive **není** default folder, takže se hledá podle jména `"Archive"` pod kořenem
|
|
primární schránky (`Inbox.Parent`) a přidává se do `scanned_roots` (aby se její položky
|
|
nehodnotily jako „opustilo schránku"). **Online Archive** (samostatný store) se i nadále
|
|
**neskenuje**. Řeší případy, kdy odeslaná kopie skončila v Archive (jinak chyběla domácímu
|
|
přehledu i párování dvojčat).
|
|
|
|
## Novinka v1.3 — detekce změny obsahu (re-upload změněného e-mailu)
|
|
|
|
**Problém:** e-mail **bez Message-ID** (typicky **NEODESLANÝ** Sent kvůli `SendAsDenied`,
|
|
nebo čerstvě odeslaný, kde Exchange ještě nedoplnil Message-ID) má **stabilní EntryID**.
|
|
Když do něj Outlook **po zachycení** dopíše chybu odeslání, obsah se změní, ale identita
|
|
(`entryid:<EID>`) zůstane → starý sync to vyhodnotil jako „známé, beze změny" a
|
|
aktualizovaný (chybový) e-mail už domů **nepřenesl**. Naproti tomu úspěšně odeslaný
|
|
e-mail dostane **nové EntryID + Message-ID**, takže se zachytil jako nový. Vznikla
|
|
asymetrie: failed-update se ztrácel.
|
|
|
|
**Řešení:** identita zůstává (Message-ID / `entryid:`), ale navíc se sleduje **verzní otisk**
|
|
= `PR_LAST_MODIFICATION_TIME` (`0x30080040`). U **známé položky bez Message-ID**
|
|
(`mid` začíná `entryid:`) se otisk porovná; když se posunul, e-mail se znovu uloží
|
|
(`SaveAs`) a nahraje s `overwrite=1` → server přepíše původní `.msg` na místě → Tower ho
|
|
přeparsuje → dokument v Mongu se aktualizuje (vč. těla s chybou).
|
|
|
|
- Hlídání je **levné** — druhé čtení property jen u známých no-ID položek (desítky kusů);
|
|
položky s Message-ID jsou finalizované a nesledují se.
|
|
- Re-upload běží jen v režimech, které smějí nahrávat (**capture, full-update**), a posílá se
|
|
s `folder=""` → server **nedělá** Graph re-import (žádný duplikát v Graph zrcadle).
|
|
- **Vyžaduje msgreceiver app.py ≥ v2.4** (overwrite na `/upload`). Bez něj se re-upload chová
|
|
jako starý skip (nepřepíše, ale nic nerozbije) — pořadí nasazení server → JNJ bez výpadku.
|
|
|
|
## Nové sloupce SQLite
|
|
|
|
- `messages.last_mod_time` — PR_LAST_MODIFICATION_TIME při posledním zachycení (otisk).
|
|
- `messages.content_uploads` — kolikrát se tělo nahrálo (1 = jen první zachycení).
|
|
- `runs.content_updated` — kolik e-mailů se v běhu re-uploadlo kvůli změně obsahu.
|
|
|
|
(Migrace přes stávající `ALTER TABLE` smyčku — staré `jnjemails.db` se doplní automaticky.)
|
|
|
|
## Argumenty
|
|
|
|
`--mode {capture,update-paths,full-update}` (default capture), `--days N`
|
|
(0 = celé), `--dry-run`, `--limit N`, `--no-db-upload`.
|
|
|
|
## Spouštění (JNJ stroj, plné cesty)
|
|
|
|
```
|
|
"C:\Users\vbuzalka\AppData\Local\Programs\Thonny\python.exe" "c:\Users\vbuzalka\OneDrive - JNJ\##JNJPrenos\Python\jnj_mailbox_sync_v1.5.py" --mode full-update --days 60
|
|
```
|
|
|
|
`full-update --days 60` = dorovná chybějící + **re-uploadne změněné** (chybové) Sent položky
|
|
za poslední 60 dní. To je doporučený běh pro „aktualizovat i neodeslané".
|
|
|
|
## Revert
|
|
|
|
Stará verze: `Trash/jnj_mailbox_sync_v1.4.py` (bez provenance sloupců),
|
|
`…_v1.3.py` (bez skenování Archive), `…_v1.2.py` (bez detekce změny). Server v2.4
|
|
zůstává zpětně kompatibilní (overwrite je opt-in), takže revert na JNJ straně
|
|
nevyžaduje zásah na serveru.
|
|
|
|
## Historie
|
|
|
|
- **1.0.0** — režimy capture/update-paths/full-update, sledování přesunů, updated_at.
|
|
- **1.1.0** — + Deleted Items do skenovaných složek.
|
|
- **1.2.0** — upload SQLite komprimován (lzma/xz max) + šifrován (Fernet) → `.db.xz.enc`.
|
|
- **1.3.0** — + detekce změny obsahu přes `PR_LAST_MODIFICATION_TIME`: známé no-ID
|
|
položky, které se po zachycení změnily (např. dopsaná chyba `SendAsDenied`), se znovu
|
|
nahrávají s `overwrite=1`. Nové sloupce `last_mod_time`, `content_uploads`,
|
|
`runs.content_updated`. Vyžaduje app.py ≥ v2.4.
|
|
- **1.4.0** — + skenování složky **Archive** v primární schránce (hledá se podle jména
|
|
pod kořenem schránky, ne přes default folder; Online Archive se neskenuje).
|
|
- **1.5.0** — + provenance verze na úrovni entry: sloupce `captured_by_version`
|
|
a `last_upload_version` (jen náhled, Tower nezpracovává).
|