conn = self.conn id_list = conn.search(None, '(UNSEEN)')[1][0].split() try: email_id = id_list[i] except IndexError: return None data = conn.fetch(email_id, '(BODY.PEEK[HEADER.FIELDS (SUBJECT)])')[1] # if not PY3: msg = message_from_string(data[0][1]) s, encoding = decode_header(msg['Subject'])[0] subject = s.decode(encoding or 'utf-8').encode('utf-8') return subject if __name__ == '__main__': from qqbot.qconf import QConf conf = QConf(['-u', 'xxx']) conf.Display() ma = MailAgent(conf.mailAccount, conf.mailAuthCode) with ma.SMTP() as s: s.send(conf.mailAccount, 'hello', 'faf房间多啦') print('send ok') with ma.IMAP() as i: subject = i.getSubject(-1) print('latest email: ' + str(subject)) print('recv ok')
class QQBot(GroupManager, TermBot): def Login(self, argv=None): self.init(argv) session, contactdb = QLogin(self.conf) self.session, self.contactdb = session, contactdb # main thread self.SendTo = session.Copy().SendTo self.groupKick = session.GroupKick self.groupSetAdmin = session.GroupSetAdmin self.groupShut = session.GroupShut self.groupSetCard = session.GroupSetCard # main thread self.List = contactdb.List self.Update = contactdb.Update self.StrOfList = contactdb.StrOfList self.ObjOfList = contactdb.ObjOfList self.findSender = contactdb.FindSender self.firstFetch = contactdb.FirstFetch self.Delete = contactdb.db.Delete self.Modify = contactdb.db.Modify # child thread 1 self.poll = session.Copy().Poll def Run(self): if self.conf.startAfterFetch: self.firstFetch() self.onPlug() self.onStartupComplete() # child thread 1~4 StartDaemonThread(self.pollForever) StartDaemonThread(self.intervalForever) StartDaemonThread(QTermServer(self.conf.termServerPort, self.onTermCommand).Run) self.scheduler.start() self.started = True try: MainLoop() except SystemExit as e: self.onExit(e.code, getReason(e.code), None) raise except Exception as e: ERROR('', exc_info=True) ERROR('Mainloop 发生未知错误:%r', e) self.onExit(1, 'unknown-error', e) raise SystemExit(1) def Stop(self): sys.exit(0) def Restart(self): sys.exit(RESTART) def FreshRestart(self): sys.exit(FRESH_RESTART) # child thread 1 def pollForever(self): while True: try: result = self.poll() except RequestError: Put(sys.exit, LOGIN_EXPIRE) break except: ERROR('qsession.Poll 方法出错', exc_info=True) else: Put(self.onPollComplete, *result) def onPollComplete(self, ctype, fromUin, membUin, content): if ctype == 'timeout': return contact, member, nameInGroup = \ self.findSender(ctype, fromUin, membUin, self.conf.qq, content) if contact.ctype == 'group' and member == 'SYSTEM-MESSAGE': INFO('来自 %s 的系统消息: "%s"', contact, content) return if self.detectAtMe(nameInGroup, content): INFO('有人 @ 我:%s[%s]' % (contact, member)) content = '[@ME] ' + content.replace('@'+nameInGroup, '') else: content = content.replace('@ME', '@Me') if ctype == 'buddy': INFO('来自 %s 的消息: "%s"' % (contact, content)) else: INFO('来自 %s[%s] 的消息: "%s"' % (contact, member, content)) self.onQQMessage(contact, member, content) def detectAtMe(self, nameInGroup, content): return nameInGroup and ('@'+nameInGroup) in content # child thread 2 def intervalForever(self): while True: time.sleep(300) Put(self.onInterval) def __init__(self): self.scheduler = BackgroundScheduler(daemon=True) self.schedTable = defaultdict(list) self.slotsTable = { 'onInit': [], 'onQrcode': [], 'onStartupComplete': [], 'onQQMessage': [], 'onInterval': [], 'onUpdate': [], 'onPlug': [], 'onUnplug': [], 'onExit': [], } self.started = False self.plugins = {} def init(self, argv): for name, slots in self.slotsTable.items(): setattr(self, name, self.wrap(slots)) self.conf = QConf(argv) self.conf.Display() for pluginName in self.conf.plugins: self.Plug(pluginName) self.onInit() def wrap(self, slots): def func(*args, **kwargs): for f in slots: _call(f, self, *args, **kwargs) return func def AddSlot(self, func): self.slotsTable[func.__name__].append(func) return func def AddSched(self, **triggerArgs): def wrapper(func): job = lambda: Put(_call, func, self) job.__name__ = func.__name__ j = self.scheduler.add_job(job, 'cron', **triggerArgs) self.schedTable[func.__module__].append(j) return func return wrapper def unplug(self, moduleName, removeJob=True): for slots in self.slotsTable.values(): i = 0 while i < len(slots): if slots[i].__module__ == moduleName: slots[i] = slots[-1] slots.pop() else: i += 1 if removeJob: for job in self.schedTable.pop(moduleName, []): job.remove() self.plugins.pop(moduleName, None) def Plug(self, moduleName): self.unplug(moduleName) try: module = Import(moduleName) except Exception as e: result = '错误:无法加载插件 %s ,%s: %s' % (moduleName, type(e), e) ERROR('', exc_info=True) ERROR(result) self.unplug(moduleName) else: self.unplug(moduleName, removeJob=False) names = [] for slotName in self.slotsTable.keys(): if hasattr(module, slotName): self.slotsTable[slotName].append(getattr(module, slotName)) names.append(slotName) if (not names) and (moduleName not in self.schedTable): result = '警告:插件 %s 中没有定义回调函数或定时任务' % moduleName WARN(result) else: self.plugins[moduleName] = module jobs = self.schedTable.get(moduleName, []) jobNames = [f.func.__name__ for f in jobs] result = '成功:加载插件 %s(回调函数%s、定时任务%s)' % \ (moduleName, names, jobNames) INFO(result) if self.started and hasattr(module, 'onPlug'): _call(module.onPlug, self) return result def Unplug(self, moduleName): if moduleName not in self.plugins: result = '警告:试图卸载未安装的插件 %s' % moduleName WARN(result) return result else: module = self.plugins[moduleName] self.unplug(moduleName) if hasattr(module, 'onUnplug'): _call(module.onUnplug, self) result = '成功:卸载插件 %s' % moduleName INFO(result) return result def Plugins(self): return list(self.plugins.keys())