Files
janssen/Feasibility/jnj_dump_recipient_msgs_v1.0.py
T
2026-06-17 15:05:10 +02:00

189 lines
6.4 KiB
Python

# -*- coding: utf-8 -*-
# =============================================================================
# Nazev: jnj_dump_recipient_msgs_v1.0.py
# Verze: 1.0
# Datum: 2026-06-16
# Popis: JNJ-native (MAPI / pywin32). Najde VSECHNY e-maily danemu prijemci
# (default Hustak) napric vybranymi slozkami, ULOZI je jako .msg a
# u kazdeho VYPISE diagnosticke MAPI vlastnosti precteni ze ZIVE
# polozky (Message-ID 0x1035, SenderName 0x0C1A, SentRepresentingName
# 0x0042, addrtype 0x0C1E/0x0064, ReportText 0x1001, PrimarySendAccount
# 0x0E28, MessageFlags 0x0E07, item.Sent). Cil: porovnat, zda tyto
# vlastnosti zustanou i v ulozenem .msg (olefile kontrola doma).
# Pouziti: Spustit v JNJ Pythonu (Thonny), Outlook s JNJ schrankou.
# pip install pywin32 ; python jnj_dump_recipient_msgs_v1.0.py
# Skript NIC neodesila ani nemaze, jen CTE a uklada .msg kopie.
# =============================================================================
import os
import re
import sys
import win32com.client # pywin32
# ----------------------------- KONFIGURACE -----------------------------------
SENDER_SMTP = "vbuzalka@its.jnj.com" # ucet (jeho store se prohledava)
TARGET_EMAIL = "rastislav.hustak@fntt.sk" # koho hledame (To NEBO Cc)
# Slozky k prohledani (shoda na NAZEV slozky kdekoli ve strome; vc. podslozek).
# Prazdny seznam + SCAN_ALL=True => projde celou schranku (pomale!).
SCAN_FOLDERS = ["Sent Items", "Drafts", "Deleted Items", "Archive", "Inbox"]
SCAN_ALL = False
# Kam ulozit .msg kopie (na JNJ stroji). Vytvori se, kdyz neexistuje.
OUTPUT_DIR = r"C:\Users\vbuzalka\hustak_dump"
# -----------------------------------------------------------------------------
OL_MSG = 3 # olMSG (SaveAs typ)
OL_FOLDER_SENT = 5
PA = "http://schemas.microsoft.com/mapi/proptag/0x{:s}"
# Diagnosticke tagy (PT_UNICODE 001F, dlouhe 0003)
TAGS = [
("Msg-ID", "1035001F"),
("SenderName", "0C1A001F"),
("SenderAddrType", "0C1E001F"),
("SentRepName", "0042001F"),
("SentRepAddrType", "0064001F"),
("ReportText", "1001001F"),
("PrimarySendAcct", "0E28001F"),
]
TAG_MSGFLAGS = "0E070003"
TAG_RCPT_ADDRTYPE = "3002001F"
def smtp_of(recipient):
try:
return (recipient.PropertyAccessor.GetProperty(PA.format("39FE001E")) or "").lower()
except Exception:
try:
return (recipient.Address or "").lower()
except Exception:
return ""
def get_prop(item, tag):
try:
v = item.PropertyAccessor.GetProperty(PA.format(tag))
return v
except Exception:
return None
def get_store_root(ns):
try:
for acct in ns.Accounts:
if (acct.SmtpAddress or "").lower() == SENDER_SMTP.lower():
return acct.DeliveryStore.GetRootFolder()
except Exception:
pass
return ns.GetDefaultFolder(OL_FOLDER_SENT).Parent # fallback: koren default store
def iter_target_folders(root):
"""Yield slozek, ktere se maji skenovat (dle nazvu + jejich podslozky)."""
def walk(folder, inscope):
scope = inscope or SCAN_ALL or (folder.Name in SCAN_FOLDERS)
if scope:
yield folder
try:
for sub in folder.Folders:
yield from walk(sub, scope)
except Exception:
pass
yield from walk(root, False)
def safe(s, n=40):
s = re.sub(r"[^A-Za-z0-9._-]+", "_", (s or ""))
return s[:n].strip("_")
def matches_target(item):
"""Vrati ('To'/'Cc') kdyz je TARGET_EMAIL mezi prijemci, jinak None."""
tgt = TARGET_EMAIL.lower()
try:
for r in item.Recipients:
if smtp_of(r) == tgt:
return {1: "To", 2: "Cc", 3: "Bcc"}.get(r.Type, "To")
except Exception:
pass
return None
def main():
os.makedirs(OUTPUT_DIR, exist_ok=True)
outlook = win32com.client.Dispatch("Outlook.Application")
ns = outlook.GetNamespace("MAPI")
root = get_store_root(ns)
print(f"Hledam e-maily, kde je prijemce: {TARGET_EMAIL}")
print(f"Slozky: {'VSE' if SCAN_ALL else ', '.join(SCAN_FOLDERS)}")
print(f"Vystup .msg: {OUTPUT_DIR}")
print("=" * 90)
idx = 0
for folder in iter_target_folders(root):
try:
items = folder.Items
except Exception:
continue
for it in list(items):
try:
if it.Class != 43: # olMail
continue
except Exception:
continue
role = matches_target(it)
if not role:
continue
idx += 1
# --- diagnostika ze ZIVE polozky ---
try:
sent_flag = it.Sent
except Exception:
sent_flag = "?"
flags = get_prop(it, TAG_MSGFLAGS)
props = {label: get_prop(it, tag) for label, tag in TAGS}
try:
sent_on = it.SentOn
except Exception:
sent_on = None
try:
entry_tail = (it.EntryID or "")[-20:]
except Exception:
entry_tail = ""
print(f"\n[{idx}] slozka='{folder.Name}' role={role} Sent={sent_flag} flags={flags}")
print(f" subject : {getattr(it,'Subject','')}")
print(f" sent_on : {sent_on}")
print(f" Msg-ID : {props['Msg-ID']}")
print(f" SenderName : {props['SenderName']} (addrtype {props['SenderAddrType']})")
print(f" SentRepName : {props['SentRepName']} (addrtype {props['SentRepAddrType']})")
print(f" PrimarySendAcct: {props['PrimarySendAcct']}")
rt = props["ReportText"]
print(f" ReportText 0x1001: {'ANO -> ' + repr(rt[:120]) if rt else '-'}")
# --- ulozeni .msg ---
fn = f"{idx:02d}_{safe(folder.Name,18)}_{safe(getattr(it,'Subject',''),28)}_{entry_tail}.msg"
path = os.path.join(OUTPUT_DIR, fn)
try:
it.SaveAs(path, OL_MSG)
print(f" ulozeno: {fn}")
except Exception as e:
print(f" !! SaveAs chyba: {e}")
print("\n" + "=" * 90)
print(f"Hotovo. Nalezeno a ulozeno: {idx} polozek do {OUTPUT_DIR}")
print("Prines .msg domu a porovnej vlastnosti olefilem (zive vs ulozene).")
if __name__ == "__main__":
try:
main()
except Exception as e:
print("CHYBA:", e)
sys.exit(1)