Redmail发送邮件过慢:原因排查与批量发送提速方案咨询
邮件发送耗时过长的原因及批量提速方案
问题背景
我最初使用smtplib发送邮件,后来因Redmail语法更简洁转而使用它,但两者发送邮件均耗时较长。测试发送2封邮件时,耗时分别为17.25秒和19.30秒,现在需要批量发送大量邮件,想知道耗时久的原因及提速方法。
我的实现代码
from redmail import outlook import time outlook.username = 'XXXXXXX' outlook.password = 'XXXXXX' def send_email(subject, body, to_email): try: outlook.send( subject=subject, receivers=[to_email], html=body ) print(f"Email sent successfully to {to_email}") except Exception as e: print(f"Email to {to_email} could not be sent. Error: {e}") try: obj = { "name": "John", "start" : "Hi. Hope you are doing good", "end": "Regards" } # 假设data是预先定义好的包含emails和names的字典 for index, recipient in enumerate(data['emails']): obj["name"] = data['names'][index] subject = 'Report' body = generate_html(obj) start_time = time.time() msg = send_email(subject, body, recipient) print(f"Email sent successfully to {recipient}") elapsed_time = time.time() - start_time print(elapsed_time) except Exception as e: print(f"An error occurred: {e}")
耗时过长的原因
- 重复建立SMTP连接:当前代码每发送一封邮件都会重新与Outlook的SMTP服务器建立连接、完成TLS加密协商和身份验证,这个过程本身就需要数秒,是主要耗时点。
- 单线程串行执行:邮件按顺序一封接一封发送,完全没有利用并行处理的优势,总耗时是单封邮件耗时的累加。
- 网络延迟:Outlook SMTP服务器(通常为smtp.office365.com)的响应速度、本地网络到服务器的链路延迟也会影响单封邮件的发送耗时。
批量发送的提速方案
1. 复用SMTP连接
Redmail默认每次发送都会新建连接,手动创建持久连接并复用,可避免重复的连接建立和认证开销:
from redmail import Outlook import time # 创建客户端并提前建立连接 outlook = Outlook( username='XXXXXXX', password='XXXXXX' ) outlook.connect() def send_email(subject, body, to_email): try: outlook.send( subject=subject, receivers=[to_email], html=body ) print(f"Email sent successfully to {to_email}") except Exception as e: print(f"Email to {to_email} could not be sent. Error: {e}") try: obj = { "name": "John", "start": "Hi. Hope you are doing good", "end": "Regards" } for index, recipient in enumerate(data['emails']): obj["name"] = data['names'][index] subject = 'Report' body = generate_html(obj) start_time = time.time() send_email(subject, body, recipient) elapsed_time = time.time() - start_time print(f"Sent to {recipient}, elapsed: {elapsed_time:.2f}s") finally: outlook.close() # 批量完成后关闭连接
2. 多线程并行发送
邮件发送属于网络IO密集型操作,用多线程并行处理可大幅降低总耗时(注意线程数不要过高,避免触发服务器限流):
from redmail import Outlook import time from concurrent.futures import ThreadPoolExecutor outlook = Outlook( username='XXXXXXX', password='XXXXXX' ) outlook.connect() def send_email(subject, body, to_email): try: outlook.send( subject=subject, receivers=[to_email], html=body ) print(f"Email sent successfully to {to_email}") return True except Exception as e: print(f"Email to {to_email} could not be sent. Error: {e}") return False try: obj = { "name": "John", "start": "Hi. Hope you are doing good", "end": "Regards" } # 提前准备所有发送任务 tasks = [] for index, recipient in enumerate(data['emails']): obj["name"] = data['names'][index] subject = 'Report' body = generate_html(obj) tasks.append((subject, body, recipient)) # 用线程池并行发送,建议线程数控制在5-10之间 start_total = time.time() with ThreadPoolExecutor(max_workers=8) as executor: executor.map(lambda args: send_email(*args), tasks) total_elapsed = time.time() - start_total print(f"Total time for all emails: {total_elapsed:.2f}s") finally: outlook.close()
3. 密抄送(BCC)批量发送(适用无个性化内容场景)
如果所有邮件内容完全一致,可将所有收件人放入BCC字段,仅发送一封邮件,耗时最短:
outlook.send( subject='Report', bcc=data['emails'], html=generate_html(obj) )
注意:部分邮箱服务商对BCC收件人数有上限,且此方法不支持个性化内容。
4. 提前批量生成HTML内容
若generate_html函数耗时较长,可提前批量生成所有邮件的HTML,避免发送过程中实时生成:
# 提前生成所有邮件内容 email_contents = [] obj = { "name": "John", "start": "Hi. Hope you are doing good", "end": "Regards" } for index, recipient in enumerate(data['emails']): obj["name"] = data['names'][index] body = generate_html(obj) email_contents.append(('Report', body, recipient)) # 再执行批量发送 with ThreadPoolExecutor(max_workers=8) as executor: executor.map(lambda args: send_email(*args), email_contents)
内容的提问来源于stack exchange,提问作者SunAns
相关产品推荐
相关产品推荐

