使用Django与win32库发送邮件时出现延迟/队列问题
问题排查:Django+win32 Outlook邮件发送延迟问题
核心问题分析
这种"滞后一封"的延迟现象,本质是Outlook COM对象在多线程请求环境下资源未正确释放,导致邮件发送操作被缓存到Outlook本地队列,而非立即提交到邮件服务器。结合你的代码,主要问题点如下:
- COM线程模型适配错误:你在请求内部调用
pythoncom.CoInitialize(),但Django是多线程服务,Outlook的COM对象要求单线程单元(STA)模型,普通初始化无法匹配,导致线程上下文混乱,邮件暂存本地。 - COM资源未显式释放:创建的
outlook和mail对象未主动销毁,Outlook进程会持续持有这些资源,延迟提交邮件。 - 潜在的Outlook客户端设置:如果Outlook开启"延迟发送"或处于脱机状态,也会导致邮件堆积在发件箱,同步时才批量发送。
修复方案
1. 调整COM线程初始化方式
使用pythoncom.CoInitializeEx(pythoncom.COINIT_APARTMENTTHREADED)替代CoInitialize(),强制适配Outlook要求的STA线程模型。
2. 显式释放COM资源
发送完成后主动销毁mail和outlook对象,配合垃圾回收确保资源完全释放。
3. 修复后代码
class ApiSendMailCreateNewReporter(APIView): def get(self, request, id_headerRequest): outlook = None mail = None try: # 初始化STA线程模型,适配Outlook COM对象要求 pythoncom.CoInitializeEx(pythoncom.COINIT_APARTMENTTHREADED) # 原有业务逻辑保留 header_request = get_object_or_404(HeaderRequest, id=id_headerRequest) serializer_header_request = HeaderRequestSerializer(header_request) usuario_id = serializer_header_request.data['id_user_id'] require_date = serializer_header_request.data['require_date'] customer = serializer_header_request.data['customer'] engineer_instance = get_object_or_404(Engineers, role='admin') engineer_serializer = EnginnerAdminSerializer(engineer_instance) admin_email = engineer_serializer.data['email'] user_instance = get_object_or_404(Users, id=usuario_id) serializer_user = UserAccountsSerializer(user_instance) full_name = f"{serializer_user.data['first_Name']} {serializer_user.data['last_Name']}" dynamic_link = 'xxxxxxxxxxxxxx' # 创建Outlook实例 outlook = win32.Dispatch('Outlook.Application') mail = outlook.CreateItem(0) mail.SentOnBehalfOfName = 'example@live.com' mail.To = admin_email mail.Subject = 'NUEVA SOLICITUD DE PRUEBAS DE LABORATORIO' html_body = f""" <html> <body> <div> <h1>Nueva solicitud de pruebas de laboratorio de {full_name}</h1> <p>El usuario {full_name} ha creado una nueva solicitud de pruebas de laboratorio para el cliente {customer} con una fecha requerida para el {require_date}</p> <a href="{dynamic_link}"> Ir al Sitio </a> </div> </body> </html> """ mail.HTMLBody = html_body mail.Send() return Response({"message": "Correo enviado correctamente"}, status=status.HTTP_200_OK) except Exception as e: print(f"Error: {e}") return Response({"message": "Correo NO enviado correctamente"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) finally: # 显式销毁COM对象 if mail: del mail if outlook: del outlook # 强制垃圾回收释放资源 import gc gc.collect() # 释放COM线程 pythoncom.CoUninitialize()
4. 额外排查点
- 检查Outlook客户端:关闭"延迟发送"功能,确保处于联机状态,查看发件箱是否有未发送的邮件堆积。
- 权限验证:确认Django运行的系统账户已登录过Outlook,且拥有访问邮箱的权限。
内容的提问来源于stack exchange,提问作者Leonardo Chavira
相关产品推荐
相关产品推荐

