Tho*_*ard 3 python email imaplib python-2.7
在获取所有“未读”消息,然后遍历它们并获取它们之后,我试图在一条消息上操纵IMAP标志以将其标记为未读。
我不太确定如何在单个消息的基础上将消息标记为未读/看不见。我得到的只是消息编号,而且我不确定如何正确存储UID以仅影响单个消息。
相似问题中的答案似乎无效,因为它将错误消息设置为“未读”。如何设置再次被提取为“未读” 的单个邮件?
我被要求提供更多信息。在这里删除“秘密”的细节时,这是我尝试实现的现有运行时,因此它将尝试根据代码规则处理消息,并存储消息号等,并尝试将消息的ID和主题存储在pickle文件中后,将每条消息设置为“未读”,因为在运行过程中“看到”的所有内容都会在服务器上自动标记为“已读”,而不会设置为“未读”状态:
def main():
conn = imaplib.IMAP4('SERVER')
conn.login('username', 'passphrase')
conn.select('inbox')
(status, nums) = conn.search(None, '(UNSEEN)')
msgnums = map(int, nums[0].split())
for i in msgnums:
try:
raw_msg = conn.fetch(i, '(RFC822)')
raw_msg = conn.fetch(i, '(RFC822)')
msg = email.message_from_string(raw_msg[1][0][1])
body = "Date: %s\r\nSender: %s\r\nSubject: %s\r\n\r\n" % (msg['Date'], msg['From'], msg['Subject'])
msg_date = re.sub('/', '-', msg['Date']).replace(":", ".")
fdate = re.sub('\s+', '_', msg_date).replace(",", "")
print "Checking message: %s" % msg['Subject']
if not msg['Subject']:
continue # fname = "unknown_msg%d_%s" % (i,fdate)
elif msg['Subject'].lower().rfind('foobar') != -1:
print "Subject match 'foobar', processing: %s" % msg['Subject']
# We should have from the pickle an "observed" set of data, both subjects and message numbers.
if msg['Subject'] in PICKLED_MESSAGES['observed']['subjects']:
print "Already handled this message, moving on to next item."
# Since this was already observed we let it be removed so things don't rerun it later.
# noinspection PyBroadException
try:
PICKLED_MESSAGES['observed']['subjects'].remove(msg['Subject'])
PICKLED_MESSAGES['observed']['msgnums'].remove(i)
except:
pass
continue
else:
continue
# Do stuff with the message to store it in a special way on the filesystem
# Note that we've now looked at the message, so next-run we can see
# what was handled on the last run.
PICKLED_MESSAGES['observed']['msgnums'].append(i)
PICKLED_MESSAGES['observed']['subjects'].append(msg['Subject'])
print "PICKLED:\n%s" % PICKLED_MESSAGES['observed']
conn.uid('STORE', str(i), '-FLAGS', '(\Seen)')
except Exception:
conn.uid('STORE', str(i), '-FLAGS', '(\Seen)')
PICKLED_MESSAGES['observed']['msgnums'].remove(i)
PICKLED_MESSAGES['observed']['subjects'].remove(msg['Subject'])
print "PICKLED:\n%s\n" % PICKLED_MESSAGES
finally:
# Store the pickle file so we can use it next run.
cPickle.dump(PICKLED_MESSAGES, open('observed_msgs.pkl', 'wb'))
if __name__ == "__main__":
# pre-runtime checks - is IMAP up, etc. run first, then this:
# Initialize the PICKLED_MESSAGES data with pickle data or an empty
# structure for the pickle.
# noinspection PyBroadException
try:
PICKLED_MESSAGES = cPickle.load(open('observed_msgs.pkl', 'rb'))
except Exception as e:
PICKLED_MESSAGES = {
'observed': {
'msgnums': [],
'subjects': [],
},
}
# If all checks satisfied, continue and process the main() directives.
try:
main()
except Exception as e:
print("CRITICAL An unhandled error has occurred: %s" % str(e))
exit()
Run Code Online (Sandbox Code Playgroud)
但是,它没有将正确的消息设置为“未读;当使用我在系统上看到的建议方法时。因此,我不能完全确定我是否没有正确获取消息的UID,或者在这里是否缺少其他内容。
好吧,我今天觉得很蠢。
显然,正在迭代的消息编号和conn.uid(...)期望的消息的UID 不一定是相同的编号。我想通了,一个人去取UID,并做一些后取处理,以得到公正的UID传递出去。
原始方法
在for上面的循环中,我可以使用以下命令获取UID :
for i in msgnums:
# ...
msg_uid = conn.fetch(i, 'UID')[1][0].split()[2].strip('()')
# ...
Run Code Online (Sandbox Code Playgroud)
这给了我conn.uid所期望的消息的UID ,而不是普通的消息号。我对没有意识到这一点感到有点愚蠢,但这似乎解决了这个问题。
更新了方法1(感谢 @Max在注释中)
我将所有搜索/获取/存储命令替换为等效的UID。
conn.search(None, '(UNSEEN)') 变成 conn.uid('SEARCH', None, '(UNSEEN)')conn.fetch(i, '(RFC822)') 变成 conn.uid('FETCH', i, '(RFC822)')conn.store(i, '-FLAGS', '(\Seen)') 变成 conn.uid('STORE', i, '-FLAGS', '(\Seen)')更新方法#2(由#1启发,但进一步去步骤)
我基本上已经厌倦了编写UID命令,但是还需要在另一个使用类似IMAP接口和命令的程序中应用类似的基于UID的功能。鉴于此,我决定写一个imaplib_extension.py模块“延伸”了imaplib的IMAP4和IMAP4_SSL功能,并覆盖‘搜索’,‘取’与‘商店’的命令uid变种否则保持‘搜索’,‘取’和“店”的命令照原样从imaplib但返回是基于UID函数来代替不同的结果集。
这是在我的imaplib_extension.py文件,我只是进口IMAP4或IMAP4_SSL从该模块,而不是从imaplib直接,并更换imaplib.IMAP4和imaplib.IMAP4_SSL只用电话IMAP4或IMAP4_SSL电话以后。因此,无需import imaplib(仅from imaplib import IMAP4或IMAP4_SSL相应地):
import imaplib
class IMAP4(imaplib.IMAP4):
def search(self, charset, *criteria):
# conn.uid('SEARCH', charset, criteria)
return self.uid('SEARCH', charset, " ".join(criteria))
def fetch(self, message_set, message_parts):
# conn.uid('FETCH', msgset, parts)
return self.uid('FETCH', message_set, message_parts)
def store(self, message_set, command, flags):
# conn.uid('STORE', msg_uid, '-FLAGS', '(\Seen)')
return self.uid('STORE', message_set, command, flags)
# noinspection PyPep8Naming
class IMAP4_SSL(imaplib.IMAP4_SSL):
def search(self, charset, *criteria):
# conn.uid('SEARCH', charset, criteria)
return self.uid('SEARCH', charset, " ".join(criteria))
def fetch(self, message_set, message_parts):
# conn.uid('FETCH', msgset, parts)
return self.uid('FETCH', message_set, message_parts)
def store(self, message_set, command, flags):
# conn.uid('STORE', msg_uid, '-FLAGS', '(\Seen)')
return self.uid('STORE', message_set, command, flags)
Run Code Online (Sandbox Code Playgroud)
我更喜欢使用的扩展名imaplib,因为命令结构与现有命令相同,但是可以正确地使用UID而不是可能不是UID的“消息号”。
更新的方法#3
在意识到我需要在其他 Python应用程序中使用它之后,我脱颖而出并发布imaplibext在PyPI上,它基本上是上述方法#2的改进和充实版本。但是,它确实具有更好的错误处理能力,并且能够为IMAP连接套接字实际指定超时。这是一项改进,因为您不能直接为imaplib.IMAP4或进行此操作imaplib.IMAP4_SSL,除其他事项外,它实际上是的替代品imaplib(尽管它仍然使用imaplib)。
该代码,这也存在于GitHub的一般用途和改进建议和问题报告。
| 归档时间: |
|
| 查看次数: |
1349 次 |
| 最近记录: |