【问题标题】:Save email attachment (python3, pop3_ssl, gmail)保存电子邮件附件(python3、pop3_ssl、gmail)
【发布时间】:2011-11-29 08:30:48
【问题描述】:

我正在尝试保存来自 Google 邮件帐户的电子邮件附件。

AFAIK,它可以“遍历”消息并获取其有效负载,

for part in message.walk():
    # getting payload, saving attach etc.

但它不起作用。 请参阅下面的整个示例:

def test_save_attach(self):
    self.connection = poplib.POP3_SSL('pop.gmail.com', 995)
    self.connection.set_debuglevel(1)
    self.connection.user(USERNAME)
    self.connection.pass_(PASS)

    emails, total_bytes = self.connection.stat()
    print("{0} emails in the inbox, {1} bytes total".format(emails, total_bytes))
    # return in format: (response, ['mesg_num octets', ...], octets)
    msg_list = self.connection.list()
    print(msg_list)

    # messages processing
    for i in range(emails):
        response = self.connection.retr(i+1)
        # return in format: (response, ['line', ...], octets)
        lines = response[1]
        str_message = email.message_from_bytes(b''.join(lines))
        print(str_message)

        # save attach
        for part in str_message.walk():
            print(part.get_content_type())

            if part.get_content_maintype() == 'multipart':
                continue

            if part.get('Content-Disposition') is None:
                continue

            filename = part.get_filename()
            if not(filename): continue

            fp = open(os.path.join(self.savedir, filename), 'wb')
            fp.write(part.get_payload(decode=1))
            fp.close

    self.connection.quit()

脚本输出是:

*cmd* 'USER **********'
*cmd* 'PASS **********'
*cmd* 'STAT'
*stat* [b'+OK', b'1', b'5301']
1 emails in the inbox, 5301 bytes total
*cmd* 'LIST'
(b'+OK 1 messages (5301 bytes)', [b'1 5301'], 8)
*cmd* 'RETR 1'
[<message headers and body>]
text/plain
*cmd* 'QUIT'

正如我们所见,消息的唯一部分是“text/plain”格式并且不包含任何附加信息,尽管消息正文肯定包含它并且可以在调试输出时看到。

【问题讨论】:

    标签: python email python-3.x gmail pop3


    【解决方案1】:
    response = self.connection.retr(i+1)
    raw_message = response[1]
    

    raw_message 不是字符串。 retr 将消息作为单行列表返回。您正在尝试使用 str(raw_message) 将列表转换为字符串 - 这不起作用。

    相反,将这些行连接在一起,例如,替换

    str_message = email.message_from_string(str(raw_message))
    

    与:

    python2:

    str_message = email.message_from_string("\n".join(raw_message))
    

    python3:

    str_message = email.message_from_bytes(b'\n'.join(raw_message))
    

    edit:// 添加我的完整工作源和输出以帮助调试问题

    import poplib
    import email
    import os
    
    class GmailTest(object):
        def __init__(self):
            self.savedir="/tmp"
    
        def test_save_attach(self):
            self.connection = poplib.POP3_SSL('pop.gmail.com', 995)
            self.connection.set_debuglevel(1)
            self.connection.user("<munged>")
            self.connection.pass_("<munged>")
    
            emails, total_bytes = self.connection.stat()
            print("{0} emails in the inbox, {1} bytes total".format(emails, total_bytes))
            # return in format: (response, ['mesg_num octets', ...], octets)
            msg_list = self.connection.list()
            print(msg_list)
    
            # messages processing
            for i in range(emails):
    
                # return in format: (response, ['line', ...], octets)
                response = self.connection.retr(i+1)
                raw_message = response[1]
    
                str_message = email.message_from_bytes(b'\n'.join(raw_message))
    
                # save attach
                for part in str_message.walk():
                    print(part.get_content_type())
    
                    if part.get_content_maintype() == 'multipart':
                        continue
    
                    if part.get('Content-Disposition') is None:
                        print("no content dispo")
                        continue
    
                    filename = part.get_filename()
                    if not(filename): filename = "test.txt"
                    print(filename)
    
                    fp = open(os.path.join(self.savedir, filename), 'wb')
                    fp.write(part.get_payload(decode=1))
                    fp.close
    
            #I  exit here instead of pop3lib quit to make sure the message doesn't get removed in gmail
            import sys
            sys.exit(0)
    
    d=GmailTest()
    d.test_save_attach()
    

    输出:

    python3 thetest.py
    *cmd* 'USER <munged>'
    *cmd* 'PASS <munged>'
    *cmd* 'STAT'
    *stat* [b'+OK', b'2', b'152928']
    2 emails in the inbox, 152928 bytes total
    *cmd* 'LIST'
    (b'+OK 2 messages (152928 bytes)', [b'1 76469', b'2 76459'], 18)
    *cmd* 'RETR 1'
    multipart/mixed
    text/plain
    test.txt
    application/pdf
    ADDFILE_0.pdf
    *cmd* 'RETR 2'
    multipart/mixed
    text/plain
    test.txt
    application/pdf
    ADDFILE_0.pdf
    

    【讨论】:

    • 我明白了,但这条线似乎有 'bytes' 类型,所以 string.join() 不起作用。如果我做类似 lines = response[1] message_text = "" for line in lines: message_text += str(line) 我会得到同样的效果
    • 啊,你好像用的是python3,我不熟悉(还),sorry!您可能需要连接字节,然后使用 email.message_from_bytes (这是 python 3 afaik 中的新功能) - 但这只是一个猜测
    • 使用 email.message_from_bytes() 得到相同的结果。
    • 好的,我深入研究了 python3 ;-) 这似乎工作 str_message = email.message_from_bytes(b'\n'.join(raw_message))
    • 我也做了差不多的事情。问题似乎出在其他地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 2021-06-26
    • 2013-07-13
    • 2019-05-07
    • 2019-01-21
    • 1970-01-01
    • 2021-06-11
    相关资源
    最近更新 更多