z230
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: jnj_scan_failed_sent_v1.0.py
|
||||
# Verze: 1.0
|
||||
# Datum: 2026-06-16
|
||||
# Popis: JNJ-native (MAPI / pywin32). Projde slozku Odeslane (Sent Items) za
|
||||
# poslednich N dni a najde PODEZRELE e-maily = pravdepodobne NEODESLANE
|
||||
# (napr. SendAs denied). Kazdy podezrely ULOZI jako .msg a vypise, ktere
|
||||
# priznaky se trefily. NIC neodesila ani nemaze, jen CTE a uklada.
|
||||
# Priznaky podezreni (cteno ze ZIVE polozky):
|
||||
# FAIL_BODY = telo/ReportText obsahuje "could not be sent" / "SendAsDenied"
|
||||
# / "permission to send the message on behalf" / "TransportSend"
|
||||
# SENDAS_BUZ = PrimarySendAccount/SentRepresenting/Sender obsahuje "buzalka.cz"
|
||||
# NO_MSGID = chybi Internet Message-ID (0x1035) -- slabsi priznak
|
||||
# Pouziti: JNJ Python (Thonny), Outlook s JNJ schrankou.
|
||||
# pip install pywin32 ; python jnj_scan_failed_sent_v1.0.py
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import datetime
|
||||
import win32com.client # pywin32
|
||||
|
||||
# ----------------------------- KONFIGURACE -----------------------------------
|
||||
|
||||
SENDER_SMTP = "vbuzalka@its.jnj.com"
|
||||
DAYS = 60 # okno: poslednich N dni
|
||||
OUTPUT_DIR = r"C:\Users\vbuzalka\sent_suspects"
|
||||
|
||||
# Ukladat i polozky, ktere maji JEN slaby priznak NO_MSGID (bez FAIL/SENDAS)?
|
||||
# True = vc. provizornich kopii bez Message-ID (muze byt vic souboru).
|
||||
INCLUDE_NO_MSGID = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
OL_MSG = 3
|
||||
OL_FOLDER_SENT = 5
|
||||
PA = "http://schemas.microsoft.com/mapi/proptag/0x{:s}"
|
||||
|
||||
P_MSGID = "1035001F"
|
||||
P_SENDACCT = "0E28001F" # PrimarySendAccount
|
||||
P_SENTREP_EM = "0065001F" # SentRepresentingEmailAddress
|
||||
P_SENDER_EM = "0C1F001F" # SenderEmailAddress
|
||||
P_REPORTTEXT = "1001001F" # ReportText (kdyz existuje)
|
||||
|
||||
FAIL_SIGNS = [
|
||||
"could not be sent",
|
||||
"sendasdenied",
|
||||
"permission to send the message on behalf",
|
||||
"transportsend operation has failed",
|
||||
"mapiexceptionsendasdenied",
|
||||
"tuto zpravu nelze odeslat", # pro pripad lokalizace
|
||||
]
|
||||
|
||||
|
||||
def gp(item, tag):
|
||||
try:
|
||||
return item.PropertyAccessor.GetProperty(PA.format(tag))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def get_sent_folder(ns):
|
||||
try:
|
||||
for acct in ns.Accounts:
|
||||
if (acct.SmtpAddress or "").lower() == SENDER_SMTP.lower():
|
||||
return acct.DeliveryStore.GetDefaultFolder(OL_FOLDER_SENT)
|
||||
except Exception:
|
||||
pass
|
||||
return ns.GetDefaultFolder(OL_FOLDER_SENT)
|
||||
|
||||
|
||||
def safe(s, n=34):
|
||||
return re.sub(r"[^A-Za-z0-9._-]+", "_", (s or ""))[:n].strip("_")
|
||||
|
||||
|
||||
def analyze(item):
|
||||
"""Vrati seznam priznaku (flags) pro polozku."""
|
||||
flags = []
|
||||
|
||||
# 1) FAIL_BODY: telo + ReportText
|
||||
blob = ""
|
||||
try:
|
||||
blob += (item.Body or "")
|
||||
except Exception:
|
||||
pass
|
||||
rt = gp(item, P_REPORTTEXT)
|
||||
if rt:
|
||||
blob += "\n" + str(rt)
|
||||
low = blob.lower()
|
||||
if any(s in low for s in FAIL_SIGNS):
|
||||
flags.append("FAIL_BODY")
|
||||
|
||||
# 2) SENDAS_BUZ: nektera z odesilatelskych poloz. obsahuje buzalka.cz
|
||||
for tag in (P_SENDACCT, P_SENTREP_EM, P_SENDER_EM):
|
||||
v = gp(item, tag)
|
||||
if v and "buzalka.cz" in str(v).lower():
|
||||
flags.append("SENDAS_BUZ")
|
||||
break
|
||||
|
||||
# 3) NO_MSGID
|
||||
mid = gp(item, P_MSGID)
|
||||
if not mid:
|
||||
flags.append("NO_MSGID")
|
||||
|
||||
return flags, (mid or "")
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
cutoff = datetime.date.today() - datetime.timedelta(days=DAYS)
|
||||
|
||||
outlook = win32com.client.Dispatch("Outlook.Application")
|
||||
ns = outlook.GetNamespace("MAPI")
|
||||
sent = get_sent_folder(ns)
|
||||
items = sent.Items
|
||||
items.Sort("[SentOn]", True) # nejnovejsi prvni
|
||||
|
||||
print(f"Slozka : {sent.FolderPath}")
|
||||
print(f"Okno : poslednich {DAYS} dni (od {cutoff.isoformat()})")
|
||||
print(f"Vystup : {OUTPUT_DIR}")
|
||||
print(f"NO_MSGID se uklada: {INCLUDE_NO_MSGID}")
|
||||
print("=" * 90)
|
||||
|
||||
scanned = saved = strong = 0
|
||||
for it in list(items):
|
||||
try:
|
||||
if it.Class != 43:
|
||||
continue
|
||||
except Exception:
|
||||
continue
|
||||
# datum + early stop
|
||||
try:
|
||||
s = it.SentOn
|
||||
sdate = datetime.date(s.year, s.month, s.day)
|
||||
except Exception:
|
||||
sdate = None
|
||||
if sdate is not None:
|
||||
if sdate < cutoff:
|
||||
break # dale uz jen starsi (serazeno desc)
|
||||
scanned += 1
|
||||
|
||||
flags, mid = analyze(it)
|
||||
if not flags:
|
||||
continue
|
||||
is_strong = ("FAIL_BODY" in flags) or ("SENDAS_BUZ" in flags)
|
||||
if not is_strong and not (INCLUDE_NO_MSGID and "NO_MSGID" in flags):
|
||||
continue
|
||||
|
||||
saved += 1
|
||||
if is_strong:
|
||||
strong += 1
|
||||
|
||||
subj = ""
|
||||
try:
|
||||
subj = it.Subject or ""
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
tail = (it.EntryID or "")[-20:]
|
||||
except Exception:
|
||||
tail = ""
|
||||
|
||||
tagstr = "+".join(flags)
|
||||
print(f"\n[{saved}] {sdate} flags={tagstr}")
|
||||
print(f" subj : {subj}")
|
||||
print(f" msgid: {mid if mid else '<chybi>'}")
|
||||
|
||||
fn = f"{('STRONG' if is_strong else 'weak')}_{sdate}_{safe(subj,30)}_{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"Prohledano (v okne): {scanned}")
|
||||
print(f"Ulozeno podezrelych: {saved} (z toho silnych FAIL/SENDAS: {strong})")
|
||||
print(f"Soubory v: {OUTPUT_DIR} -> prines je domu ke kontrole.")
|
||||
print("Pozn.: STRONG_* = telo NDR nebo send-account buzalka.cz (skoro jiste neodeslano).")
|
||||
print(" weak_* = jen chybi Message-ID (muze byt i provizorni kopie, co se pozdeji dokonci).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
print("CHYBA:", e)
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user