Python : 원시 이메일에 "Body"태그 등이없는 경우 원시 이메일에서 본문을 구문 분석하는 방법


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

113

매우 긍정적이 되려면 실제 이메일 본문으로 작업하고 (그래도 올바른 부분을 구문 분석하지 않을 가능성이 있음) 첨부 파일을 건너 뛰고 추가를 위해 일반 또는 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)

BTW, walk()mime 부분에서 놀랍도록 반복하고 get_payload(decode=True)base64 등을 디코딩하는 작업을 수행합니다.

일부 배경-내가 암시했듯이 MIME 이메일의 멋진 세계는 메시지 본문을 "잘못"찾는 많은 함정을 제시합니다. 가장 단순한 경우에는 "text / plain"부분에 있고 get_payload ()는 매우 유혹적이지만 우리는 단순한 세상에 살지 않습니다. 종종 여러 부분 / 대체, 관련, 혼합 등의 콘텐츠로 둘러싸여 있습니다. Wikipedia는 MIME을 엄격하게 설명 하지만 아래의 모든 경우가 유효하고 일반적이라는 점을 고려할 때 모든 안전망을 고려해야합니다.

매우 일반적입니다. 일반 편집기 (Gmail, Outlook)에서 서식이 지정된 텍스트를 첨부 파일과 함께 보내는 것입니다.

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

이것이 조금 도움이되기를 바랍니다.

추신 : 내 요점은 이메일에 가볍게 접근하지 않는다는 것입니다.


6
이 철저한 예와 허용 된 답변과는 달리 경고를 작성해 주셔서 감사합니다. 나는 이것이 훨씬 더 나은 / 안전한 접근이라고 생각합니다.
Simon Steinberger

1
아, 아주 좋아요! .get_payload(decode=True)대신 .get_payload()삶을 훨씬 더 쉽게 만들었습니다. 감사합니다!
Mark

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
라이브러리는 훌륭하지만 이메일 본문의 일부를 "\ n --- mail_boundary --- \ n"으로 결합하기 때문에 body 메서드 를 상속 MailParser하고 재정의 하는 자체 클래스를 만들어야 했습니다 .
avram

안녕하세요 @avram 님, 작성한 수업을 공유해 주시겠습니까?
Amey P Naik

결과를 "\ n --- mail_boundary --- \ n"으로 분할했습니다.
Amey P Naik

1
@AmeyPNaik 여기서 빠른 github 요점을 만들었습니다. gist.github.com/aleksaa01/ccd371869f3a3c7b3e47822d5d78ccdf
avram

1
@AmeyPNaik은 문서 에서 다음과 같이 말합니다. mail-parser는 Outlook 이메일 형식 (.msg)을 구문 분석 할 수 있습니다. 이 기능을 사용하려면 libemail - 전망 - 메시지 - 펄 패키지를 설치해야
치프 리안 Tomoiagă

6

Python 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

emails가 pandas 데이터 프레임이고 emails.message 인 경우 이메일 텍스트 열

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

다음은 나에게 매번 작동하는 코드입니다 (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

4
아마도 이것은 실제 이메일이 아닌 Windows의 Outlook 용이라고 말할 수 있습니다.
tripleee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.