【问题标题】:Get the Gmail attachment filename without downloading it无需下载即可获取 Gmail 附件文件名
【发布时间】:2012-11-19 18:18:55
【问题描述】:

我正在尝试从可能包含一些大附件(大约 30MB)的 Gmail 帐户获取所有邮件。我只需要名称,而不是整个文件。我找到了一段代码来获取消息和附件的名称,但它会下载文件然后读取其名称:

import imaplib, email

#log in and select the inbox
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('username', 'password')
mail.select('inbox')

#get uids of all messages
result, data = mail.uid('search', None, 'ALL') 
uids = data[0].split()

#read the lastest message
result, data = mail.uid('fetch', uids[-1], '(RFC822)')
m = email.message_from_string(data[0][1])

if m.get_content_maintype() == 'multipart': #multipart messages only
    for part in m.walk():
        #find the attachment part
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Disposition') is None: continue

        #save the attachment in the program directory
        filename = part.get_filename()
        fp = open(filename, 'wb')
        fp.write(part.get_payload(decode=True))
        fp.close()
        print '%s saved!' % filename

我必须每分钟执行一次,所以我无法下载数百 MB 的数据。我是网络脚本的新手,所以有人可以帮助我吗?我实际上不需要使用 imaplib,任何 python 库都可以。

最好的问候

【问题讨论】:

  • 你只能在 gmail 中发送 20MB 你知道吗?
  • 我的意思是所有邮件中的所有附件。

标签: python gmail attachment imaplib


【解决方案1】:

如果您对文件名有所了解,可以使用X-GM-RAW gmail extensions for imap SEARCH command。这些扩展允许您使用任何gmail advanced search 查询来过滤消息。这样,您可以将下载限制为匹配的消息,或排除一些您不想要的消息。

mail.uid('search', None, 'X-GM-RAW', 
       'has:attachment filename:pdf in:inbox -label:parsed'))

以上搜索收件箱中带有未标记为“已解析”的 PDF 附件的邮件。

一些专业提示:

  • 标记您已经解析的消息,因此您不需要再次获取它们(上例中的 -label:parsed 过滤器)
  • 始终使用 uid 版本而不是标准的顺序 id(您已经这样做了)
  • 不幸的是,MIME 很混乱:有很多客户端会做奇怪(或完全错误)的事情。您可以尝试仅下载和解析标头,但这值得吗?

[编辑]

如果您在解析后标记消息,则可以跳过已解析的消息。这应该足以监控您的班级邮箱。

也许您生活在互联网带宽比程序员时间更昂贵的世界角落;在这种情况下,您可以仅获取标题并查找“Content-disposition” == “attachment; filename=somefilename.ext”。

【讨论】:

  • 这很酷,但问题是我对附件一无所知。我正在编写一个脚本来“扫描”我班级帐户的所有 gmail 收件箱,并告诉我它是否是新内容,包括有关附件的信息(名称和大小)。由于该帐户已被 30 人使用,因此无法搜索未读邮件。
  • 至少可以跳过不带附件的消息和已经解析过的消息;请注意,您也可以按大小过滤。
  • 当然可以,但是跳过我已经解析的消息是没有问题的。问题是在一分钟内解析接下来的 20 条带有 20MB 附件的消息。
  • 您好 Paulo,我使用了高级搜索。但是我的问题是我想搜索xls文件,所以我使用了filename:xls',但我最终得到了xls文件和xlsx文件。你知道如何只搜索 xls 文件吗?
  • @Cacheing:也许这值得作为一个新问题提出 - 评论系统正在搞砸我的答案。
【解决方案2】:

RFC822 消息数据项的 FETCH 在功能上等同于 BODY[]。 IMAP4 支持section 6.4.5 of RFC 3501 中列出的其他消息数据项。

尝试请求一组不同的消息数据项以获取您需要的信息。例如,您可以尝试RFC822.HEADERBODY.PEEK[MIME]

【讨论】:

    【解决方案3】:

    您可以指定BODYSTRUCTURE,而不是获取完整内容的RFC822

    imaplib 生成的数据结构相当混乱,但您应该能够找到消息各部分的文件名、内容类型和大小,而无需下载整个内容。

    【讨论】:

    • 这就是我一直在寻找的......结果确实令人困惑,但它确实有效。非常感谢!
    • 这正是我所寻找的。但是你有关于如何解析那个疯狂的结果字符串的任何线索吗? @mopsiok,你是怎么处理的?
    • 我用它做了一些测试,但结果不是很好。实际上,我发现获取附件列表对于我的应用程序来说是不够的。最终,我通过它获取所有邮件内容、文本和所有附件。我没有解析代码,因为我说它是无效的。对不起...
    • 对于新读者,请参阅stackoverflow.com/questions/13663672/…EDIT@
    【解决方案4】:

    老问题,但只是想分享我今天想出的解决方案。搜索所有带有附件的电子邮件并输出 uid、发件人、主题和格式化的附件列表。编辑相关代码以显示如何格式化 BODYSTRUCTURE:

        data   = mailobj.uid('fetch', mail_uid, '(BODYSTRUCTURE)')[1]
        struct = data[0].split()        
        list   = []                     #holds list of attachment filenames
    
        for j, k in enumerate(struct):
            if k == '("FILENAME"':
                count = 1
                val = struct[j + count]
                while val[-3] != '"':
                    count += 1
                    val += " " + struct[j + count]
                list.append(val[1:-3])
            elif k == '"FILENAME"':
                count = 1
                val = struct[j + count]
                while val[-1] != '"':
                    count += 1
                    val += " " + struct[j + count]
                list.append(val[1:-1])
    

    我也在GitHub上发布了它。

    编辑

    上述解决方案很好,但从有效负载中提取附件文件名的逻辑并不可靠。当文件名包含第一个单词只有两个字符的空格时,它会失败,

    例如:“ad cde gh.png”。

    试试这个:

    import re # Somewhere at the top
    
    result, data = mailobj.uid("fetch", mail_uid, "BODYSTRUCTURE")
    
    itr = re.finditer('("FILENAME" "([^\/:*?"<>|]+)")', data[0].decode("ascii"))
    
    for match in itr:
        print(f"File name: {match.group(2)}")
    

    测试正则表达式here

    【讨论】:

      猜你喜欢
      • 2016-03-23
      • 2012-06-23
      • 2012-11-30
      • 1970-01-01
      • 1970-01-01
      • 2017-08-26
      • 1970-01-01
      • 2014-11-01
      • 2012-06-25
      相关资源
      最近更新 更多