[Risolto] filtrare le mail prima di scaricarle

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

[Risolto] filtrare le mail prima di scaricarle

Messaggio da rai »

Ciao a tutti,
vorrei monitorare regolarmente un mail server e scaricarne solo i messaggi che nel corpo corrispondono a un dato pattern.
Il contenuto dei messaggi scaricati serve a uno script per predisporre dei documenti.

Potrei usare fetchmail (forse insieme a procmail ?), non cancellare dal server i messaggi scaricati, tenere il mio disco pulito mettendo la inbox su /tmp. Però non ho capito se e come è possibile filtrare i messaggi *prima* di averli scaricati localmente.
O forse è possibile scorrere sul server il corpo dei nuovi messaggi con wget / curl o analoghi tool ?
Grazie dell'attenzione.
Ultima modifica di rai il lunedì 14 aprile 2014, 21:11, modificato 1 volta in totale.
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

Quando un domanda non riceve risposte di solito è posta male o non merita considerazione per qualche altro motivo.

Allora provo un'altra formulazione: posso scaricare automaticamente solo determinate mail sulla base del testo contenuto e ignorare le altre? (e quindi evitare di scaricare i loro allegati)

Sarei molto grato se qualcuno rispondesse anche solo per farmi notare l'illogicità della questione, tenuto conto che sono un incompetente al riguardo
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

ciao rai,
provo a proporre una possibile soluzione velocemente:
fetchmail in crontab (oppure puo' essere daemon) per avere una copia della corrispondenza in locale sempre aggiornata. L'opzione --keep mantiene le mail sul server. grepmail per le ricerche con regex e mpack per estrarre l'allegato.

Un esempio veloce per gmail da linea di comando (meglio scrivere i parametri in ~/.fetchmailrc).
proto IMAP, server imap.gmail.com, timeout 10s, Secure Sockets Layer, porta 993 di default

Codice: Seleziona tutto

% fetchmail --ssl --keep --timeout 10 -p imap imap.gmail.com -u xxxxxxxxx@gmail.com
Al primo avvio devi dare il tempo di scaricare tutto. Puoi aggiungere --verbose per controllare e poi cambiare con --silent per togliere l'output a video.

grepmail cerca localmente. Il man è ben dettagliato e vi sono anche parecchi esempi. Uno tra questi:

Codice: Seleziona tutto

# cerca tutte le mail, nell'header e nel body,  il contenuto "Pilot"
% grepmail -hb "Pilot" saved-mail*
Fai attenzione che saved-mail, la directory dove fetchmail ha salvato le mail, sulla Debian e' in /var/mail/$USER

Per l'allegato e' sufficiente fare una pipe dell'output di grepmail su munpack

Codice: Seleziona tutto

# estrai gli allegati dalle mail di ieri
% grepmail -d yesterday /var/mail/$USER | munpack
Tieni presente che io l'ho verificato e funziona bene, ma bisognerebbe (forse dipendente dal tuo reale utilizzo) mettere anche grepmail in crontab.

:ciao:
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

grazie della risposta e di avere condiviso la tua configurazione per gmail.
In realtà le mail devo prenderle da un server di PEC, ma se avessi problemi a farlo potrei sempre inoltrarle con un filtro a un indirizzo gmail e mi troverei il lavoro semplificato ;)
Purtroppo dalla tua soluzione mi pare di capire che per greppare un messaggio devo averlo scaricato in locale.
Invece, per il mio script, a me interessano solo alcune delle mail che mi arrivano e non vorrei essere costretto al download di tutte: la posta la leggo su webmail.
Non c'è modo di cercare nel corpo dei messaggi ancora sul server? come ti fa fare gmail, per capirci
Pike
Rampante Reduce
Rampante Reduce
Messaggi: 5460
Iscrizione: domenica 20 gennaio 2008, 1:13
Desktop: Kubuntu
Distribuzione: 20.04 x64
Contatti:

Re: filtrare le mail prima di scaricarle

Messaggio da Pike »

Solo se il server PEC ti consente di attivare i filtri.
E tu scarichi solo il contenuto di UNA cartella, via POP3.
Sono colui che fa cose che non servono...
Secondo Principio di Dilbert, di Scott Adams. "Si parte dalla certezza che siamo tutti idioti". Ed alcuni su questo mi ab-battono alla grande.
Come certificato dalla moderazione, incivile e maleducato. You have been warned.
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

Solo se il server PEC ti consente di attivare i filtri.
non sarà un crivello raffinatissimo ma un inoltro selettivo per forza deve fartelo fare, dopo tutto si paga! Comunque questo lo terrei come piano b
E tu scarichi solo il contenuto di UNA cartella, via POP3.
potresti chiarire per favore?
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

rai ha scritto: In realtà le mail devo prenderle da un server di PEC, ma se avessi problemi a farlo potrei sempre inoltrarle con un filtro a un indirizzo gmail e mi troverei il lavoro semplificato
PEC (RFC6109)mantiene le specifiche IMAP/POP.
Eventuali dettagli di configurazione vengono forniti dal gestore.
rai ha scritto: Invece, per il mio script, a me interessano solo alcune delle mail che mi arrivano e non vorrei essere costretto al download di tutte: la posta la leggo su webmail.
Il motivo e' semplice e dipende dal protocollo utilizzato dal gestore. Se fosse IMAP potresti fare delle query significanti, ma con POP non fai assolutamente niente ! Questo potrebbe essere un buon motivo per greppare localmente.
rai ha scritto: Non c'è modo di cercare nel corpo dei messaggi ancora sul server? come ti fa fare gmail, per capirci
Certo che si con IMAP, non con POP.
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

ixamit ha scritto:Certo che si con IMAP, non con POP.
Il mio gestore PEC ofre IMAP solo come servizio aggiuntivo e non lo vorrei pagare:
però ho verificato che mi fa selettivamente inoltrare le pec quindi viene buono il piano B se posso contare sul tuo aiuto.
Mi aiuteresti a capire come arrivare ad assegnare ad una variabile della mia shell un stringa presa dal corpo di un messaggio che sta su Gmail?

PS grazie per il link con le specifiche PEC
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

rai ha scritto: Mi aiuteresti a capire come arrivare ad assegnare ad una variabile della mia shell un stringa presa dal corpo di un messaggio che sta su Gmail?
Attenzione, io non capisco questa richiesta.... spiega in dettaglio.

Se il tuo piano "B" consiste nell'innoltrare da PEC a IMAP(rfc3501) per poter fare delle SEARCH da remoto, si' le puoi fare senza scaricare;
ma se vuoi che ti restituisca parte del HEADER/BODY o altro devi aprire e leggere l'email.
La SEARCH restituisce solo una lista con riferimenti trovati; se vuoi vedere il paragrafo dove e' presente "FOO", devi necessariamente leggere l'email. Similmente a sql, una query non estrae il record. Credo che un esempio sia piu' esplicativo:

Codice: Seleziona tutto

% openssl s_client -crlf -connect imap.gmail.com:993
CONNECTED(00000003)
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=imap.gmail.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
------ [cut here] --------

tag LOGIN USER PASSWORD
* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE ENABLE MOVE CONDSTORE     ESEARCH
tag OK xxxxxxxxx xxxxxxxxxx xxxxxxxxxxxx authenticated (Success)

tag SEARCH TEXT "hello"
* SEARCH 26 37 43 48 55 62 63 80 83 88 89 92 93 94 95 97 112 114 134 150 395 445 447 452 540 541 543

tag FETCH 43 (FLAGS BODY[HEADER.FIELDS (To)])
* 43 FETCH (FLAGS (\Seen) BODY[HEADER.FIELDS (To)] {32}
To: "Max" <xxxxxxxxxxxx@xxxxxxxxxxx>

)
tag OK Success

tag LOGOUT
* BYE LOGOUT Requested
tag OK 73 good day (Success)
read:errno=0 

% _
Questo e' esattamente quello che succede con IMAP: dopo i convenevoli, chiedo di ricercare, tra tutte le mail, quelle che contengono nell'header o nel body "hello" ed il server risponde con una lista numerata. Il comando FETCH restituisce i dati associati

L'esempio di sopra puo' essere semplificato usando apposite librerie con linguaggi di scripting, per esempio python:

Codice: Seleziona tutto

% python
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import imaplib
>>> mail = imaplib.IMAP4_SSL('imap.gmail.com')
>>> mail.login('xxxxxxxxxxx@gmail.com', 'password')
('OK', ['xxxxxxxxxxx@gmail.com xxxxxxxx xxxxxxxx authenticated (Success)'])
>>> mail.select()
('OK', ['545'])
>>> mail.search(None, 'TEXT', '"hello"')
('OK', ['26 37 43 48 55 62 63 80 83 88 89 92 93 94 95 97 112 114 134 150 395 445 447 452 540 541 543'])
>>> mail.fetch(43, '(FLAGS BODY) ')
('OK', ['43 (FLAGS (\\Seen) BODY (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 2435 77)("TEXT" "PLAIN" ("NAME" "stereochemistry_aminoacids.txt") NIL NIL "BASE64" 201974 2589) "MIXED"))'])
>>> mail.close()
('OK', ['Returned to authenticated state. (Success)'])
>>> mail.logout()
('BYE', ['LOGOUT Requested'])
>>> quit()
% _
Fai delle prove ed eventualmente scrivi/amo un 2cents script se questa e' la strada
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

Grazie della disponibilità.
ixamit ha scritto:Attenzione, io non capisco questa richiesta.... spiega in dettaglio.
sì, ho fatto confusione, volevo dire: come faccio a scaricare in locale solo le mail che corrispondono a un dato pattern ?
sto leggendo la documentazione di openssl e del modulo imaplib ma credo di avere delle lacune di base da colmare. Per questo il tuo aiuto è prezioso

ho provato a loggarmi con openssl ma alla search ottengo

Codice: Seleziona tutto

tag SEARCH TEXT "qualsiasi cosa"
tag BAD SEARCH not allowed now.
invece con python la cosa funziona

Codice: Seleziona tutto

$ python
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import imaplib
>>> m = imaplib.IMAP4_SSL('imap.gmail.com')
>>> m.login('xxx@gmail.com', 'password')
('OK', ['xxxxxxxxx@gmail.com xxxxxxxxx xxxxxxxxx authenticated (Success)'])
>>> m.select()
('OK', ['17'])
>>> m.search(None, 'TEXT', '"certificata"')
('OK', ['6 7 8 9 10 12 13 14 16'])
>>> m.fetch(12, '(FLAGS BODY)')
('OK', ['12 (FLAGS (\\Seen) BODY ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 682 13)("APPLICATION" "XML" ("NAME" "daticert.xml") NIL NIL "BASE64" 1018)("MESSAGE" "RFC822" ("NAME" "postacert.eml") NIL NIL "7BIT" 13914 (NIL "Fwd: POSTA CERTIFICATA: COMUNICAZIONE 2261/2014/LAV" ((NIL NIL "xxxxxxxxx" "pec.it")) ((NIL NIL "xxxxxxxxx" "pec.it")) ((NIL NIL "xxxxxxxxx" "pec.it")) ((NIL NIL "xxxxxxxxx" "gmail.com")) NIL NIL "NIL" "<opec275.20140324160757.25897.02.1.30@pec.aruba.it>") (("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 0 0)("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 12965 ("Mon, 24 Mar 2014 16:07:38 +0100" "POSTA CERTIFICATA: COMUNICAZIONE 2261/2014/LAV" (("Per conto di: tribunale.palermo@civile.ptel.giustiziacert.it" NIL "posta-certificata" "hpcertpe.it")) (("Per conto di: tribunale.palermo@civile.ptel.giustiziacert.it" NIL "posta-certificata" "hpcertpe.it")) ((NIL NIL "tribunale.palermo" "civile.ptel.giustiziacert.it")) ((NIL NIL "xxxxxxxxx" "pec.it")) NIL NIL "NIL" "<opec275.20140324160738.01006.06.6.6@hpcertpe.it>") ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 369 9)("APPLICATION" "XML" ("NAME" "daticert.xml") NIL NIL "BASE64" 1204)("MESSAGE" "RFC822" ("NAME" "postacert.eml") NIL NIL "7BIT" 3798 ("Mon, 24 Mar 2014 16:07:37 +0100 (CET)" "COMUNICAZIONE 2261/2014/LAV" ((NIL NIL "tribunale.palermo" "civile.ptel.giustiziacert.it")) ((NIL NIL "tribunale.palermo" "civile.ptel.giustiziacert.it")) ((NIL NIL "tribunale.palermo" "civile.ptel.giustiziacert.it")) ((NIL NIL "xxxxxxxxx" "pec.it")) NIL NIL "NIL" "<opec275.20140324160738.01006.06.6.6@hpcertpe.it>") (("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 702 25)("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 497 18)("TEXT" "XML" ("CHARSET" "us-ascii" "NAME" "IndiceBusta.xml") "IndiceBusta.xml" NIL "7BIT" 190 0)("TEXT" "XML" ("CHARSET" "us-ascii" "NAME" "Comunicazione.xml") "part54668A405A309E8008D5C442270ED6B4" NIL "7BIT" 924 27) "MIXED") 110) "MIXED")("APPLICATION" "X-PKCS7-SIGNATURE" ("NAME" "smime.p7s") NIL NIL "BASE64" 5066) "SIGNED") 278) "MIXED") 305) "MIXED")("APPLICATION" "X-PKCS7-SIGNATURE" ("NAME" "smime.p7s") NIL NIL "BASE64" 3412) "SIGNED"))'])
>>> m.close()
('OK', ['Returned to authenticated state. (Success)'])
>>> m.logout()
('BYE', ['LOGOUT Requested'])
>>> quit()
$ 
domande:

Dato che vorrei raffinare i risultati della search: :·: la ricerca può essere case sensitive ? :·: c'è modo di cercare la stringa esatta invece delle varie parole ? :·: si possono usare regex ?

questa search si esegue su tutte le mail in INBOX, lette o non-lette: :·: c'è modo di restringerla a quelle UNREAD ?
Se no, dopo aver scaricato le mail desiderate lo script dovrebbe 'archiviarle' per non ritrovarsele alla successiva passata

La webGmail mostra anche il testo della PEC originale ma il testo restituito da fetch non comprende il messaggio PEC originale: è incluso in un allegato che si chiama sempre Comunicazione.xml : :·: come ci si arriva?
Ultima modifica di rai il giovedì 10 aprile 2014, 15:28, modificato 1 volta in totale.
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

Ciao rai,
rai ha scritto: domande:

Dato che vorrei raffinare i risultati della search: :·: la ricerca può essere case sensitive ? :·: c'è modo di cercare la stringa esatta invece delle varie parole ? :·: si possono usare regex ?

questa search si esegue su tutte le mail in INBOX, lette o non-lette: :·: c'è modo di restringerla a quelle UNREAD ?
Se no, dopo aver scaricato le mail desiderate lo script dovrebbe 'archiviarle' per non ritrovarsele alla successiva passata

La webGmail mostra anche il testo della PEC originale ma il testo restituito da fetch non comprende il messaggio PEC originale: è incluso in un allegato che si chiama sempre Comunicazione.xml : :·: come ci si arriva?
Rispondo velocissimamente in quanto ho i minuti contati, stasera se la famiglia mi concede guardo meglio la situazione.

case sesitive, no, mi sembra proprio che sia specificatamente case-insensitive...
ma non scoraggiarti :D se guardi il mio precedente post trovi un link al rfc... mi sembra a pagina 49 trovi le risposte alle SEARCH (ed anche SEEN/UNSEEN)

Guardo meglio stasera, scusa
Max
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

ixamit [url=http://forum.ubuntu-it.org/viewtopic.php?p=4560776#p4560776][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Ciao rai,
rai ha scritto: domande:

Dato che vorrei raffinare i risultati della search: :·: la ricerca può essere case sensitive ? :·: c'è modo di cercare la stringa esatta invece delle varie parole ? :·: si possono usare regex ?

questa search si esegue su tutte le mail in INBOX, lette o non-lette: :·: c'è modo di restringerla a quelle UNREAD ?
Se no, dopo aver scaricato le mail desiderate lo script dovrebbe 'archiviarle' per non ritrovarsele alla successiva passata

La webGmail mostra anche il testo della PEC originale ma il testo restituito da fetch non comprende il messaggio PEC originale: è incluso in un allegato che si chiama sempre Comunicazione.xml : :·: come ci si arriva?
Rispondo velocissimamente in quanto ho i minuti contati, stasera se la famiglia mi concede guardo meglio la situazione.

case sesitive, no, mi sembra proprio che sia specificatamente case-insensitive...
ma non scoraggiarti :D se guardi il mio precedente post trovi un link al rfc... mi sembra a pagina 49 trovi le risposte alle SEARCH (ed anche SEEN/UNSEEN)

Guardo meglio stasera, scusa
Max
Vedo di buttare giu' uno schizzo (penso 1/2 ora con qualche test). Ho bisogno *comunque* maggiori info da te.

Come avrai sicuramente visto, nel rfc non hai le regex, quindi dovresti cercare di "raffinare" la ricerca il piu' possibile con quello che offre il protocollo.
Se proprio hai bisogno regex, la si fa *eventualmente* dopo la prima selezione (se proprio e' indispensabile).

A dopo,
Max
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

Vabbè va... e' solo uno schizzo. Giusto per fare qualche prova

Codice: Seleziona tutto

#! /usr/bin/env python
import sys
import datetime
import socket, imaplib, email

#
# SET ME PLEASE
# vvvvvvvvvvvvvvvvvvvv
HOST = 'imap.gmail.com'
USER = 'user@gmail.com'
PASS = 'password'
# prefered attachement multiparts tuple (FIXME ?? WTF ANALYSIS ??)
PARTS = ('foo','bar')
# ^^^^^^^^^^^^^^^^^^^^
#
# default
MAILBOX = 'INBOX'
SSL = True
VERBOSE = True
#
#

#
# connect host
#
try:
    if SSL:
        imap = imaplib.IMAP4_SSL(HOST)
    else:
        imap = imaplib.IMAP4(HOST)
except socket.error, e:
    print ("socket.error: %s\n" % e)
    sys.exit(1)

#
# login
#
try:
    result, data = imap.login(USER, PASS)
except imaplib.IMAP4.error, e:
    print ("imaplib.IMAP4.error: %s\n" % e)
    sys.exit(1)
if result != "OK":
    print ("login fault: %s\n" % result)
    sys.exit(1)
if VERBOSE:
    print (data)

#
# select mailbox folder
#
result, data = imap.select(MAILBOX, readonly=True)
if result != "OK":
    print ("Error select: %s" % data)
    result, data = imap.list()
    if result == "OK":
        print ("Availables mailbox:")
        for i in data:
            print i
    print ("\nPlease, correct MAILBOX. Exit with error")
    imap.logout()
    sys.exit(1)

# got count of messages (?? WTF ??)
nmail = int(data[0])
if VERBOSE:
    print ("You have %d messages in %s\n" % (nmail, MAILBOX))

#
# searching
# argv[n] as criterion string else "ALL"
if len(sys.argv) > 1:
    search = " ".join(sys.argv[1:])
else:
    search = "ALL"
search = '('+search+')'
if VERBOSE:
    print ("imap.uid('search', None, %s)" % search)
try:
    result, data = imap.uid('search', None, search)
except imaplib.IMAP4.error, e:
    print (search);
    print (e)
    sys.exit(1)
if result != "OK":
    printf ("Search return something wrong. Sorry, exit with error\n")
    sys.exit(1)

#
# fetching
#
list_mail=data[0].split()
if VERBOSE:
    print ("Your search returned %d  messages" % len(list_mail))

for uid in list_mail:
    result, data = imap.uid('fetch', uid, '(RFC822)')
    if result != "OK":
        # FIXME
        continue

    mail = email.message_from_string(data[0][1])

    if VERBOSE:
        print ("Date     : %s" % mail['Date'])
        print ("From     : %s" % mail['From'])
        print ("To       : %s" % mail['To'])
        print ("Subject  : %s" % mail['Subject'])

    # FIXME WHAT FUCKING WRITE HERE! MISSING ANAL...YSIS
    if mail.is_multipart():
        for part in mail.walk():
            type_ext = part.get_content_type()
            filename = part.get_filename()
            if filename:
                if VERBOSE:
                    print ("%s ==> %s" % (type_ext, filename))
                if type_ext in PARTS:
                    open(filename, 'wb').write(part.get_payload(decode=True))
    if VERBOSE:
        print

#End For
imap.close()
imap.logout()
sys.exit(0)
time && test:

Codice: Seleziona tutto

% time ./foo.py seen from "Diana" SINCE 1-Jan-2013 text "jpg"
['xxxxxxxx@gmail.com xxxxxxxxxxxxxxxxxxxxx authenticated (Success)']
You have 543 messages in INBOX

imap.uid('search', None, (seen from Diana SINCE 1-Jan-2010 text jpg))
Your search returned 1  messages
Date     : Sun, 10 Feb 2013 15:29:25 +0000 (GMT)
From     : Diana xxxxxxxxxx <xxxxxxxxxxxxxxx@xxxxxxxxxxxxxx>
To       : Max <xxxxxx@gmail.com>
Subject  : =?iso-8859-1?Q?photoshop_o_realt=E0=3F?=
image/jpeg ==> universe.jpg


real	0m4.882s
user	0m0.060s
sys	0m0.012s

%
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

purtroppo non sono veloce se faccio da me, ottengo questo ( ho messo UNSEEN per semplificare e ridurre l'output )

Codice: Seleziona tutto

$ ./foo.py UNSEEN
['xxxxx@gmail.com xxxxx xxxxx authenticated (Success)']
You have 17 messages in INBOX

imap.uid('search', None, (UNSEEN))
Your search returned 1  messages
Date     : Tue, 25 Mar 2014 16:45:23 +0100 (CET)
From     : xxxxx.xxxxx@pec.it
To       : xxxxx@gmail.com
Subject  : Fwd: POSTA CERTIFICATA: COMUNICAZIONE 2677/2014/LAV
application/xml ==> daticert.xml
message/rfc822 ==> postacert.eml
text/xml ==> IndiceBusta.xml
text/xml ==> Comunicazione.xml
application/x-pkcs7-signature ==> smime.p7s
ovviamente le mail che cerchiamo sono multipart, ma non ho capito in questo caso la tupla PARTS cosa deve rappresentare: pensavo di doverci mettere il Content-Type dell'allegato che serve (text/xml) ma evidentemente no, dato che qualsiasi cosa ci ho messo non cambia niente... need help
fammi sapere cosa altro ti serve sapere per aiutarmi. Da parte mia prometto di studiarmi tutti i moduli che non conosco che useremo (cosa che faccio comunque sempre)

per ogni evenienza posto il file xml da parsare: la parte interessante sta tra i tag <contenuto>

EDIT Sicuramente per miei limiti, non capisco un'altra cosa: quando apri il file in scrittura, dove dovrebbe venire salvato ? anzi, dato che lo apri senza la sintassi with, non dovresti fare il file.close() ?
Allegati
Comunicazione.xml
(657 Byte) Scaricato 60 volte
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

rai ha scritto: ovviamente le mail che cerchiamo sono multipart, ma non ho capito in questo caso la tupla PARTS cosa deve rappresentare: pensavo di doverci mettere il Content-Type dell'allegato che serve (text/xml) ma evidentemente no, dato che qualsiasi cosa ci ho messo non cambia niente... need help
Quando sei all'oscuro su quello che devi realmente fare predisponi certe vie che possono anche non corrispondere alle reali esigenze.
La tupla e' stata concepita come filtro allegati multipart e viene poi gestita in un unico punto sulla write. Ma la write non posso sapere se ti serve.
Per cui la modifica, se ho capito bene, consiste nel definire il ctype multipart TEXT/XML:

Codice: Seleziona tutto

...
PARTS = ('text/xml','bar')
...
In fondo allo script si limita a salvarlo localmente (si manca la close, ho visto) e non so se serve o bisogna solo parsare il contenuto:

Codice: Seleziona tutto

...
part.get_payload(decode=True)
...
Questo io non lo posso *immaginare*, come del resto non mi e' chiaro se bisogna parsare *tutti gli allegati* o solo "Comunicazione.xml".
E' poi cosa devi parsare, cosa devi ottenere? Se chiedo informazioni devi fare TU l'analisi di quello che vuoi ottenere...
Questo e' quello che lo script fa attualmente:

Codice: Seleziona tutto

% rm Comunicazione.xml 
% ./foo.py 'UNSEEN FROM "MAX"'
['xxxxxxxx@gmail.com xxxxxxxxxxxxxxxxx authenticated (Success)']
You have 545 messages in INBOX

imap.uid('search', None, (UNSEEN FROM "MAX"))
Your search returned 1  messages
Date     : Fri, 11 Apr 2014 11:28:32 +0200
From     :xxxxxxxxxx <xxxxxxxxx@gmail.com>
To       :xxxxxxxxxxxx <xxxxxxxxx@gmail.com>
Subject  : prova multipart forum programmazione
text/xml ==> Comunicazione.xml

% ll Comunicazione.xml
-rw-r--r-- 1 me me 657 apr 11 12:14 Comunicazione.xml
poi, leggendo un esempio da https://docs.python.org/2/library/xml.e ... ttree.html:

Codice: Seleziona tutto

% python
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import xml.etree.ElementTree as ET
>>> tree = ET.parse('Comunicazione.xml')
>>> root = tree.getroot()
>>> for child in root:
...  print child.tag, child.text
... 
NumeroRuolo xxxx/2014/LAV
Oggetto FISSAZIONE UDIENZA DI COMPARIZIONE PARTI
Contenuto --
Comunicazione di cancelleria
Sez/Coll.: LA

Tipo procedimento: Diritto del Lavoro
Numero di Ruolo generale: xxxx/2014
Giudice: xxx xxx
Ricorr. principale: xxx xxx
Resist. principale: xxx 

Oggetto: FISSAZIONE UDIENZA DI COMPARIZIONE PARTI
Descrizione: FISSATA UDIENZA DI COMPARIZIONE PARTI IL xxx 09:00 NOMINATO CTU xxx xxx


Note: 

Notificato alla PEC / in cancelleria il xxx 12:10
Registrato da xxx
--

CodiceUG 0820530098
CodiceFiscaleDestinatario xxxxxxxxx
>>>  quit()
% _
Ciao,
Max
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

grazie Max, ricevuto.
appena possibile ( stasera? ) cerco di risponderti dopo aver fatto qualche prova
Ciao,
Rai
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

Scusa rai,
stavo rileggendo l'intero 3d e mi era sfuggita questa tua affermazione:
rai ha scritto: La webGmail mostra anche il testo della PEC originale ma il testo restituito da fetch non comprende il messaggio PEC originale: è incluso in un allegato che si chiama sempre Comunicazione.xml : :·: come ci si arriva?
Se cosi' fosse, sarebbe opportuno restringere la ricerca inziale con:

Codice: Seleziona tutto

%  ./foo.py 'UNSEEN TEXT "comunicazione.xml"'
Ciao
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

Nope
purtroppo arrivano messaggi con 'Comunicazioni.xml' che non contengono i dati che mi servono. Bada bene che se è un casino filtrare ulteriormente le mail, non è un problema fetchare tutte quelle che contengono Comunicazione.xml e poi la greppata la faccio in locale. Il fatto è che ancora non ho capito :muro: come dovrebbe arrivare il contenuto di questi allegati nella mia shell :nono: mi spiace sono di coccio
ixamit ha scritto: Quando sei all'oscuro su quello che devi realmente fare predisponi certe vie che possono anche non corrispondere alle reali esigenze.
scusa, ho una specie di afasia e non riesco a selezionare le info necessarie da quelle superflue
rai ha scritto:per ogni evenienza posto il file xml da parsare: la parte interessante sta tra i tag <contenuto>
quello che devo fare è: appena possibile, dopo l'arrivo della mail, devo predisporre dei documenti odt. Per farlo voglio estrarre determinate substringhe da <contenuto> per metterle nei campi che per ora riempo a manina . . .
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: filtrare le mail prima di scaricarle

Messaggio da ixamit »

rai ha scritto: Nope
purtroppo arrivano messaggi con 'Comunicazioni.xml' che non contengono i dati che mi servono. Bada bene che se è un casino filtrare ulteriormente le mail, non è un problema fetchare tutte quelle che contengono Comunicazione.xml e poi la greppata la faccio in locale. Il fatto è che ancora non ho capito :muro: come dovrebbe arrivare il contenuto di questi allegati nella mia shell :nono: mi spiace sono di coccio

Il primo punto e' la selezione iniziale delle mail da leggere e qui' devi per forza di cose utilizzare la SEARCH del protocollo, magari con piu' chiavi tipo UNSEEN, FROM, SINCE e TEXT. Questo ovviamente per restringere il campo FETCH e ridurre i tempi.

Ora puoi:
1) scaricare/visualizzare localmente *solo* l'allegato ctype == 'TEXT/XML' che contiene il tag <Contenuto>
2) scaricare/visualizzare localmente il testo contenuto all'interno del tag <Contenuto>
3) Applicare una regex sul testo al punto 2

Prova con questa versione leggermente modificata seguendo l'opzione 2:

Codice: Seleziona tutto

#! /usr/bin/env python
import sys
import datetime
import socket, imaplib, email
import xml.etree.ElementTree as ET
#
# SET ME PLEASE
# vvvvvvvvvvvvvvvvvvvv
HOST = 'imap.gmail.com'
USER = 'user@gmail.com'
PASS = 'password'
CONTENT = './Contenuto'
# ^^^^^^^^^^^^^^^^^^^^
#
# default
MAILBOX = 'INBOX'
SSL = True
VERBOSE = False
#
#

#
# connect host
#
try:
    if SSL:
        imap = imaplib.IMAP4_SSL(HOST)
    else:
        imap = imaplib.IMAP4(HOST)
except socket.error, e:
    print ("socket.error: %s\n" % e)
    sys.exit(1)

#
# login
#
try:
    result, data = imap.login(USER, PASS)
except imaplib.IMAP4.error, e:
    print ("imaplib.IMAP4.error: %s\n" % e)
    sys.exit(1)
if result != "OK":
    print ("login fault: %s\n" % result)
    sys.exit(1)
if VERBOSE:
    print (data)

#
# select mailbox folder
#
result, data = imap.select(MAILBOX, readonly=True)
if result != "OK":
    print ("Error select: %s" % data)
    result, data = imap.list()
    if result == "OK":
        print ("Availables mailbox:")
        for i in data:
            print i
    print ("\nPlease, correct MAILBOX. Exit with error")
    imap.logout()
    sys.exit(1)

# got count of messages (?? WTF ??)
nmail = int(data[0])
if VERBOSE:
    print ("You have %d messages in %s\n" % (nmail, MAILBOX))

#
# searching
# argv[n] as criterion string else "ALL"
if len(sys.argv) > 1:
    search = " ".join(sys.argv[1:])
else:
    search = "ALL"
search = '('+search+')'
if VERBOSE:
    print ("imap.uid('search', None, %s)" % search)
try:
    result, data = imap.uid('search', None, search)
except imaplib.IMAP4.error, e:
    print (search);
    print (e)
    sys.exit(1)
if result != "OK":
    printf ("Search return something wrong. Sorry, exit with error\n")
    sys.exit(1)

#
# fetching
#
list_mail=data[0].split()
if VERBOSE:
    print ("Your search returned %d  messages" % len(list_mail))

for uid in list_mail:
    result, data = imap.uid('fetch', uid, '(RFC822)')
    if result != "OK":
        # FIXME
        continue

    mail = email.message_from_string(data[0][1])

    if VERBOSE:
        print ("Date     : %s" % mail['Date'])
        print ("From     : %s" % mail['From'])
        print ("To       : %s" % mail['To'])
        print ("Subject  : %s" % mail['Subject'])

    # FIXME WHAT FUCKING WRITE HERE! MISSING ANAL...YSIS
    if mail.is_multipart():
        for part in mail.walk():
            type_ext = part.get_content_type()
            filename = part.get_filename()
            if filename:
                if VERBOSE:
                    print ("%s ==> %s" % (type_ext, filename))
                if type_ext == 'text/xml':
                    # open(filename, 'wb').write(part.get_payload(decode=True))
                    #
                    root = ET.fromstring(part.get_payload(decode=True))
                    content = root.findall(CONTENT)
                    if content:
                        for elem in content:
                            print elem.text
    if VERBOSE:
        print

#End For
imap.close()
imap.logout()
sys.exit(0)
PS Ho messo VERBOSE = False

Codice: Seleziona tutto

max@studio:~/foo$ time ./foo.py 'UNSEEN FROM "MAX" SINCE 10-Apr-2014'
--
Comunicazione di cancelleria
Sez/Coll.: LA

Tipo procedimento: Diritto del Lavoro
Numero di Ruolo generale: xxxx/2014
Giudice: xxx xxx
Ricorr. principale: xxx xxx
Resist. principale: xxx 

Oggetto: FISSAZIONE UDIENZA DI COMPARIZIONE PARTI
Descrizione: FISSATA UDIENZA DI COMPARIZIONE PARTI IL xxx 09:00 NOMINATO CTU xxx xxx


Note: 

Notificato alla PEC / in cancelleria il xxx 12:10
Registrato da xxx
--


real	0m2.692s
user	0m0.052s
sys	0m0.012s
max@studio:~/foo$ 

rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: filtrare le mail prima di scaricarle

Messaggio da rai »

direi che siamo vicinissimi alla soluzione: già così facendo

Codice: Seleziona tutto

./foo.py 'unseen TEXT "Comunicazione.xml"' > outfile
ho su disco quello che mi serve

solo mi vengono in mente un paio di cose:

:1: la ricerca può restituire diverse mail (anche *tutte utili*) e il loro contenuto finirebbe nello stesso outfile creando qualche confusione in più a awk/grep. Che faresti? printare un separatore di caratteri non equivoci a inizio e fine di ogni mail?

:2: come dicevo prima, serve fare su tutte le mail fetchate qualcosa del tipo
imap.store(mail_num, '+flags.silent', '\\seen')
imap.store(mail_num, '-flags.silent', '\\unseen')
che non saprei come mettere nello script, dato che tu cicli sugli uid e non sui mail_num

:0: se cortesemente ripulisci lo script dallo stuff non utilizzato, oltre ad aiutarmi avrai avuto un ruolo didattico ;) perché mi verrà più facile studiarmi i vari metodi
grazie veramente per la pazienza
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 12 ospiti