'_ic"rdZ ddlmZn#e$rddlZejeZYnwxYwGddZdS)u OutlookConnector — Frank Outlook Module (Layer 1) Connessione a Outlook via COM/MAPI usando pywin32. Outlook deve essere aperto e loggato prima dell'uso. Guardrail: nessun delete definitivo — le email vengono sempre spostate in [Frank_Cestino] invece di essere eliminate. )loggerNc eZdZdZdZdefdZddedeefdZ dd e d e d edeefdZ de de defdZ de fdZde de de defdZd e fdZdS)OutlookConnectorz@Wrapper COM/MAPI per Outlook. Richiede Outlook aperto e loggato.c"d|_d|_dS)N)app namespace)selfs 8C:\PYTHON\Scheduler\modules\outlook\outlook_connector.py__init__zOutlookConnector.__init__sreturnc: ddl}|jd|_|jd|_|jjj}tj d|dS#t$r"}tj d|Yd}~dSd}~wwxYw) u Connette a Outlook via COM (late binding). Usa Dispatch, NON GetActiveObject — funziona anche se Outlook non era già aperto. Restituisce True se connessione riuscita. rNzOutlook.ApplicationMAPIuConnesso a Outlook — utente: TzConnessione Outlook fallita: F) win32com.clientclientDispatchr GetNamespacer CurrentUserNamerinfo Exceptionerror)r win32comaccountes r connectzOutlookConnector.connects  " " " "//0EFFDH!X226::DNn05G KC'CC D D D4    L<<< = = =55555 sA*A.. B8BBNF recursivec|jstd||jd}g} |jD]]}|j|j|jjd}|||r*| | |d^n.#t$r!}tj d|Yd}~nd}~wwxYw|S)a Elenca le cartelle di Outlook. Args: parent: folder MAPI da cui partire (None = root Inbox) recursive: se True, elenca anche le sottocartelle Returns: Lista di dict: [{'name': str, 'path': str, 'count': int}, ...] %Non connesso. Chiama connect() prima.N)namepathcountT)parentrzErrore listando cartelle: )r RuntimeErrorGetDefaultFolderFoldersr FolderPathItemsCountappendextend list_foldersrrr)r r$rresultsfolderentryrs r r-zOutlookConnector.list_folders*s ~ HFGG G >^44Q77F ; . U U"K"-#\/ u%%%UNN4#4#4Fd#4#S#STTT U ; ; ; L9a99 : : : : : : : : ;sA%B C&CCInbox folder_namen unread_onlyc f|jstd||}|tjd|dgS|j}|dd|r|d}g}d} |D]}||krn|jd kr |j pd dd  d d  dd } |j } t| dr| d} nt| } ||jpd|jpd |jpd | | |j|jd|dz }#t*$r!} tjd| Yd} ~ d} ~ wwxYwn1#t*$r$} tjd|d| Yd} ~ nd} ~ wwxYw|S)a Legge le ultime N email da una cartella. Usa .Restrict() per filtrare in modo efficiente (evita di caricare tutta la mailbox in memoria). Args: folder_name: nome cartella ('Inbox' = Posta in arrivo) n: numero massimo di email da restituire unread_only: se True, restituisce solo le non lette Returns: Lista di dict per ogni email: {'subject', 'sender', 'sender_email', 'received', 'body_preview', 'unread', 'entry_id'} rN Cartella 'z ' non trovataz[ReceivedTime]Tz[UnRead] = Truer+z   strftimez%Y-%m-%d %H:%M(nessun oggetto))subjectsender sender_emailreceived body_previewunreadentry_idzErrore leggendo email: zErrore iterando email in '': )rr%_get_folder_by_namerrr)SortRestrictClassBodyreplace ReceivedTimehasattrr=strr+Subject SenderNameSenderEmailAddressUnReadEntryIDrwarning) r r3r4r5r/itemsr.r#itemrCrB received_strrs r get_emailszOutlookConnector.get_emailsKsA ~ HFGG G))+66 > L@k@@@ A A AI  #T***  6NN#455E K  A::E:##$(IOTcT#:#B#B63#O#O#W#WX\^a#b#bL#0Hx445'/'8'89I'J'J '*8}} NN#'<#E3E"&/"7R(,(?(E2$0(4"&+$(L$$QJEE N#@Q#@#@AAAHHHH K K K LIkIIaII J J J J J J J J KsCFB6EF E<E72F7E<<F F. F))F.rEtarget_folder_namec|jstd |j|}|jd}|||}|jpd}||tjd|d|dS#t$r%}tj d|d|Yd }~d Sd }~wwxYw) u Sposta un'email in una cartella target. GUARDRAIL: non usare per cancellare email — usa sempre [Frank_Cestino] come destinazione "cestino" reversibile. Args: entry_id: EntryID dell'email (da get_emails) target_folder_name: nome della cartella destinazione Returns: True se operazione riuscita rr r>zEmail spostata in 'rGTzErrore spostando email : NF) rr% GetItemFromIDr&get_or_create_folderrQMoverrrr)r rEr[ mail_iteminbox target_folderr?rs r move_emailzOutlookConnector.move_emails~ HFGG G 44X>>IN33A66E 55e=OPPM'=+=G NN= ) ) ) KN.@NNWNN O O O4    LB8BBqBB C C C55555 sBB C &CC r!c |jD]}|j|kr|cS|j|}tjd|d|S#t $r }tjd|d|d}~wwxYw)a  Cerca una sottocartella per nome in parent_folder. Se non esiste, la crea. Args: parent_folder: folder MAPI padre name: nome della cartella da cercare/creare Returns: Folder object MAPI r7z' creatazErrore get_or_create_folder 'rGN)r'rAddrrrr)r parent_folderr!r/ new_folderrs r r_z%OutlookConnector.get_or_create_folders '/ " ";$&&!MMM''.22488J K3T333 4 4 4     LEEE!EE F F F  sA4A A9A44A9tor?bodycR|jstd |jd}||_||_||_|tjd|d|dS#t$r%}tj d|d|Yd}~dSd}~wwxYw) z Invia un'email tramite Outlook. Args: to: destinatario (indirizzo email) subject: oggetto body: corpo del messaggio (testo semplice) Returns: True se invio riuscito rrzEmail inviata a r]TzErrore invio email a NF) rr% CreateItemTorQrLSendrrrr)r rir?rjmailrs r send_emailzOutlookConnector.send_emailsx HFGG G 8&&q))DDG"DLDI IIKKK K:2:::: ; ; ;4    L:::q:: ; ; ;55555 sAA77 B&B!!B&cl|dvr|jdS|jd}|jD]}|j|kr|cS |jjD]1}|}|jD]}|j|kr|ccS2n#t$rYnwxYwdS)z Recupera una cartella per nome semplice. 'Inbox' mappa sulla cartella Posta in arrivo nativa. Per altre cartelle, cerca per nome in primo livello dell'Inbox. )rbzposta in arrivor N)lowerrr&r'rStores GetRootFolderr)r r3rbr/storeroots r rHz$OutlookConnector._get_folder_by_names     "> > >>22155 5//22m  F{k)) * . & &**,,"l&&F{k11% 2& &     D ts%;B$!B$$ B10B1)NF)r1r2F)__name__ __module__ __qualname____doc__r boolrlistdictr-rPintrZrdr_rprHr r rrsFJJ"4DJBAAcAAtA`dei`jAAAAF 3 C D    D0S3cd4sr r)rzlogurur ImportErrorlogging getLoggerrwrrr r rs))))NNN W x ( (FFF) iiiiiiiiiis  ''