使用Azure Communication Email Python SDK异步发件报错求助
问题分析与解决思路
一、object NoneType can't be used in 'await' expression异常原因
你使用了Azure Communication Email的同步客户端EmailClient,它的begin_send()返回的是同步Poller对象,其wait()方法返回None,而你对None使用了await,因此抛出异常。
二、解决异常并实现真正异步发送的步骤
1. 替换为异步客户端AsyncEmailClient
Azure SDK提供了异步版本的邮件客户端,解决同步Poller的await问题:
- 导入异步客户端:
from azure.communication.aio.email import AsyncEmailClient - 使用
AsyncEmailClient.from_connection_string()创建客户端,并用异步上下文管理(async with)确保资源正确释放 - 异步客户端的
begin_send()、poller.wait()、poller.result()均为可await方法,不会返回None
2. 修改后的核心代码
from azure.communication.aio.email import AsyncEmailClient import os import asyncio class Email(Configuration): def __init__(self): super().__init__() self.logger_file = 'email_exception.log' async def send_mail(self, email_content: dict, email_recipient: str = None): print(f" sending email called") error = False message = "Success" recipient_address = email_recipient or os.getenv("RECIPIENT_EMAIL_ADDRESS") try: content = { "senderAddress": sender_address, "recipients": { "to": [{"address": recipient_address}, {"address": recipient_address}], "cc": [{"address": recipient_address}], "bcc": [{"address": recipient_address}] }, "content": email_content } # 初始化异步客户端并通过async with管理 async with AsyncEmailClient.from_connection_string(connection_string) as client: # 异步触发邮件发送 poller = await client.begin_send(content) time_elapsed = 0 while not poller.done(): await poller.wait(POLLER_WAIT_TIME) time_elapsed += POLLER_WAIT_TIME if time_elapsed > 18 * POLLER_WAIT_TIME: raise RuntimeError("Polling timed out.") # 异步获取发送结果 result = await poller.result() if result["status"] == "Succeeded": print(f"Successfully sent the emails (operation id: {result['id']})") return error, message else: raise RuntimeError(str(result["error"])) except Exception as ex: self.logger.error(f"exception was thrown when sending email {str(ex)}") error = True message = str(ex) return error, message
3. 实现真正的异步调用
当前代码修改后,若直接调用await email.send_mail()仍会阻塞主流程。要实现非阻塞的异步发送,需将邮件任务提交到事件循环后台执行:
async def main(): email = Email() email_content = {"subject": "Test", "plainText": "Hello"} # 提交后台任务,主流程无需等待发送完成 asyncio.create_task(email.send_mail(email_content)) # 执行其他业务逻辑... asyncio.run(main())
关键注意点
- 异步客户端必须配合
async with使用,避免资源泄漏 - 多次调用时,用
asyncio.create_task可并行执行多个邮件发送任务,大幅提升效率 - 若需要监听发送结果,可通过
asyncio.gather()或任务的result()方法获取,但需注意异常处理
内容的提问来源于stack exchange,提问作者ira
相关产品推荐
相关产品推荐

