imaplib.error: 在AUTH状态下FETCH命令非法

3 投票
2 回答
8710 浏览
提问于 2025-04-16 13:02

我正在尝试从Gmail下载附件,使用的是我在网上找到的一些代码,经过我自己的修改。不过,下面这段代码:

import email, getpass, imaplib, os, random, time
import oauth2 as oauth
import oauth2.clients.imap as imaplib

MY_EMAIL = 'example@gmail.com'
MY_TOKEN = "token"
MY_SECRET = "secret"

consumer = oauth.Consumer('anonymous', 'anonymous')
token = oauth.Token(MY_TOKEN, MY_SECRET)

url = "https://mail.google.com/mail/b/"+MY_EMAIL+"/imap/"
m = imaplib.IMAP4_SSL('imap.gmail.com')

m.authenticate(url, consumer, token)

m.select('INBOX')

items = m.select("UNSEEN"); 
items = items[0].split() 

for emailid in items:
    data = m.fetch(emailid, "(RFC822)")

却返回了这个错误:

imaplib.error: command FETCH illegal in state AUTH

为什么在我已经授权的情况下,Fetch会被认为是非法的呢?

2 个回答

3

为什么我有权限的情况下,Fetch会被认为是非法的呢?

IMAP有一个状态的概念。

你只能在选择了一个文件夹之后,才能获取邮件。

这里有一张很好的图片来说明这个问题:

IMAP状态

图片来源:http://www.tcpipguide.com/free/t_IMAP4GeneralOperationClientServerCommunicationandS-2.htm

4

你在调用选择邮箱的函数时没有检查错误。通常,我会这样来设置连接邮箱的前几步:

# self.conn is an instance of IMAP4 connected to my server.
status, msgs = self.conn.select('INBOX')

if status != 'OK':
  return # could be break, or continue, depending on surrounding code.

msgs = int(msgs[0])

简单来说,你遇到的问题是你选择了一个不存在的邮箱,你的状态信息可能不是“OK”,而是其他的,这样你在循环中的值就不对了。记住,选择邮箱时需要提供一个邮箱名称。它不会根据某个标记(比如你可能想用的“UNSEEN”)来搜索。当你选择一个不存在的邮箱时,实际上会收到这样的回应:

('NO', ['The requested item could not be found.'])

在这种情况下,for email id in items 就无法正常工作了。很遗憾,这不是你想要的结果。如果你选择一个有效的邮箱,得到的回应会是这样的:

('OK', ['337'])

希望这能帮到你。

针对评论中的问题,如果你想真正获取邮箱中的未读消息,你可以使用这个:

status, msgs = self.conn.select('INBOX')
# returns ('OK', ['336'])

status, ids = self.conn.search(None, 'UNSEEN')
# returns ('OK', ['324 325 326 336'])

if status == 'OK':
  ids = map(int, ids[0].split())

回应会和选择邮箱时的回应类似,但这次你会得到一个消息ID的列表,而不是一个单一的整数来表示消息数量。

撰写回答