पायथन: एक कच्चे ईमेल से बॉडी को पार्स कैसे किया जाए, यह देखते हुए कि कच्चे ईमेल में "बॉडी" टैग या कुछ भी नहीं है


83

इसे प्राप्त करना आसान लगता है

From
To
Subject

आदि के माध्यम से

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

यह मानते हुए कि "a"कच्चे-ईमेल स्ट्रिंग है जो कुछ इस तरह दिखता है।

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 <ooo@a1.local.tld>; 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: <1374805739.3861@a1>
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--"""

प्रश्न

आप Bodyअजगर के माध्यम से इस ईमेल को कैसे प्राप्त करेंगे ?

अब तक यह एकमात्र कोड है जिसके बारे में मुझे पता है लेकिन मुझे अभी इसका परीक्षण करना है।

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

क्या यह सही तरीका है?

या शायद कुछ सरल है जैसे ...

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

?

जवाबों:


95

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()

114

अत्यधिक सकारात्मक होने के लिए आप वास्तविक ईमेल बॉडी के साथ काम करते हैं (फिर भी, अभी भी इस संभावना के साथ कि आप सही भाग को पार्स नहीं कर रहे हैं), आपको अटैचमेंट को छोड़ना होगा, और आगे के लिए सादे या html भाग (अपनी आवश्यकताओं के आधार पर) पर ध्यान केंद्रित करना होगा। प्रसंस्करण।

जैसा कि पहले उल्लेखित अटैचमेंट बहुत बार पाठ / सादे या पाठ / html भाग के होते हैं, यह गैर-बुलेट-प्रूफ नमूना सामग्री-वितरण हेडर की जाँच करके उन्हें छोड़ देता है:

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 - i.e. plain text, no attachments, keeping fingers crossed
else:
    body = b.get_payload(decode=True)

बीटीडब्लू, walk()माइम भागों पर अद्भुत रूप से पुनरावृत्त get_payload(decode=True)करता है , और आपके लिए बेस 64 आदि को डिकोड करने पर गंदा काम करता है।

कुछ पृष्ठभूमि - जैसा कि मैंने निहित किया है, MIME ईमेल की अद्भुत दुनिया संदेश शरीर को खोजने के लिए "गलत तरीके से" बहुत सारे नुकसान प्रस्तुत करती है। सबसे सरल मामले में यह एकमात्र "टेक्स्ट / प्लेन" भाग में है और get_payload () बहुत आकर्षक है, लेकिन हम एक साधारण दुनिया में नहीं रहते हैं - यह अक्सर मल्टीपार्ट / वैकल्पिक, संबंधित, मिश्रित आदि सामग्री में घिरा हुआ है। विकिपीडिया इसका कड़ा वर्णन करता है - MIME , लेकिन नीचे इन सभी मामलों पर विचार करना मान्य है - और आम - सभी को सुरक्षा जाल पर विचार करना होगा:

बहुत आम है - सामान्य संपादक (जीमेल, आउटलुक) में बहुत कुछ जो आपको एक अनुलग्नक के साथ स्वरूपित पाठ भेजना है:

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

अपेक्षाकृत सरल - बस वैकल्पिक प्रतिनिधित्व:

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

अच्छे या बुरे के लिए, यह संरचना भी मान्य है:

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

उम्मीद है इससे कुछ मदद मिली होगी।

PS मेरी बात ईमेल के हल्के में नहीं है - यह काटता है जब आप कम से कम उम्मीद करते हैं :)


6
इस पूरी तरह से उदाहरण के लिए और एक चेतावनी वर्तनी के लिए धन्यवाद - स्वीकृत उत्तर के विपरीत। मुझे लगता है कि यह एक बेहतर / सुरक्षित दृष्टिकोण है।
साइमन स्टेनबर्गर

1
आह, बहुत अच्छा! .get_payload(decode=True)इसके बजाय बस .get_payload()जीवन को बहुत आसान बना दिया है, धन्यवाद!
मार्क

11

उचित प्रलेखन के साथ ईमेल सामग्री को पार्स करने के लिए बहुत अच्छा पैकेज उपलब्ध है।

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)

कैसे इस्तेमाल करे:

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

2
लाइब्रेरी महान है, लेकिन मैं अपने ही वर्ग से विरासत में मिली है कि बनाने के लिए किया था MailParserऔर ओवरराइड शरीर , पद्धति है क्योंकि यह के साथ ईमेल के शरीर के कुछ हिस्सों में शामिल "\ n --- mail_boundary --- \ n" जो मेरे लिए आदर्श नहीं था।
अवराम

hi @avram, क्या आप उस कक्षा को साझा कर सकते हैं जिसे आपने लिखा है?
अमेय पी नाइक

मैं परिणाम को "\ n --- mail_boundary --- \ n" पर विभाजित करने में कामयाब रहा।
अमेय पी नाइक

1
@AmeyPNaik यहाँ मैंने एक त्वरित गथबस्ट गिस्ट बनाया: gist.github.com/aleksaa01/ccd371869f3a3c7b3e47822d5d78ccdf
avram

1
उनके दस्तावेज़ में @AmeyPNaik , यह कहता है: मेल-पार्सर आउटलुक ईमेल प्रारूप (.msg) को पार्स कर सकता है। इस सुविधा का उपयोग करने के लिए, आपको libemail-outlook-message-perl पैकेज
Ciprian Tomoiagă

6

पायथन 3.6+ सादे टेक्स्ट बॉडी को खोजने और डीकोड करने के लिए बिल्ट-इन सुविधा के तरीके प्रदान करता है @Todor Minakov। आप EMailMessage.get_body()और get_content()विधियों का उपयोग कर सकते हैं :

msg = email.message_from_string(s, policy=email.policy.default)
body = msg.get_body(('plain',))
if body:
    body = body.get_content()
print(body)

ध्यान दें कि Noneयदि कोई स्पष्ट (स्पष्ट) सादे पाठ अंग नहीं है तो यह दे देगा ।

यदि आप उदाहरण के लिए एक mbox फ़ाइल से पढ़ रहे हैं, तो आप मेलबॉक्स निर्माता को एक EmailMessageकारखाना दे सकते हैं :

mbox = mailbox.mbox(mboxfile, factory=lambda f: email.message_from_binary_file(f, policy=email.policy.default), create=False)
for msg in mbox:
    ...

ध्यान दें कि आपको email.policy.defaultपॉलिसी के रूप में पास होना चाहिए , क्योंकि यह डिफ़ॉल्ट नहीं है ...


2
email.policy.defaultडिफ़ॉल्ट क्यों नहीं है? लगता है जैसे यह होना चाहिए।
PartialOrder

4

b['body']अजगर में कोई नहीं है। आपको 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...

शुभ लाभ।


0

यदि ईमेल पंडों डेटाफ्रेम और ईमेल है। ईमेल पाठ के लिए कॉलम को ईमेल करें

## 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()

-3

यहाँ वह कोड है जो मेरे लिए हर समय काम करता है (आउटलुक ईमेल के लिए):

#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

4
शायद यह वर्तनी है कि यह विंडोज पर आउटलुक के लिए है, वास्तविक ईमेल के लिए नहीं।
ट्रिपल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.