2009-09-22 5 views
28

Учитывая сообщение RFC822 в Python 2.6, как я могу получить справа текст/часть простого контента? В принципе, алгоритм я хочу это:Как получить текстовое содержимое сообщения электронной почты с помощью 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 

Из этих вещей, я get_mime_part и has_mime_part вниз погладить, но я не совсем уверен, как получить расшифрованный текст из MIME части. Я могу получить текст в кодируются с помощью get_payload(), но если я пытаюсь использовать параметр метода get_payload()decode (см the doc) Я получаю сообщение об ошибке, когда я вызываю его на текст/равнинной части:

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'> 

Кроме того, я не знаю, как взять HTML и сделать его в тексте максимально близко.

+1

Я нашел полезное решение что-то подобное в http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with- python/ – beldaz

ответ

69

В многостраничной электронной почте email.message.Message.get_payload() возвращает список с одним элементом для каждой части. Самый простой способ ходить сообщение и получить полезную нагрузку на каждую часть:

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 

Для не составного сообщения, нет необходимости делать все ходьбу. Вы можете перейти прямо к get_payload(), независимо от content_type.

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

Если содержание кодируется, вам необходимо передать None в качестве первого параметра get_payload(), а затем True (флаг декодирования является вторым параметром). Например, предположим, что моя электронная почта содержит вложение документов 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() 

Что касается получения разумного открытого текста приближение к HTML части, я обнаружил, что html2text работает довольно чертовски хорошо.

+1

+1, очень четкое и полезное объяснение. –

+0

Это отличное объяснение ... которое охватывает именно то, что у меня уже есть; Я могу, как отмечалось, найти и извлечь полезную нагрузку части. Тем не менее, я не могу декодировать часть, если она декодирована, и я не могу отрисовать текст/html часть текста, если текстовая/простая часть недоступна. –

+0

(при повторном чтении - извините, кофе не хватает!) Хорошо, ладно, поэтому вы решили проблему с текстом в формате HTML :) –

-1

Квартира лучше, чем вложенными;)

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

Это слепо извлекает все «текстовые/простые» части, не обращая внимания на то, что «правильно». – tripleee

+0

@tripleee Обычно мы используем одну обычную, одну часть html и несколько частей изображения. Даже если есть более чем простые части, как вы знаете, какой из них прав? – guneysus

+1

В типичном случае, с одним словом 'multipart/alternative', где только одна часть является« текстовой/простой », другой.В более общем случае я не думаю, что есть один правильный ответ, потому что это зависит от цели вашего приложения и предпочтений получателя. – tripleee