Fatture dei fornitori, conferme d'ordine, rendiconti mensili, scansioni inviate dalla stampante multifunzione: molti documenti arrivano in ufficio come allegati email. Aprire ogni messaggio, scaricare il file e spostarlo nella cartella giusta è un'attività che si ripete decine di volte alla settimana. Con il protocollo IMAP e la libreria standard di Python si può affidare tutto a uno script che legge la casella, salva gli allegati e tiene traccia di ciò che ha già fatto.
IMAP in breve
IMAP è il protocollo con cui i client di posta leggono i messaggi lasciandoli sul server. Uno script può usarlo esattamente come Outlook o Thunderbird: si collega, sceglie una cartella, cerca messaggi secondo criteri e li scarica. Servono l'indirizzo del server IMAP, di norma con cifratura sulla porta 993, e le credenziali. Per gli account con verifica in due passaggi si genera una password per app, come per l'invio via SMTP; alcuni servizi aziendali richiedono invece un'autenticazione basata su token, da configurare secondo la documentazione del provider.
Collegarsi e cercare i messaggi
import imaplib
with imaplib.IMAP4_SSL("imap.provider.it") as imap:
imap.login(utente, password)
imap.select("INBOX")
stato, dati = imap.uid("search", None, '(UNSEEN FROM "fatture@fornitore.it")')
uid_trovati = dati[0].split()
print(len(uid_trovati), "messaggi da elaborare")
Il criterio di ricerca segue la sintassi IMAP. Alcuni esempi utili:
| Criterio | Significato |
|---|---|
UNSEEN |
Messaggi non letti |
FROM "indirizzo" |
Mittente specifico |
SUBJECT "fattura" |
Parola nell'oggetto |
SINCE 01-Mar-2025 |
Ricevuti da quella data in poi |
(UNSEEN SUBJECT "ordine") |
Più condizioni insieme |
Il formato della data usa il mese abbreviato in inglese, indipendentemente dalla lingua dell'account. Conviene usare gli identificativi UID, tramite imap.uid(...), invece dei numeri di sequenza: i numeri cambiano quando si spostano o cancellano messaggi, gli UID restano stabili.
Estrarre gli allegati
Ogni messaggio si scarica in formato grezzo e si interpreta con il modulo email, che sa scomporre le parti di un messaggio complesso:
import email
from email import policy
from pathlib import Path
destinazione = Path("C:/Amministrazione/Fatture in arrivo")
for uid in uid_trovati:
stato, parti = imap.uid("fetch", uid, "(RFC822)")
messaggio = email.message_from_bytes(parti[0][1], policy=policy.default)
for allegato in messaggio.iter_attachments():
nome = allegato.get_filename()
if not nome or not nome.lower().endswith(".pdf"):
continue
percorso = destinazione / nome_sicuro(nome)
percorso.write_bytes(allegato.get_content())
Con policy=policy.default il modulo restituisce oggetti moderni, decodifica automaticamente i nomi dei file con caratteri accentati e offre iter_attachments(), che elenca solo le parti marcate come allegati.
Nomi di file sicuri
Il nome di un allegato è scelto da chi invia il messaggio e non va mai usato così com'è. Può contenere caratteri non validi su Windows, essere identico a quello di un file già salvato o, in casi malevoli, includere sequenze come ..\ per scrivere fuori dalla cartella prevista. Una funzione di pulizia risolve tutti e tre i problemi:
import re
from datetime import date
def nome_sicuro(nome):
nome = Path(nome).name # elimina eventuali percorsi
nome = re.sub(r'[\\/:*?"<>|]', "_", nome).strip(" .")
return f"{date.today():%Y-%m-%d}_{nome}"
Anteporre la data aiuta l'ordinamento e riduce le collisioni. Per eliminarle del tutto, prima di salvare si controlla se il file esiste e, in quel caso, si aggiunge un suffisso numerico.
Segnare i messaggi elaborati
Lo script deve ricordare quali messaggi ha già trattato, altrimenti alla prossima esecuzione salverà gli stessi allegati. Le strategie sono tre:
- segnare come letto: il fetch con
RFC822lo fa già automaticamente su molti server; è semplice, ma se una persona apre il messaggio prima dello script, questo non lo vedrà più; - spostare in una cartella dedicata, per esempio «Elaborati»: è la scelta più chiara, perché la casella mostra a colpo d'occhio cosa resta da fare. Si fa con
imap.uid("copy", uid, "Elaborati")seguito dalla marcatura del messaggio come eliminato; molti server supportano anche il comandoMOVEin un solo passaggio; - registrare gli UID in un file locale: indipendente dallo stato dei messaggi, ma da mantenere con cura.
Nel mio lavoro preferisco la seconda: lascia una traccia visibile anche a chi non conosce lo script e permette di rielaborare un messaggio semplicemente riportandolo nella posta in arrivo.
Sicurezza degli allegati
Salvare automaticamente file ricevuti da Internet richiede prudenza. Limitate lo script ai mittenti attesi e ai tipi di file previsti, come i PDF, ignorando eseguibili, archivi compressi e documenti con macro. Ricordate inoltre che il mittente di un'email può essere falsificato: filtrare per indirizzo riduce il rumore, ma non garantisce l'autenticità. I file salvati non vanno mai aperti automaticamente; vanno messi a disposizione delle persone, che li tratteranno come qualsiasi altro allegato, con l'antivirus aziendale attivo sulla cartella di destinazione.
In sintesi
imaplibpermette di cercare e scaricare messaggi; usate gli UID e la connessione cifrata.- Il modulo
emailconpolicy.defaultestrae gli allegati e ne decodifica i nomi. - Ripulite sempre i nomi dei file e anteponete la data per evitare collisioni.
- Spostate i messaggi elaborati in una cartella dedicata per non trattarli due volte.
- Filtrate mittenti e tipi di file e non aprite mai automaticamente gli allegati.