如何从IMAP服务器获取最新的10条消息?

3

我使用imaplib2库来搜索最近的10个消息,使用以下命令:

imap_client.search(None, '{}:{}'.format(last_uid, last_uid - 9))

但是要获取last_uid,我需要每次执行这样的命令:

imap_client.select("INBOX", readonly=True)

获取最后一个UID。

有没有以下方式:

  1. 不使用 select() 命令获取最后10条消息中的最后一个UID
  2. 不使用最后一个UID。也许有任何搜索条件,如“LAST”或“-10:”?

我无法执行此类命令 client.search(None, 'ALL'),因为IMAP服务器有超过50K个消息。


1
可能是使用IMAP和Python获取最近的n封电子邮件的重复问题。 - Joe
@Joe,这不是重复的。我无法执行“ALL”标准。感谢您此刻的帮助,现在已编辑问题。 - p2mbot
1
@Joe:如果“last”只有一种意思,那就是重复了。叹气 - arnt
1
UID不能保证连续,应使用序列号。您可以通过选择邮箱时返回的COUNT获取最后一个序列号。 - Nameless One
2个回答

4

对于任何寻求答案的未来旅行者,我从@arnt给出的提示中得出了代码。

svr = imaplib.IMAP4_SSL(server)
if svr.login(user=user, password=password):
    print('User ' + user + ' logged in successfully.')
else:
    print('Login for the user ' + user + " was denied. Please check your credentials.")

x = svr.select('inbox', readonly=True)
num = x[1][0].decode('utf-8')
#from here you can start a loop of how many mails you want, if 10, then num-9 to num
resp, lst = svr.fetch(num, '(RFC822)')
body = lst[0][1]
email_message = email.message_from_bytes(body)

对我来说,这非常方便,因为我要访问的电子邮件中有超过67000封邮件。


4
您可以使用STATUS (UIDNEXT)命令获取最后一个 UID。但是,您必须选择邮箱以检索邮件,并且当您发出 SELECT 命令时,您将收到一条返回消息计数的信息,该消息计数 Python imaplib 的 select 命令会返回。因此,您只需要执行以下操作即可:
(status, response_text) = mailbox.select("inbox")
# response_text usually contains only one bytes element that denotes
# the message count in an ASCII string
message_count = int(response_text[0].decode("ascii"))

然后,您可以通过索引从 message_count - 9message_count 来获取消息。

请注意,消息的索引从1开始计数。


UIDNEXT给出最后一个UID。根据RFC 3501中的说明,“下一个唯一标识符值旨在为客户端提供一种方式,以确定是否有任何消息在上次检查此值之后交付到邮箱中。它不旨在提供任何保证某个消息将具有此唯一标识符。”不能保证UIDNEXT与最后一个UID之间有任何特定的关系,除了它比最后一个UID大。 - InterLinked
没错,这没有任何保证。但如果你想要最后几条消息,我认为检索 [UIDNEXT-x, UIDNEXT> 是最好的单个命令。如果你愿意进行MSN算术并使用两个命令,你可以做得更好(例如,使用 UID SEARCH x-10:* 其中x是EXISTS发送的值,然后检查缓存中的这些UID,再使用UID FETCH获取结果)。不过,MSN算术很棘手,我不建议任何人尝试MSN算术。如果有人想尝试:那就是一个带有MSN参数的UID SEARCH命令。 - arnt
顺便说一句,在所讨论的服务器上,UIDs接近连续是第2.3.1.1节第一段的一个暗示。如果它们不接近连续,那么分配方案在构建该邮箱中的5万条消息之前将遇到32位边界问题,明白吗? - arnt
我正在考虑一个更现实的例子:假设你有一堆连续的邮件被倾倒到邮箱中,比如1-50,但是你删除了25-50,那么你只剩下UID为1-24的邮件,但是UIDNEXT仍然是51。因此,在这种情况下,说最高编号的邮件是50是错误的,实际上是24。如果假设是从邮箱中永远不会删除邮件(我没有看到提供这个假设),并且UID是连续分配的(我认为这是合理的),那么我认为这个假设是成立的。我在考虑一个更好的选择可能是使用MAX搜索选项(RFC 4731)。 - InterLinked
这也是真的,也是为什么在小邮箱中使用 UIDNEXT 之前的十个 UID 是一个不好的方法。但在这种情况下,我们知道那里有/曾经有 50k 条消息,这并不是在删除大量消息时会发生的事情。编程定律第42条:你总是可以通过创造一些额外的用例或边缘情况来使代码变得更复杂,并要求它支持这些情况。这就是 YAGNI 的意义所在。 - arnt
我从问题中没有感受到邮箱中的消息永远不会被删除。只要这是可能的,我不明白为什么信箱有多大就很重要。我的邮箱里有10万封邮件,而且随着时间的推移,我也删除了成千上万封邮件,但我无法想象如何能够可靠地使用UIDNEXT从邮箱中获取最大的UID。这假设最近传递到邮箱的n封邮件没有被清除,我认为这不是一个合理的假设,或者说这是一个一般情况下的边缘案例(想想收件箱)。 - InterLinked

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接