2009-09-22 9 views
28

Dado un mensaje RFC822 en Python 2.6, ¿cómo puedo obtener el derecho parte de texto/contenido simple? Básicamente, el algoritmo que yo quiero es éste:¿Cómo puedo obtener el contenido de texto de un mensaje de correo electrónico usando Python?

message = email.message_from_string(raw_message) 
if has_mime_part(message, "text/plain"): 
    mime_part = get_mime_part(message, "text/plain") 
    text_content = decode_mime_part(mime_part) 
elif has_mime_part(message, "text/html"): 
    mime_part = get_mime_part(message, "text/html") 
    html = decode_mime_part(mime_part) 
    text_content = render_html_to_plaintext(html) 
else: 
    # fallback 
    text_content = str(message) 
return text_content 

de estas cosas, tengo get_mime_part y has_mime_part al dedillo, pero no estoy muy seguro de cómo obtener el texto decodificado de la parte MIME. Puedo obtener el texto codificado usando get_payload(), pero si trato de utilizar el parámetro decode del método get_payload() (ver the doc) me da un error cuando llamo en el texto/parte llana:

File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/email/message.py", line 189, in get_payload 
    raise TypeError('Expected list, got %s' % type(self._payload)) 
TypeError: Expected list, got <type 'str'> 

Además, no sé cómo tomar HTML y presentarlo al texto lo más fielmente posible.

+1

he encontrado una solución útil para algo similar en http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with- python/ – beldaz

Respuesta

69

En un correo electrónico de varias partes, email.message.Message.get_payload() devuelve una lista con un elemento para cada parte. La forma más fácil es caminar el mensaje y obtener la carga útil en cada parte:

import email 
msg = email.message_from_string(raw_message) 
for part in msg.walk(): 
    # each part is a either non-multipart, or another multipart message 
    # that contains further parts... Message is organized like a tree 
    if part.get_content_type() == 'text/plain': 
     print part.get_payload() # prints the raw text 

Para que un mensaje no multiparte, no hay necesidad de hacer todo el pie. Puede ir directamente a get_payload(), independientemente de content_type.

msg = email.message_from_string(raw_message) 
msg.get_payload() 

Si el contenido está codificado, es necesario pasar None como primer parámetro a get_payload(), seguido por True (el indicador de decodificación es el segundo parámetro). Por ejemplo, supongamos que mi correo electrónico contiene un archivo adjunto documento de MS Word:

msg = email.message_from_string(raw_message) 
for part in msg.walk(): 
    if part.get_content_type() == 'application/msword': 
     name = part.get_param('name') or 'MyDoc.doc' 
     f = open(name, 'wb') 
     f.write(part.get_payload(None, True)) # You need None as the first param 
               # because part.is_multipart() 
               # is False 
     f.close() 

En cuanto a conseguir una aproximación razonable de texto plano de una parte HTML, he encontrado que html2text obras bastante maldito también.

+1

+1, explicación muy clara y útil. –

+0

Esa es una excelente explicación ... que cubre exactamente lo que ya obtuve; Puedo, como noté, ubicar y extraer la carga útil de la pieza. Sin embargo, no puedo decodificar la parte si está decodificada, ni puedo representar la parte text/html en el texto si no hay disponible texto/parte normal. –

+0

(en relectura - ¡Lo siento, falta café!) Bueno, está bien, así que resolvió mi problema de HTML a texto :) –

-1

plana es mejor que anidado;)

from email.mime.multipart import MIMEMultipart 
assert isinstance(msg, MIMEMultipart) 

for _ in [k.get_payload() for k in msg.walk() if k.get_content_type() == 'text/plain']: 
    print _ 
+0

Esto extrae ciegamente todas las partes 'text/plain' sin prestar atención a cuál está" correcto ". – tripleee

+0

@tripleee Generalmente utilizamos una parte normal, una parte html y varias partes de la imagen. Incluso si hay más que simples partes, ¿cómo sabes cuál correcto? – guneysus

+1

En el caso típico, con un toplevel 'multipart/alternative' donde solo una parte es' text/plain', esa.En el caso más general, no creo que haya una sola respuesta correcta, ya que depende del propósito de su aplicación y las preferencias del destinatario. – tripleee

Cuestiones relacionadas