Files
janssen/EmailsImport/parse_emails_v1.0.md

8.2 KiB
Raw Permalink Blame History

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:

"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):

"U:\PythonProject\Janssen\.venv\Scripts\python.exe" "U:\PythonProject\Janssen\EmailsImport\parse_emails_v1.0.py" --skip-existing

Test na malém vzorku:

"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

{
  "_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:

db["vbuzalka@its.jnj.com"].find({
  $text: { $search: "UCO3001" },
  has_attachments: true
}).sort({ received_at: -1 })

Emaily od konkrétního odesílatele:

db["vbuzalka@its.jnj.com"].find({
  "sender.email": /covance/i
}).sort({ received_at: -1 })

Celé konverzační vlákno:

db["vbuzalka@its.jnj.com"].find({
  conversation_topic: "Protocol deviation CZ10022"
}).sort({ received_at: 1 })

Označené emaily (follow up):

db["vbuzalka@its.jnj.com"].find({ flag_status: 1 })

Vysoká priorita s přílohou:

db["vbuzalka@its.jnj.com"].find({
  importance: 2,
  has_attachments: true
}).sort({ received_at: -1 })

Statistiky podle odesílatele (top 20):

db["vbuzalka@its.jnj.com"].aggregate([
  { $group: { _id: "$sender.email", count: { $sum: 1 } } },
  { $sort: { count: -1 } },
  { $limit: 20 }
])

Emaily s PDF přílohou:

db["vbuzalka@its.jnj.com"].find({
  "attachments.mime_type": "application/pdf"
})

Hledání v těle emailu:

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 25 GB

Závislosti

extract-msg==0.55.0
pymongo
python-dateutil

Instalace do venv:

"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