【转载+原创】python imaplib读邮件,存附件至本地,标记为已读,搜索邮件-腾讯qq邮箱
借鉴:python高阶教程-使用imap接收邮箱的附件(中文字符编码与MIME) - 码农教程
原版运行代码
import imaplib
import email
from email.parser import BytesParser
from email.utils import parseaddr
# 如果是企业邮箱,host要更换成企业邮箱的
host = 'imap.qq.com'
user = 'xxxxx@qq.com'
# 不是登录password,是单独生成的邮箱authCode
passwd = ''
mail_directory = 'INBOX'
conn = imaplib.IMAP4(host)
conn.login(user, passwd)
conn.select(mail_directory)
# status, data = conn.search(None, 'ALL')
# 多条件:来自xxx发件人,未读
status, data = conn.search(None, '(FROM "xxx@qq.com") UNSEEN')
email_list = list(reversed(data[0].split()))def decode_str(s):try:subject = email.header.decode_header(s)except:# print('Header decode error')return Nonesub_bytes = subject[0][0]sub_charset = subject[0][1]if None == sub_charset:subject = sub_byteselif 'unknown-8bit' == sub_charset:subject = str(sub_bytes, 'utf8')else:subject = str(sub_bytes, sub_charset)return subjectdef get_email(num, conn):typ, content = conn.fetch(num, '(RFC822)')msg = BytesParser().parsebytes(content[0][1])sub = msg.get('Subject')for part in msg.walk():fileName = part.get_filename()fileName = decode_str(fileName)if None != fileName:print('+++++++++++++++++++')print(fileName)print(num, decode_str(sub))for num in email_list:get_email(num, conn)
conn.close()
conn.logout()
获取附件
附件的获取按照网络上的代码没有出现问题.
for part in message.walk(): fileName = part.get_filename() fileName = decode_str(fileName)# 保存附件 if fileName: data = part.get_payload(decode=True) localFileName = "D:\\\\" + fileNamewith open(localFileName,'wb') as f:f.write(data)print("附件%s已保存" % fileName)
按时间搜索
不能有时间,只能有日期,而且格式是日月年
以下为引用:Python imaplib 搜索带有日期和时间的电子邮件
“不幸的是没有。 中定义的通用IMAP搜索语言RFC 3501 §6.4.4不包括任何按时间搜索的规定。
SINCE
被定义为取一个<date>
项,该项又被定义为date-day "-" date-month "-" date-year
,可以带或不带引号。
IMAP甚至没有时区意识,所以你将不得不根据INTERNALDATE
项,在本地过滤掉不符合你范围的前几条信息。 你甚至可能要多取几天的信息。
如果你使用的是Gmail,你也许可以使用Gmail的搜索语言,它可以作为一个extension.”
搜索其他文件夹
众所周知,收件箱统一交inbox,但是自定义或者其他文件呢?
有一个命令可以看到自己邮箱下那些文件夹的具体名称
import imaplib
import email
from email.parser import BytesParser
from email.utils import parseaddr
# 如果是企业邮箱,host要更换成企业邮箱的
host = 'imap.qq.com'
user = 'xxxxx@qq.com'
# 不是登录password,是单独生成的邮箱authCode
passwd = ''
conn = imaplib.IMAP4(host)
conn.login(user, passwd)
# 登录后使用
conn.list()
'''('OK',[b'(\\\\NoSelect \\\\HasChildren) "/" "&UXZO1mWHTvZZOQ-"',b'(\\\\HasNoChildren) "/" "INBOX"',b'(\\\\HasNoChildren) "/" "Sent Messages"',b'(\\\\HasNoChildren) "/" "Drafts"',b'(\\\\HasNoChildren) "/" "Deleted Messages"',b'(\\\\HasNoChildren) "/" "Junk"'])'''
mail_directory = 'Sent Messages'
conn.select("\\"" + mail_directory + "\\"")
# status, data = conn.search(None, 'ALL')
# 多条件:来自xxx发件人,未读
status, data = conn.search(None, '(FROM "xxx@qq.com") UNSEEN')
email_list = list(reversed(data[0].split()))
如果文件夹名有空格,一定要按照一下格式写!
email-Python imaplib 无法选择()自定义 Gmail 标签 - 糯米PHP
与朋友讨论了几个小时后解决了这个问题。事实证明,问题是 imap.select() 想要在邮箱名称周围加上引号,如果它包含空格。所以 imap.select("INBOX") 很好,但有空格你需要 imap.select("\\"" + "Label Name" + "\\"")
最有效的搜索方式
试验了一个晚上,发现inbox通过:发件人,日期,是否已读来搜索是最有效的,理论上按照subject应该也是可以的,但是我试了半天,如果使用中文搜索,完全不行,都会搜到一大堆,根本不能完全匹配,只有标题里有英文,通过那个英文搜索才可以完全匹配!
发件人 未读 日期
conn = imaplib.IMAP4(host)
conn.login(user, passwd)
conn.select('INBOX')
status, data = conn.search(None, '(FROM "xxxx@qq.com") UNSEEN SINCE "05-04-2023"')
标题中含有‘hk_us’的邮件
conn = imaplib.IMAP4(host)
conn.login(user, passwd)
conn.select('INBOX')
status, data = conn.search(None, 'SUBJECT "hk_us"')
标记为已读
import imaplib
import email
from email.parser import BytesParser
from email.utils import parseaddr
# 如果是企业邮箱,host要更换成企业邮箱的
host = 'imap.qq.com'
user = 'xxxxx@qq.com'
# 不是登录password,是单独生成的邮箱authCode
passwd = ''
mail_directory = 'INBOX'
conn = imaplib.IMAP4(host)
conn.login(user, passwd)
conn.select(mail_directory)
# status, data = conn.search(None, 'ALL')
# 多条件:来自xxx发件人,未读
status, data = conn.search(None, '(FROM "xxx@qq.com") UNSEEN')
email_list = list(reversed(data[0].split()))def decode_str(s):try:subject = email.header.decode_header(s)except:# print('Header decode error')return Nonesub_bytes = subject[0][0]sub_charset = subject[0][1]if None == sub_charset:subject = sub_byteselif 'unknown-8bit' == sub_charset:subject = str(sub_bytes, 'utf8')else:subject = str(sub_bytes, sub_charset)return subjectdef get_email(num, conn):typ, content = conn.fetch(num, '(RFC822)')msg = BytesParser().parsebytes(content[0][1])sub = msg.get('Subject')for part in msg.walk():fileName = part.get_filename()fileName = decode_str(fileName)if None != fileName:print('+++++++++++++++++++')print(fileName)# 标记为已读conn.store(num,'+FLAGS','\\Seen')print(num, decode_str(sub))for num in email_list:get_email(num, conn)
conn.close()
conn.logout()
获取邮件时间
引用:PYTHON 获取邮件发送时间_获取邮件日期_稚麟的博客-CSDN博客
def get_email(num, conn):typ, content = conn.fetch(num, '(RFC822)')msg = BytesParser().parsebytes(content[0][1])# 获得标题sub = msg.get('Subject')# 获得邮件时间mailDate = msg.get("Date")mailDate = mailDate.split(',')[1]mailDate = datetime.datetime.strptime(mailDate,'%d %b %Y %H:%M:%S %z').strftime('%Y%m%d%H%M%S')
我用的腾讯邮箱,他里面的日期是以下这样:
Tue, 24 Aug 2021 09:17:00 +0800 (CST)
Mon, 23 Aug 2021 09:35:26 +0000 (UTC)
Wed, 28 Jul 2021 00:51:23 +0000 (GMT)
用split(),把星期去掉,只处理后面的