我正在尝试使用一个 python 脚本来不断监控 gmail 帐户中的新电子邮件。使用IMAPClient,它打开两个 imap 连接,一个处于空闲模式。每当收到新消息时,处于空闲模式的连接会告诉另一个连接它应该获取新邮件。非空闲连接将获取邮件,执行一些处理,然后存档电子邮件。
当我在短时间内收到许多电子邮件时,问题就出现了,一分钟内超过几封。在这种情况下,我得到一个 AssertionError。下面是重现错误的最小示例。除了 imap 连接之外,它还打开一个 smtp 连接,以便它可以将电子邮件发送给它自己。在发送 5-7 封电子邮件后,它通常会在某个时间点因 AssertionError 而失败。AssertionError 来自对idle_check
.
关于运行代码的一些简短评论。它不使用 OAuth,因此必须将 gmail 设置为允许不太安全的应用程序。必须设置脚本底部的“用户名”和“密码”字段。该脚本还将归档当前在收件箱中的所有电子邮件,因此不应在主电子邮件帐户上运行。
#!/usr/bin/env python3
import smtplib
import imapclient
import email
import threading
import time
class Server(object):
def __init__(self,username,password):
self.username = username
self.password = password
def start(self):
self.stop_running = threading.Event()
self.has_mail = threading.Event()
threading.Thread(target=self._idle).start()
threading.Thread(target=self._poll).start()
print('Listening for messages now')
def _idle(self):
imap_idle = self.imap_connect()
while not self.stop_running.is_set():
imap_idle.idle()
for i in range(600):
try:
if imap_idle.idle_check(1):
self.has_mail.set()
except AssertionError as e:
self.stop_running.set()
raise
imap_idle.idle_done()
imap_idle.noop()
def _poll(self):
imap_poll = self.imap_connect()
self.process_unread(imap_poll)
while True:
if self.has_mail.wait(1):
self.has_mail.clear()
self.process_unread(imap_poll)
if self.stop_running.is_set():
return
def imap_connect(self):
imap = imapclient.IMAPClient('imap.gmail.com',use_uid=True,ssl=True)
imap.login(self.username,self.password)
imap.select_folder('INBOX')
return imap
def process_unread(self, imap):
imap.select_folder('INBOX')
messages = imap.search()
if messages:
imap.copy(messages,'[Gmail]/All Mail')
imap.delete_messages(messages)
def smtp_connect(self):
smtp = smtplib.SMTP('smtp.gmail.com',587)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(self.username,self.password)
return smtp
def send(self,recipient,subject='',body=''):
headers = ['from: ' + self.username,
'subject: ' + subject,
'to: ' + recipient,
'mime-version: 1.0',
'content-type: text/html']
headers = '\r\n'.join(headers)
self.smtp_connect().sendmail(self.username,recipient,headers+'\r\n\r\n'+body)
def main():
username = 'username@gmail.com'
password = 'password'
s = Server(username, password)
s.start()
for i in range(8):
if s.stop_running.is_set():
break
print('Sending message',i)
s.send(username,
'Test Message'.format(i),
'Body {}'.format(i))
time.sleep(15)
if __name__=='__main__':
main()
给出的错误信息如下。错误时的text
变量有时是b'XISTS'
有时b' FLAGS (\\Seen))'
。
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
self.run()
File "/usr/lib/python3.4/threading.py", line 868, in run
self._target(*self._args, **self._kwargs)
File "./emailer.py", line 31, in _idle
if imap_idle.idle_check(1):
File "/path/to/the/venv/lib/python3.4/site-packages/imapclient/imapclient.py", line 519, in idle_check
resps.append(_parse_untagged_response(line))
File "/path/to/the/venv/lib/python3.4/site-packages/imapclient/imapclient.py", line 1093, in _parse_untagged_response
assert text.startswith(b'* ')
AssertionError
我使用 IMAPClient 0.13 使用 Python 3.4.0 运行它。这是在一个干净的 virtualenv 中运行的,没有安装其他库。任何帮助将不胜感激。