12.2.1 Rappresentazione di un messaggio email

La classe centrale nel package email è la classe Message; è la classe base per il modello dell'oggetto email. Message fornisce le funzionalità basilari per impostare ed interrogare i campi delle intestazioni e per accedere al corpo del messaggio.

Concettualmente, un oggetto Message è composto da headers (NdT: intestazioni) e payloads (NdT: carico utile). Le intestazioni hanno nomi dei campi e valori in stile RFC 2822 dove i nomi dei campi ed i valori sono separati da un due punti. Il due punti non è né parte del nome del campo né del suo valore.

Le intestazioni vengono immagazzinate e restituite in una forma che ne mantiene la sensibilità a maiuscole e minuscole, ma sono fatte corrispondere in modo non sensibile a queste differenze. Può anche esserci una singola intestazione della busta, anche nota come l'intestazione Unix-From o l'intestazione From_. Il carico utile può essere sia una stringa, in caso di semplici oggetti messaggio, sia una lista di oggetti Message per documenti che contengono MIME (per esempio multipart/* e messaggi/rfc822).

Gli oggetti Message forniscono un'interfaccia in stile mappa per accedere alle intestazioni dei messaggi ed una specifica interfaccia per accedere sia alle intestazioni che al carico utile. Fornisce metodi utili per generare una rappresentazione dell'albero degli oggetti di messaggio, per accedere ai parametri delle intestazioni acceduti comunemente e per navigare ricorsivamente nell'albero degli oggetti.

Questi sono i metodi della classe Message:

class Message( )
Il costruttore non accetta argomenti.

as_string( [unixfrom])
Restituisce l'intero messaggio in una stringa. Quando l'argomento facoltativo unixfrom è True, l'intestazione della busta viene inclusa nella stringa restituita. Il valore predefinito di unixfrom è False.

Notare che questo metodo viene fornito per comodità ma non può sempre formattare il messaggio nel modo voluto. Per avere maggiore flessibilità, istanziare un'istanza di Generator ed utilizzare direttamente il suo metodo flatten(). Per esempio:

from cStringIO import StringIO
from email.Generator import Generator
fp = StringIO()
g = Generator(fp, mangle_from_=False, maxheaderlen=60)
g.flatten(msg)
text = fp.getvalue()

__str__( )
Equivalente a as_string(unixfrom=True).

is_multipart( )
Restituisce True se il carico utile del messaggio è una lista di oggetti sotto Message, altrimenti restituisce False. Quando is_multipart() restituisce False, il carico utile deve essere un oggetto di tipo stringa.

set_unixfrom( unixfrom)
Imposta l'intestazione della busta ad unixfrom, che deve essere una stringa.

get_unixfrom( )
Restituisce l'intestazione della busta del messaggio. Il valore predefinito è None se nessuna intestazione della busta è mai stata impostata.

attach( payload)
Aggiunge il carico utile, payload, fornito al carico utile corrente, che deve essere None o una lista di oggetti Message prima della chiamata. Dopo la chiamata, il carico utile sarà sempre una lista di oggetti di tipo Message. Se si vuole impostare il carico utile a un oggetto scalare (tipo una stringa), utilizzare invece set_payload().

get_payload( [i[, decode]])
Restituisce un riferimento al carico utile attuale, che deve essere una lista di oggetti Message quando is_multipart() è True o una stringa quando is_multipart() è False. Se il carico utile è una lista e viene modificato l'oggetto lista si modifica anche il carico utile dell'oggetto.

Con l'argomento facoltativo i, get_payload() restituisce l'i-esimo elemento del carico utile, contando da zero, se is_multipart() è True. Viene sollevata l'eccezione IndexError se i è minore di 0 o maggiore o uguale al numero di oggetti nel carico utile. Se il carico utile è una stringa (is_multipart() è False) e i viene fornito, viene sollevata l'eccezione TypeError.

L'opzione facoltativa decode indica se il carico utile deve essere decodificato o no, in accordo con l'intestazione Content-Transfer-Encoding:. Quando il valore è True ed il messaggio non è multipart, il carico utile viene decodificato se il valore dell'intestazione è "quoted-printable" o "base64". Se altre codifiche vengono utilizzate o l'intestazione Content-Transfer-Encoding: manca o il carico utile ha dati base64 falsi, il carico utile viene restituito così com'è (non decodificato). Se il messaggio è multipart ed l'opzione decode è impostata a True, viene restituito None. Il valore predefinito per decode è False.

set_payload( payload[, charset])
Imposta l'intero carico utile dell'oggetto messaggio a payload. È responsabilità del client assicurare l'invarianza del carico utile. Il charset facoltativo imposta il charset predefinito per il messaggio; vedere set_charset() per i dettagli.

Modificato nella versione 2.2.2: Aggiunto l'argomento charset.

set_charset( charset)
Imposta il charset del carico utile a charset, che può essere sia un'istanza di Charset (vedere email.Charset), sia una stringa che nomina un charset o None. Se è una stringa, verrà convertita ad un'istanza di Charset. Se charset è None, il parametro charset viene rimosso dall'intestazione Content-Type:. Qualunque altra cosa solleva l'eccezione TypeError.

Il messaggio si assume essere di tipo text/* codificato con charset.input_charset. Verrà convertito in charset.output_charset e codificato opportunamente, se necessario, quando verrà generata la rappresentazione in testo del messaggio. Le intestazioni MIME (MIME-Version:, Content-Type:, Content-Transfer-Encoding:) verranno aggiunte quando necessario.

Nuovo nella versione 2.2.2.

get_charset( )
Restituisce l'istanza di Charset associata al carico utile del messaggio. Nuovo nella versione 2.2.2.

I seguenti metodi implementano un'interfaccia in stile mappa per accedere alle intestazioni RFC 2822 del messaggio. Si noti che ci sono alcune differenze semantiche tra questi metodi e l'interfaccia delle normali mappe (dizionari). Per esempio, in un dizionario non ci sono chiavi duplicate, ma qui ci possono essere intestazioni duplicate. Inoltre, nei dizionari non c'è garanzia di ordinamento per le chiavi restituite da keys(), ma in un oggetto Message, le intestazioni vengono sempre restituite nell'ordine in cui appaiono nel messaggio originale, o aggiunte al messaggio in seguito. Ogni intestazione cancellata e poi reinserita viene sempre aggiunta alla fine della lista delle intestazioni.

Queste differenze semantiche sono intenzionali e sono polarizzate verso la massima convenienza.

Notare che in tutti i casi, ogni intestazione della busta presente nel messaggio non viene inclusa nella mappa di interfaccia.

__len__( )
Restituisce il numero totale delle intestazioni, incluse quelle duplicate.

__contains__( name)
Restituisce True se l'oggetto messaggio ha un campo chiamato name. La corrispondenza viene effettuata in modo non sensibile alle differenze tra maiuscole e minuscole e name non deve includere i due punti terminali. Utilizzato per l'operatore in, per esempio:

if 'message-id' in myMessage:
    print 'Message-ID:', myMessage['message-id']

__getitem__( name)
Restituisce il valore del campo dell'intestazione nominata. name non deve includere il separatore di campi, i due punti. Se l'intestazione non è presente, viene restituito None; l'eccezione KeyError non viene mai sollevata.

Notare che se il campo nominato appare più di una volta nelle intestazioni del messaggio, non è definito quale di questi verrà restituito. Utilizzare il metodo get_all() per ottenere i valori di tutte le intestazioni nominate.

__setitem__( name, val)
Aggiunge una intestazione al messaggio con il campo chiamato name ed il valore val. Il campo viene aggiunto alla fine della lista dei campi del messaggio esistenti.

Notare che questo non sovrascrive o cancella nessuna intestazione esistente con lo stesso nome. Se si vuole l'assicurazione che la nuova intestazione sia l'unica presente nel messaggio con quel nome di campo, cancellare il campo prima dell'inserimento, per esempio:

del msg['subject']
msg['subject'] = 'Python roolz!'

__delitem__( name)
Cancella tutte le occorrenze del campo con il nome name dalle intestazioni del messaggio. Non viene sollevata alcuna eccezione se il nome del campo non è presente nelle intestazioni.

has_key( name)
Restituisce True se il messaggio contiene nell'intestazione un campo chiamato name, altrimenti restituisce False.

keys( )
Restituisce una lista di tutti i nomi dei campi delle intestazioni del messaggio.

values( )
Restituisce una lista di tutti i valori dei campi del messaggio.

items( )
Restituisce una lista di tuple di 2 elementi contenenti tutte le intestazioni ed i valori dei campi del messaggio.

get( name[, failobj])
Restituisce il valore dei campi delle intestazioni nominate. Questo è identico a __getitem__() ad eccezione che l'argomento facoltativo failobj viene restituito se non è presente l'intestazione nominata (il cui valore predefinito è None).

Qui di seguito altri metodi utili:

get_all( name[, failobj])
Restituisce una lista di tutti i valori per il campo chiamato name. Se non c'è questa intestazione nel messaggio, viene restituito failobj (il cui valore predefinito è None).

add_header( _name, _value, **_params)
Impostazione avanzata delle intestazioni. Questo metodo è simile a __setitem__() ad eccezione che i parametri addizionali dell'intestazione possono essere forniti come argomenti chiave. _name è il campo dell'intestazione da aggiungere e _value è il valore primario per l'intestazione.

Per ogni oggetto nel dizionario degli argomenti di tipo keyword _params, la chiave viene presa come il nome del parametro, con i caratteri di trattino basso convertiti in punti (poiché i punti sono illegali come identificatori Python). Normalmente, il parametro viene aggiunto come chiave="valore" a meno che value non sia None, in tal caso solo la chiave verrà aggiunta.

Ecco un esempio:

msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')

Questo aggiunge un'intestazione che avrà questa forma:

Content-Disposition: attachment; filename="bud.gif"

replace_header( _name, _value)
Sostituisce un header. Sostituisce la prima intestazione trovata nel messaggio che corrisponde a _name, mantenendo l'ordine delle intestazioni e maiuscole/minuscole dei nomi dei campi. Se non ci sono intestazioni corrispondenti, viene sollevata l'eccezione KeyError.

Nuovo nella versione 2.2.2.

get_content_type( )
Restituisce il content type (NdT: tipologia del contenuto) del messaggio. La stringa restituita viene convertita in minuscolo nella forma maintype/subtype. Se nel messaggio non c'è l'intestazione Content-Type:, viene restituito il tipo predefinito, come specificato da get_default_type(). In accordo con l'RFC 2045, i messaggi hanno sempre un content type predefinito, per questo get_content_type() restituisce sempre un valore.

La RFC 2045 definisce il tipo predefinito del messaggio come text/plain (NdT: puro testo), a meno che non appaia all'interno di un contenitore multipart/digest, in tal caso sarà message/rfc822. Se l'intestazione Content-Type: ha una specifica errata per il tipo, la RFC 2045 stabilisce che il tipo predefinito sia text/plain.

Nuovo nella versione 2.2.2.

get_content_maintype( )
Restituisce il content type principale del messaggio. Questa è la parte maintype della stringa restituita da get_content_type().

Nuovo nella versione 2.2.2.

get_content_subtype( )
Restituisce il sotto content type del messaggio. Questa è la parte subtype della stringa restituita da get_content_type().

Nuovo nella versione 2.2.2.

get_default_type( )
Restituisce il content type predefinito. La maggior parte dei messaggi hanno un content type predefinito text/plain, ad eccezione dei messaggi che sono sotto parti di un contenitore multipart/digest. Questa sotto parte ha un content type predefinito message/rfc822.

Nuovo nella versione 2.2.2.

set_default_type( ctype)
Imposta il content type predefinito. ctype deve essere text/plain o message/rfc822, altrimenti non viene fatto rispettare. Il content type predefinito non viene immagazzinato nell'intestazione Content-Type:.

Nuovo nella versione 2.2.2.

get_params( [failobj[, header[, unquote]]])
Restituisce il parametro Content-Type: del messaggio come una lista. Gli elementi della lista restituita sono delle tuple di 2 elementi costituiti da coppie chiave/valore, derivate dallo split dei valori separati dal segno "=". La parte a sinistra del segno "=" è la chiave, la parte a destra è il valore. Se non c'è il segno "=" nel parametro, il valore è una stringa vuota, altrimenti il valore è come descritto da get_param() ed è non quotato se l'argomento facoltativo unquote è True (il valore predefinito).

L'argomento facoltativo failobj è l'oggetto restituito se non c'è l'intestazione Content-Type:. L'argomento facoltativo header è l'intestazione da ricercare al posto di Content-Type:.

Modificato nella versione 2.2.2: aggiunto l'argomento unquote.

get_param( param[, failobj[, header[, unquote]]])
Restituisce il valore del parametro param dell'intestazione Content-Type: come una stringa. Se il messaggio non ha un'intestazione Content-Type: o se non c'è questo parametro, viene restituito failobj (il valore predefinito è None).

Se viene fornito l'argomento facoltativo header, specifica l'intestazione del messaggio da utilizzare al posto di Content-Type:.

Le chiavi dei parametri sono sempre confrontate in modo non sensibile alle differenze tra maiuscole e minuscole. Il valore restituito può essere una stringa o una tupla di 3 elementi se il parametro è codificato secondo la RFC 2231. Quando è una tupla di 3 elementi, gli elementi del valore sono nella forma (CHARSET, LANGUAGE, VALUE). Notare che siaCHARSET che LANGUAGE possono essere None, in qual caso doveva considerare VALUE come codificato nel charset us-ascii. Si può generalmente ignorare LANGUAGE.

Un'applicazione deve essere pronta a gestire i valori restituiti come tuple di 3 elementi, e deve poter convertire il parametro in una stringa Unicode, tipo:

param = msg.get_param('foo')
if isinstance(param, tuple):
    param = unicode(param[2], param[0] or 'us-ascii')

In ogni caso, il parametro value (sia restituito come stringa o l'oggetto VALUE nella tupla di 3 elementi) è sempre non quotato, a meno che unquote non sia impostato a False.

Modificato nella versione 2.2.2: aggiunto l'argomento unquote e la tupla di 3 elementi restituisce i valori possibili.

set_param( param, value[, header[, requote[, charset[, language]]]])

Imposta un parametro nell'intestazione Content-Type:. Se il parametro esiste nell'intestazione, il valore viene sostituito con value. Se l'intestazione Content-Type: non è ancora stata definita per questo messaggio, viene impostata a text/plain, ed il nuovo parametro viene aggiunto in coda come per l'RFC 2045.

L'header facoltativo specifica un'intestazione alternativa a Content-Type: e tutti i parametri verranno quotati come necessario a meno che il facoltativo requote sia False (il valore predefinito è True).

Se il facoltativo charset viene specificato, il parametro verrà codificato secondo l'RFC 2231. Il facoltativo language specifica la lingua secondo la RFC 2231, il valore predefinito è la stringa vuota. Sia charset che language devono essere stringhe.

Nuovo nella versione 2.2.2.

del_param( param[, header[, requote]])
Rimuove completamente il parametro fornito dall'intestazione Content-Type:. L'intestazione viene riscritta in linea senza il parametro o il suo valore. Tutti i valori verranno quotati se necessario, a meno che requote sia False (il valore predefinito è True). Il facoltativo header specifica un'alternativa a Content-Type:.

Nuovo nella versione 2.2.2.

set_type( type[, header][, requote])
Imposta il tipo principale e il sotto tipo per l'intestazione Content-Type:. type dev'essere una stringa nella forma maintype/subtype, altrimenti viene sollevata un'eccezione ValueError.

Questo metodo sostituisce l'intestazione Content-Type:, mantenendo tutti i parametri in linea. Se requote è False, questo lascia la quotatura esistente delle intestazioni invariata, altrimenti il parametro verrà quotato (il comportamento predefinito).

Un'intestazione alternativa può essere specificata nell'argomento header. Quando l'intestazione Content-Type: viene impostata, viene anche aggiunta un'intestazione MIME-Version:.

Nuovo nella versione 2.2.2.

get_filename( [failobj])
Restituisce il valore del parametro filename dell'intestazione Content-Disposition: del messaggio o failobj se l'intestazione è assente o non ha un parametro filename. Alla stringa restituita viene sempre rimossa la quotatura come da Utils.unquote().

get_boundary( [failobj])
Restituisce il valore del parametro boundary (NdT: limite) dell'intestazione Content-Type: del messaggio o failobj se l'intestazione è assente o non ha un parametro boundary. Alla stringa restituita viene sempre rimossa la quotatura come da Utils.unquote().

set_boundary( boundary)
Imposta il parametro boundary dell'intestazione Content-Type: a boundary. set_boundary() quoterà sempre boundary se necessario. Viene sollevata l'eccezione HeaderParseError se l'oggetto del messaggio non contiene l'intestazione Content-Type:.

Notare che usare questo metodo è sottilmente differente che non cancellare la vecchia intestazione Content-Type: ed aggiungerne una nuova con il nuovo boundary tramite add_header(), poiché set_boundary() mantiene l'ordine dell'intestazione Content-Type: nella lista delle intestazioni. Comunque, non mantiene alcuna soluzione di continuità che poteva essere presente nell'intestazione Content-Type: originale.

get_content_charset( [failobj])
Restituisce il parametro charset dell'intestazione Content-Type: convertito in minuscolo. Se non c'è un'intestazione Content-Type: o se questa intestazione non ha un parametro charset viene restituito failobj.

Notare che questo metodo differisce da get_charset() che restituisce l'istanza di Charset per la codifica predefinita per il corpo del messaggio.

Nuovo nella versione 2.2.2.

get_charsets( [failobj])
Restituisce una lista contenente il nome dell'insieme di caratteri nel messaggio. Se il messaggio è multipart, la lista conterrà un elemento per ogni sotto parte del carico utile, altrimenti restituirà una lista di lunghezza 1.

Ogni elemento nella lista sarà una stringa corrispondente al valore del parametro charset dell'intestazione Content-Type: per la sotto parte rappresentata. Comunque, se la sotto parte non ha un header Content-Type:, non ha un parametro charset o non è il text del tipo MIME principale, l'elemento nella lista restituita sarà failobj.

walk( )
Il metodo walk() è un generatore generico che può essere utilizzato per iterare su tutte le parti e le sotto parti dell'albero degli oggetti del messaggio, in ordine di attraversamento in profondità. Tipicamente si utilizzerà walk() come iteratore in un ciclo for; ogni iterazione restituisce la prossima sotto parte.

Ecco un esempio che stampa il tipo di MIME di tutte le parti di una struttura di messaggio multipart:

>>> for part in msg.walk():
>>>     print part.get_content_type()
multipart/report
text/plain
message/delivery-status
text/plain
text/plain
message/rfc822

Gli oggetti Message possono, facoltativamente, contenere due attributi delle istanze, che possono essere utilizzate quando si genera la versione testuale di un messaggio MIME.

preamble
Il formato di un documento MIME permette che in alcuni testi possano essere presenti righe vuote che seguono le intestazioni, e la prima stringa del limite multipart. Normalmente, questo testo non è visibile in una lettore di mail capace di comprendere i MIME, poiché cade al di fuori dello standard MIME. Comunque, quando si visualizza il testo grezzo del messaggio o quando si visualizza il messaggio in un lettore che non comprende i MIME, questo testo può diventare visibile.

L'attributo preamble contiene questo testo iniziale, fuori dagli standard, per il documento MIME. Quando l'analizzatore (Parser) scopre del testo dopo le intestazioni ma prima della prima stringa di limite, assegna questo testo all'attributo preamble. Quando il generatore Generator sta scrivendo la rappresentazione in testo del messaggio MIME, e vede che il messaggio ha un attributo preamble, scriverà questo testo nell'area tra le intestazioni ed il primo limite. Vedere email.Parser ed email.Generator per i dettagli.

Notare che se l'oggetto messaggio non ha un preambolo, l'attributo preamble varrà None.

epilogue
L'attributo epilogue agisce nello stesso modo dell'attributo preamble, ad eccezione che contiene il testo che compare tra l'ultimo limite e la fine del messaggio.

Una nota: quando si genera la versione testuale di un messaggio multipart che non ha epilogue (utilizzando la classe standard Generator), nessun fine riga viene aggiunto dopo la riga del limite di chiusura. Se nell'oggetto del messaggio è presente epilogue e questo valore non inizia con un fine riga, un fine riga viene stampato dopo il limite di chiusura. Questo parrebbe un po' malcostruito, ma è la cosa più logica. Il risultato è che se si vuole assicurare che un fine riga sia stampato dopo il limite di chiusura del multipart, si deve impostare epilogue ad una stringa vuota.



Subsections
Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.