323 lines
8.2 KiB
Markdown
323 lines
8.2 KiB
Markdown
# parse_emails_v1.0
|
||
|
||
**Název:** parse_emails_v1.0.py
|
||
**Verze:** 1.0
|
||
**Datum:** 2026-06-01
|
||
**Autor:** vladimir.buzalka
|
||
|
||
---
|
||
|
||
## Účel
|
||
|
||
Jednorázový import všech `.msg` souborů do MongoDB. Z každého souboru extrahuje **všechny dostupné vlastnosti** — podobně jako EXIF u fotek.
|
||
|
||
- **DB:** `emaily`
|
||
- **Kolekce:** `vbuzalka@its.jnj.com`
|
||
- `_id` = Internet Message-ID (nebo `filename:<stem>` jako fallback)
|
||
- Bezpečné přerušit a opakovat — upsert podle `_id`
|
||
|
||
---
|
||
|
||
## Zdroje dat
|
||
|
||
Výhradně `.msg` soubory — žádná závislost na SQLite ani jiné DB.
|
||
|
||
| Z každého .msg se extrahuje |
|
||
|---|
|
||
| Předmět, normalized subject |
|
||
| Odesílatel (email, jméno, SMTP adresa) |
|
||
| Příjemci To/CC/BCC — strukturovaně `[{type, email, name}]` |
|
||
| Čas doručení a odeslání (UTC) |
|
||
| Tělo plaintext + HTML (max 2 MB) |
|
||
| Přílohy — metadata: jméno, velikost, MIME typ, inline flag |
|
||
| Internet headers — X-Originating-IP, Received, DKIM, X-Mailer, ... |
|
||
| MAPI: důležitost, citlivost, příznak, konverzační vlákno, kategorie |
|
||
| In-Reply-To, References — pro rekonstrukci vlákna |
|
||
| Všechny raw MAPI properties jako `{0xXXXX: value}` |
|
||
|
||
---
|
||
|
||
## Konfigurace
|
||
|
||
Konstanty přímo v kódu:
|
||
|
||
| Konstanta | Hodnota |
|
||
|---|---|
|
||
| `MSGS_DIR` | `\\tower\JNJEMAILS` |
|
||
| `MONGO_URI` | `mongodb://192.168.1.76:27017` |
|
||
| `MONGO_DB` | `emaily` |
|
||
| `MONGO_COL` | `vbuzalka@its.jnj.com` |
|
||
| `BATCH_SIZE` | 200 dokumentů na jeden bulk_write |
|
||
| `LOG_FILE` | `parse_emails_errors.log` (vedle skriptu) |
|
||
|
||
---
|
||
|
||
## Spouštění
|
||
|
||
**Venv:** `U:\PythonProject\Janssen\.venv\Scripts\python.exe`
|
||
|
||
**1. spuštění — kompletní import:**
|
||
```cmd
|
||
"U:\PythonProject\Janssen\.venv\Scripts\python.exe" "U:\PythonProject\Janssen\EmailsImport\parse_emails_v1.0.py"
|
||
```
|
||
|
||
**Pokračování po přerušení (druhý den):**
|
||
```cmd
|
||
"U:\PythonProject\Janssen\.venv\Scripts\python.exe" "U:\PythonProject\Janssen\EmailsImport\parse_emails_v1.0.py" --skip-existing
|
||
```
|
||
|
||
**Test na malém vzorku:**
|
||
```cmd
|
||
"U:\PythonProject\Janssen\.venv\Scripts\python.exe" "U:\PythonProject\Janssen\EmailsImport\parse_emails_v1.0.py" --limit 50 --no-indexes
|
||
```
|
||
|
||
### Všechny parametry
|
||
|
||
| Parametr | Popis |
|
||
|---|---|
|
||
| `--skip-existing` | Načte seznam hotových souborů z MongoDB a přeskočí je. Použij pro pokračování po přerušení. |
|
||
| `--limit N` | Zpracuje jen prvních N souborů. Vhodné pro test. |
|
||
| `--no-indexes` | Nevytváří indexy na konci. Použij pokud je přerušíš uprostřed — indexy vytvoř ručně až je vše hotové. |
|
||
|
||
---
|
||
|
||
## Průběh na konzoli
|
||
|
||
Každý email na jednom řádku:
|
||
```
|
||
1/69371 OK RE: Protocol deviation CZ10022 jan.novak@its.jnj.com
|
||
2/69371 OK UCO3001: Draft FUL pro DD5-CZ10022 monitor@4gclinical.com
|
||
3/69371 ERR ? ?
|
||
```
|
||
|
||
Každých 500 emailů oddělovač s průběhem:
|
||
```
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
Průběh: ok=498 err=2 0.4 msg/s ETA 47h12m
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
```
|
||
|
||
Na konci souhrn:
|
||
```
|
||
====================================================
|
||
Vysledek: ok=69300 | skip=0 | err=71
|
||
Celkovy cas: 47h 23m 10s
|
||
Dokumentu v kolekci: 69300
|
||
```
|
||
|
||
---
|
||
|
||
## Struktura dokumentu v MongoDB
|
||
|
||
```json
|
||
{
|
||
"_id": "<message-id@domain>",
|
||
"filename": "7A3F...0000.msg",
|
||
|
||
"subject": "RE: Protocol deviation CZ10022",
|
||
"normalized_subject": "Protocol deviation CZ10022",
|
||
"importance": 1,
|
||
"sensitivity": 0,
|
||
"flag_status": 0,
|
||
"read_receipt_requested": false,
|
||
"delivery_receipt_requested": false,
|
||
"has_attachments": true,
|
||
"attachment_count": 1,
|
||
"message_size_bytes": 284512,
|
||
|
||
"conversation_topic": "Protocol deviation CZ10022",
|
||
"conversation_index": "AcqX...",
|
||
"in_reply_to": "<prev-id@domain>",
|
||
"internet_references": ["<ref1@domain>", "<ref2@domain>"],
|
||
"categories": ["UCO3001"],
|
||
|
||
"received_at": "2026-05-15T09:23:11",
|
||
"sent_at": "2026-05-15T09:21:44",
|
||
|
||
"sender": {
|
||
"email": "jan.novak@its.jnj.com",
|
||
"name": "Novák Jan",
|
||
"smtp": "jan.novak@its.jnj.com"
|
||
},
|
||
"to": "vladimir.buzalka@its.jnj.com",
|
||
"cc": "petra.free@its.jnj.com",
|
||
"bcc": "",
|
||
"display_to": "Buzalka Vladimir",
|
||
"display_cc": "Free Petra",
|
||
"recipients": [
|
||
{ "type": "to", "email": "vbuzalka@its.jnj.com", "name": "Buzalka Vladimir" },
|
||
{ "type": "cc", "email": "petra.free@its.jnj.com", "name": "Free Petra" }
|
||
],
|
||
|
||
"body_text": "Dobrý den,\n\nposílám...",
|
||
"body_html": "<html>...",
|
||
|
||
"attachments": [
|
||
{
|
||
"filename": "PD_report_CZ10022.pdf",
|
||
"size_bytes": 284512,
|
||
"mime_type": "application/pdf",
|
||
"content_id": null,
|
||
"is_inline": false
|
||
}
|
||
],
|
||
|
||
"headers": {
|
||
"message_id": "<xxx@domain>",
|
||
"x_originating_ip": "10.24.1.55",
|
||
"x_mailer": "Microsoft Outlook 16.0",
|
||
"received": ["from SMTP01...", "from EX2019..."],
|
||
"x_spam_status": "No"
|
||
},
|
||
|
||
"mapi": {
|
||
"0x0017": 1,
|
||
"0x0036": 0,
|
||
"0x0070": "Protocol deviation CZ10022",
|
||
"0x1035": "<message-id@domain>",
|
||
"0x1042": "<prev-id@domain>"
|
||
},
|
||
|
||
"parsed_at": "2026-06-01T20:00:00"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Hodnotové kódy
|
||
|
||
| Pole | Hodnota | Význam |
|
||
|---|---|---|
|
||
| `importance` | 0 | Nízká |
|
||
| | 1 | Normální |
|
||
| | 2 | Vysoká |
|
||
| `sensitivity` | 0 | Normální |
|
||
| | 1 | Osobní |
|
||
| | 2 | Soukromé |
|
||
| | 3 | Důvěrné |
|
||
| `flag_status` | 0 | Bez příznaku |
|
||
| | 1 | Označeno (follow up) |
|
||
| | 2 | Dokončeno |
|
||
|
||
---
|
||
|
||
## MongoDB indexy
|
||
|
||
Automaticky vytvořeny na konci importu (`--no-indexes` přeskočí):
|
||
|
||
| Index | Pole |
|
||
|---|---|
|
||
| Chronologický | `received_at`, `sent_at` |
|
||
| Odesílatel | `sender.email` |
|
||
| Soubor | `filename` (unique) |
|
||
| Konverzace | `conversation_topic` |
|
||
| Filtry | `has_attachments`, `categories`, `importance`, `flag_status` |
|
||
| Full-text | `subject` + `body_text` + `to` + `cc` (text index `text_search`) |
|
||
|
||
---
|
||
|
||
## Ukázkové dotazy (MongoDB shell / MCP)
|
||
|
||
**Emaily o UCO3001 s přílohou:**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({
|
||
$text: { $search: "UCO3001" },
|
||
has_attachments: true
|
||
}).sort({ received_at: -1 })
|
||
```
|
||
|
||
**Emaily od konkrétního odesílatele:**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({
|
||
"sender.email": /covance/i
|
||
}).sort({ received_at: -1 })
|
||
```
|
||
|
||
**Celé konverzační vlákno:**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({
|
||
conversation_topic: "Protocol deviation CZ10022"
|
||
}).sort({ received_at: 1 })
|
||
```
|
||
|
||
**Označené emaily (follow up):**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({ flag_status: 1 })
|
||
```
|
||
|
||
**Vysoká priorita s přílohou:**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({
|
||
importance: 2,
|
||
has_attachments: true
|
||
}).sort({ received_at: -1 })
|
||
```
|
||
|
||
**Statistiky podle odesílatele (top 20):**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].aggregate([
|
||
{ $group: { _id: "$sender.email", count: { $sum: 1 } } },
|
||
{ $sort: { count: -1 } },
|
||
{ $limit: 20 }
|
||
])
|
||
```
|
||
|
||
**Emaily s PDF přílohou:**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({
|
||
"attachments.mime_type": "application/pdf"
|
||
})
|
||
```
|
||
|
||
**Hledání v těle emailu:**
|
||
```javascript
|
||
db["vbuzalka@its.jnj.com"].find({
|
||
$text: { $search: "inactivation notification" }
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## Chybový log
|
||
|
||
Soubory které selhaly jsou zalogrovány do `parse_emails_errors.log` vedle skriptu:
|
||
```
|
||
2026-06-01 20:14:33 | open failed [7A3F...0000.msg]: <důvod>
|
||
2026-06-01 20:15:01 | extract_message failed [8B2C...0000.msg]: <důvod>
|
||
```
|
||
|
||
---
|
||
|
||
## Výkon
|
||
|
||
| Parametr | Hodnota |
|
||
|---|---|
|
||
| Počet souborů | ~69 000 |
|
||
| Rychlost | ~0.4 msg/s (síť SMB + htmlBody dekódování) |
|
||
| Odhadovaný čas | 48 hodin (přes noc, s pokračováním) |
|
||
| Batch size | 200 dokumentů / bulk_write |
|
||
| Odhadovaná velikost DB | 2–5 GB |
|
||
|
||
---
|
||
|
||
## Závislosti
|
||
|
||
```
|
||
extract-msg==0.55.0
|
||
pymongo
|
||
python-dateutil
|
||
```
|
||
|
||
Instalace do venv:
|
||
```cmd
|
||
"U:\PythonProject\Janssen\.venv\Scripts\pip.exe" install extract-msg pymongo python-dateutil
|
||
```
|
||
|
||
---
|
||
|
||
## Historie verzí
|
||
|
||
| Verze | Datum | Změna |
|
||
|---|---|---|
|
||
| 1.0 | 2026-06-01 | Iniciální verze |
|