Python: Cómo analizar el cuerpo de un correo electrónico sin procesar, dado que el correo electrónico sin formato no tiene una etiqueta de “Cuerpo” o algo así

Parece fácil conseguir el

From To Subject 

etc via

 import email b = email.message_from_string(a) bbb = b['from'] ccc = b['to'] 

asumiendo que "a" es la cadena de correo electrónico sin formato que se parece a esto.

 a = """From root@a1.local.tld Thu Jul 25 19:28:59 2013 Received: from a1.local.tld (localhost [127.0.0.1]) by a1.local.tld (8.14.4/8.14.4) with ESMTP id r6Q2SxeQ003866 for ; Thu, 25 Jul 2013 19:28:59 -0700 Received: (from root@localhost) by a1.local.tld (8.14.4/8.14.4/Submit) id r6Q2Sxbh003865; Thu, 25 Jul 2013 19:28:59 -0700 From: root@a1.local.tld Subject: oooooooooooooooo To: ooo@a1.local.tld Cc: X-Originating-IP: 192.168.15.127 X-Mailer: Webmin 1.420 Message-Id:  Date: Thu, 25 Jul 2013 19:28:59 -0700 (PDT) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="bound1374805739" This is a multi-part message in MIME format. --bound1374805739 Content-Type: text/plain Content-Transfer-Encoding: 7bit ooooooooooooooooooooooooooooooooooooooooooooooo ooooooooooooooooooooooooooooooooooooooooooooooo ooooooooooooooooooooooooooooooooooooooooooooooo --bound1374805739--""" 

LA PREGUNTA

¿Cómo se obtiene el Body de este correo electrónico a través de python?

Hasta ahora, este es el único código que conozco, pero todavía no lo he probado.

 if email.is_multipart(): for part in email.get_payload(): print part.get_payload() else: print email.get_payload() 

¿Es esta la manera correcta?

O tal vez hay algo más simple como …

 import email b = email.message_from_string(a) bbb = b['body'] 

?

Utilice Message.get_payload

 b = email.message_from_string(a) if b.is_multipart(): for payload in b.get_payload(): # if payload.is_multipart(): ... print payload.get_payload() else: print b.get_payload() 

Para ser altamente positivo, trabaja con el cuerpo del correo electrónico real (aún así, con la posibilidad de que no esté analizando la parte correcta), debe omitir los archivos adjuntos y concentrarse en la parte simple o html (según sus necesidades) para obtener más información. tratamiento.

Como los archivos adjuntos mencionados anteriormente pueden y muy a menudo son parte de texto / sin formato o texto / html, esta muestra no a prueba de viñetas los omite al verificar el encabezado de disposición de contenido:

 b = email.message_from_string(a) body = "" if b.is_multipart(): for part in b.walk(): ctype = part.get_content_type() cdispo = str(part.get('Content-Disposition')) # skip any text/plain (txt) attachments if ctype == 'text/plain' and 'attachment' not in cdispo: body = part.get_payload(decode=True) # decode break # not multipart - ie plain text, no attachments, keeping fingers crossed else: body = b.get_payload(decode=True) 

Por cierto, walk() recorre maravillosamente las partes de mimo, y get_payload(decode=True) realiza el trabajo sucio en la deencoding de la base64, etc.

Algunos antecedentes, como lo insinué, el maravilloso mundo de los correos electrónicos de MIME presenta muchos escollos de encontrar “erróneamente” el cuerpo del mensaje. En el caso más simple, está en la única parte “text / plain” y get_payload () es muy tentador, pero no vivimos en un mundo simple: a menudo está rodeado de contenido multiparte / alternativo, relacionado, mixto, etc. Wikipedia lo describe con precisión – MIME , pero considerando que todos los casos a continuación son válidos – y en general – uno tiene que considerar las redes de seguridad en todos los aspectos:

Muy común: casi todo lo que se obtiene en el editor normal (Gmail, Outlook) que envía texto con formato con un archivo adjunto:

 multipart/mixed | +- multipart/related | | | +- multipart/alternative | | | | | +- text/plain | | +- text/html | | | +- image/png | +-- application/msexcel 

Relativamente simple – solo representación alternativa:

 multipart/alternative | +- text/plain +- text/html 

Para bien o para mal, esta estructura también es válida:

 multipart/alternative | +- text/plain +- multipart/related | +- text/html +- image/jpeg 

Espero que esto ayude un poco.

PD: Mi punto es que no te acerques al correo electrónico a la ligera: se muerde cuando menos lo esperas 🙂

No hay b['body'] en python. Tienes que usar get_payload.

 if isinstance(mailEntity.get_payload(), list): for eachPayload in mailEntity.get_payload(): ...do things you want... ...real mail body is in eachPayload.get_payload()... else: ...means there is only text/plain part.... ...use mailEntity.get_payload() to get the body... 

Buena suerte.

Hay muy buen paquete disponible para analizar el contenido del correo electrónico con la documentación adecuada.

 import mailparser mail = mailparser.parse_from_file(f) mail = mailparser.parse_from_file_obj(fp) mail = mailparser.parse_from_string(raw_mail) mail = mailparser.parse_from_bytes(byte_mail) 

Cómo utilizar:

 mail.attachments: list of all attachments mail.body mail.to 

Si los correos electrónicos son el dataframe de pandas y los correos electrónicos, mida la columna para el texto del correo electrónico

 ## Helper functions def get_text_from_email(msg): '''To get the content from email objects''' parts = [] for part in msg.walk(): if part.get_content_type() == 'text/plain': parts.append( part.get_payload() ) return ''.join(parts) def split_email_addresses(line): '''To separate multiple email addresses''' if line: addrs = line.split(',') addrs = frozenset(map(lambda x: x.strip(), addrs)) else: addrs = None return addrs import email # Parse the emails into a list email objects messages = list(map(email.message_from_string, emails['message'])) emails.drop('message', axis=1, inplace=True) # Get fields from parsed email objects keys = messages[0].keys() for key in keys: emails[key] = [doc[key] for doc in messages] # Parse content from emails emails['content'] = list(map(get_text_from_email, messages)) # Split multiple email addresses emails['From'] = emails['From'].map(split_email_addresses) emails['To'] = emails['To'].map(split_email_addresses) # Extract the root of 'file' as 'user' emails['user'] = emails['file'].map(lambda x:x.split('/')[0]) del messages emails.head() 

Aquí está el código que me funciona cada vez (para correos electrónicos de Outlook):

 #to read Subjects and Body of email in a folder (or subfolder) import win32com.client #import package outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI") #create object #get to the desired folder (MyEmail@xyz.com is my root folder) root_folder = outlook.Folders['MyEmail@xyz.com'].Folders['Inbox'].Folders['SubFolderName'] #('Inbox' and 'SubFolderName' are the subfolders) messages = root_folder.Items for message in messages: if message.Unread == True: # gets only 'Unread' emails subject_content = message.subject # to store subject lines of mails body_content = message.body # to store Body of mails print(subject_content) print(body_content) message.Unread = True # mark the mail as 'Read' message = messages.GetNext() #iterate over mails