You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用imap_tools实现邮箱登录后,如何保持IMAP连接避免LOGOUT错误?

问题描述

我编写了一个用于登录邮箱的辅助函数:

import imap_tools

def mailbox_login():
    try:
        with imap_tools.MailBoxUnencrypted(ENV["IMAP4_FQDN"]).login(
            ENV["RECEIVING_EMAIL_USER"], ENV["RECEIVING_EMAIL_PASSWORD"]
        ) as mailbox:
            print("Successfully logged into the mailbox.")
            return mailbox
    except imap_tools.MailboxLoginError as error:
        print(f"CRITICAL: Failed to login to the mailbox: {error}")

另有一个需要邮箱连接的函数:

def email_count():
    """
    Get all emails from the mail server via IMAP
    """
    msgs = []
    mailbox = mailbox_login()
    for msg in mailbox.fetch():
        msgs.append(msg)
    return msgs

运行email_count()时出现如下错误:

imaplib.IMAP4.error: command SEARCH illegal in state LOGOUT, only allowed in states SELECTED

离开with语句范围后邮箱就会自动登出,请问如何在离开mailbox_login()后保持连接?

解决方案

问题出在with语句的特性上——当with块执行完毕,会自动触发对象的__exit__方法,而imap_tools的MailBox对象在这个方法里会自动执行登出操作,所以你从mailbox_login()返回的mailbox已经是登出状态,自然无法执行后续的fetch操作。以下两种方法可以解决这个问题:

方法一:移除with语句,手动管理连接生命周期

直接创建并登录邮箱实例,不使用with,这样就不会自动登出。但要记得在使用完邮箱后手动调用logout(),避免连接泄漏:

import imap_tools

def mailbox_login():
    try:
        mailbox = imap_tools.MailBoxUnencrypted(ENV["IMAP4_FQDN"]).login(
            ENV["RECEIVING_EMAIL_USER"], ENV["RECEIVING_EMAIL_PASSWORD"]
        )
        print("Successfully logged into the mailbox.")
        return mailbox
    except imap_tools.MailboxLoginError as error:
        print(f"CRITICAL: Failed to login to the mailbox: {error}")
        return None

# 使用时手动登出连接
def email_count():
    msgs = []
    mailbox = mailbox_login()
    if not mailbox:
        return msgs
    try:
        for msg in mailbox.fetch():
            msgs.append(msg)
    finally:
        mailbox.logout()  # 手动释放连接,避免资源浪费
    return msgs

方法二:将mailbox_login改造为上下文管理器,在外层控制连接生命周期

用contextmanager装饰器把mailbox_login改成可以用with语句调用的上下文管理器,让连接的生命周期由外层的with块控制:

import imap_tools
from contextlib import contextmanager

@contextmanager
def mailbox_login():
    mailbox = None
    try:
        mailbox = imap_tools.MailBoxUnencrypted(ENV["IMAP4_FQDN"]).login(
            ENV["RECEIVING_EMAIL_USER"], ENV["RECEIVING_EMAIL_PASSWORD"]
        )
        print("Successfully logged into the mailbox.")
        yield mailbox
    except imap_tools.MailboxLoginError as error:
        print(f"CRITICAL: Failed to login to the mailbox: {error}")
        yield None
    finally:
        if mailbox:
            mailbox.logout()  # 自动在with块结束后登出

# 在外层使用with管理连接
def email_count():
    msgs = []
    with mailbox_login() as mailbox:
        if not mailbox:
            return msgs
        for msg in mailbox.fetch():
            msgs.append(msg)
    return msgs

内容的提问来源于stack exchange,提问作者Trouble Bucket

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:55:16