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

Django中测试Amazon SES邮件发送失败:邮件未实际发出

Django中测试Amazon SES邮件发送失败:邮件未实际发出

遇到这种线上正常但测试环境发不出邮件的问题确实头疼,我来帮你梳理几个可能的排查方向和解决方案:

1. 先排查测试环境的AWS SES权限与配置问题

  • 验证IAM用户权限:你测试环境用的IAM用户是否拥有SES的ses:SendEmail或ses:SendRawEmail权限?线上可能用的是EC2实例角色,权限自动继承,但测试环境的独立IAM用户可能没配置这个权限,导致发送请求被AWS拒绝。
  • 检查SES沙盒模式限制:如果你的SES账号还在沙盒模式下,只能发送到已验证的邮箱地址。确认settings.NOTIFICATIONS_TESTERS里的收件邮箱都在AWS SES控制台完成了验证,不然邮件会被悄悄拦截,不会抛出异常但也不会实际发出。
  • 确认区域配置一致性:你配置的区域是ca-central-1,要确保测试环境用的IAM用户、验证的邮箱都属于这个区域,SES的资源是区域隔离的。

2. 确认测试环境的邮件后端未被覆盖

很多Django项目会在测试配置(比如settings/test.py)里把邮件后端替换成内存或控制台后端(django.core.mail.backends.locmem.EmailBackend或console.EmailBackend),来避免实际发邮件。你可以在测试代码里加一行打印确认:

print("当前邮件后端:", settings.EMAIL_BACKEND)

如果输出不是django_ses.SESBackend,那就是测试配置覆盖了线上的设置,需要调整测试环境的配置。

3. 调整连接对象的初始化与使用方式

你当前用mail.get_connection()获取连接,虽然理论上没问题,但可以试试显式初始化SESBackend来确保配置正确加载:

from django_ses import SESBackend
connection = SESBackend(
    aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
    aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
    region_name=settings.AWS_DEFAULT_REGION
)

同时,记得把这个连接对象传给每个EmailMessage,或者确保send_messages用的是这个正确的连接。另外,发送完成后手动关闭连接:

connection.send_messages(emails)
connection.close()

4. 优化信号与断言的时机

  • 信号注册时机:你在测试函数里才连接信号,有可能在创建EmailMessage之后才完成注册,导致信号没触发。建议把信号的连接和断开放到测试类的setUp和tearDown方法里:
    def setUp(self):
        signals.message_sent.connect(_mail_signal_assertion_handler)
    def tearDown(self):
        signals.message_sent.disconnect(_mail_signal_assertion_handler)
    
  • SES统计数据延迟问题:SES的发送统计数据不是实时更新的,你发送邮件后立刻调用get_ses_emails_data,大概率还没拿到最新的统计结果,导致断言失败。可以临时加个短暂等待(虽然测试里用sleep不太优雅,但针对SES这个特例是可行的):
    import time
    connection.send_messages(emails)
    time.sleep(3)  # 等待SES更新统计
    post_data = get_ses_emails_data()
    
    或者更靠谱的方式:放弃依赖SES的API统计,转而检查connection.send_messages的返回值(它会返回成功发送的邮件数量),这样能直接验证发送结果:
    sent_count = connection.send_messages(emails)
    assert sent_count == send_ct
    

5. 开启日志排查隐藏错误

开启Django的DEBUG模式,或者配置日志记录django_ses和boto3的详细日志,看看有没有隐藏的错误信息。比如在发送邮件时捕获异常:

try:
    sent_count = connection.send_messages(emails)
    print(f"成功发送{sent_count}封邮件")
except Exception as e:
    import traceback
    traceback.print_exc()

很多时候AWS会返回详细的错误原因(比如权限不足、邮箱未验证),但django-ses可能不会主动抛出,需要手动捕获查看。


备注:内容来源于stack exchange,提问作者Marc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 08:45:37