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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:57:46