无需下载即可获取 Gmail 附件文件名

Posted

技术标签:

【中文标题】无需下载即可获取 Gmail 附件文件名【英文标题】:Get the Gmail attachment filename without downloading it 【发布时间】: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 你知道吗? 我的意思是所有邮件中的所有附件。 【参考方案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,你是怎么处理的? 我用它做了一些测试,但结果不是很好。实际上,我发现获取附件列表对于我的应用程序来说是不够的。最终,我通过它获取所有邮件内容、文本和所有附件。我没有解析代码,因为我说它是无效的。对不起... 对于新读者,请参阅***.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。

【讨论】:

以上是关于无需下载即可获取 Gmail 附件文件名的主要内容,如果未能解决你的问题,请参考以下文章

如何在gmail中下载包含.exe文件的.rar文件(附件)

检索从 gmail 下载的文件表单附件中的内容,因为它存储在 gmail 服务器中

如何让用户浏览器直接从 GMAIL 下载 gmail 附件?

从 Android 上的 gmail 应用程序下载附件的意图过滤器

Android从gmail获取数据,附件是json

使用 Gmail API 从 Gmail 下载附件