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

如何用Python3+Exchangelib多线程加速删除Outlook/Hotmail可恢复项

多线程批量删除Outlook/Hotmail可恢复项单线程执行问题解决

问题情况

尝试用Python多线程批量删除大量Outlook/Hotmail邮箱的可恢复项,但从日志时间能看出,连接邮箱及删除操作实际是单线程串行执行。相关代码与日志如下:

原代码

from exchangelib import DELEGATE, Account, Credentials
import threading
# 原代码遗漏time模块导入,会导致time.time()调用报错
import time

def main(login,password):
    print('started',time.time())
    credentials = Credentials(
        username=login,  # 针对O365可使用myusername@example.com格式
        password=password
    )
    a = Account(
        primary_smtp_address=login, 
        credentials=credentials, 
        autodiscover=True, 
        access_type=DELEGATE
    )
    
    a.protocol.TIMEOUT=15
    
    ### 尝试过以下配置但无效果
    #a.protocol.SESSION_POOLSIZE=50
    #a.protocol.CONNECTIONS_PER_SESSION=50

    a.recoverable_items_deletions.empty()
        
    a.protocol.close()
    print('done',time.time())

for i in logins_passwords_dict:
    threading.Thread(target=main, args=(i[0],i[1],))

执行日志

started 17000
started 17000
started 17000
done 17010
done 17020
done 17030

问题原因

  1. 线程未启动:原代码仅创建了threading.Thread对象,但未调用.start()方法启动线程,所有任务实际由主线程串行处理。
  2. 潜在库限制:exchangelib部分内部逻辑可能存在线程阻塞,加上Python GIL特性,纯多线程可能无法完全发挥并发效果。

解决方案

方案1:修复多线程代码(正确启动线程)

先确保线程被正常启动,同时可以通过线程池控制并发数,避免触发Exchange服务器限流:

from exchangelib import DELEGATE, Account, Credentials
import threading
import time
from concurrent.futures import ThreadPoolExecutor

def main(login,password):
    print('started',time.time())
    try:
        credentials = Credentials(
            username=login,
            password=password
        )
        a = Account(
            primary_smtp_address=login, 
            credentials=credentials, 
            autodiscover=True, 
            access_type=DELEGATE
        )
        
        a.protocol.TIMEOUT=15
        # 合理调整会话池参数,提升单账号操作效率
        a.protocol.SESSION_POOLSIZE=10
        a.protocol.CONNECTIONS_PER_SESSION=10

        a.recoverable_items_deletions.empty()
            
        a.protocol.close()
    except Exception as e:
        print(f"处理账号{login}失败: {str(e)}")
    print('done',time.time())

# 控制并发数,建议设置为5-10,避免被服务器限制
with ThreadPoolExecutor(max_workers=8) as executor:
    for login, password in logins_passwords_dict:
        executor.submit(main, login, password)

方案2:改用多进程绕过GIL限制

如果多线程效果仍不理想,用多进程可以实现真正的并行执行:

from exchangelib import DELEGATE, Account, Credentials
import multiprocessing
import time
from concurrent.futures import ProcessPoolExecutor

def main(login,password):
    print('started',time.time())
    try:
        credentials = Credentials(
            username=login,
            password=password
        )
        a = Account(
            primary_smtp_address=login, 
            credentials=credentials, 
            autodiscover=True, 
            access_type=DELEGATE
        )
        
        a.protocol.TIMEOUT=15
        a.recoverable_items_deletions.empty()
            
        a.protocol.close()
    except Exception as e:
        print(f"处理账号{login}失败: {str(e)}")
    print('done',time.time())

if __name__ == "__main__":
    # 控制进程数,根据机器性能和服务器限制调整
    with ProcessPoolExecutor(max_workers=5) as executor:
        for login, password in logins_passwords_dict:
            executor.submit(main, login, password)

额外优化建议

  • 限制并发数量:不要一次性启动过多线程/进程,避免触发Exchange服务器的限流机制,建议从5-10的并发数开始测试。
  • 添加异常处理:避免单个账号的登录失败、网络超时等问题中断整个批量任务。
  • 调整会话池参数:根据实际情况微调SESSION_POOLSIZE和CONNECTIONS_PER_SESSION,提升单账号的操作效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:10:31