无需下载即可获取 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.HEADER
或BODY.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 附件?