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

如何解决Fake SMTP服务器不支持SMTP AUTH认证的问题?

解决aiosmtpd模拟SMTP服务器不支持AUTH认证的问题

我编写了一个创建SMTP客户端、登录服务器并发送邮件的函数,想要通过Fake SMTP服务器做单元测试,把邮件内容写入IO流而非实际发送。但登录环节触发以下错误:

smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server.

最小可复现示例(MRE)

import email.message
import io
import smtplib

import aiosmtpd.controller
import aiosmtpd.handlers
import aiosmtpd.smtp


def foobar(host, port):
    client = smtplib.SMTP(host=host, port=port)
    message = email.message.EmailMessage()
    message["From"] = "me@me.me"
    message["To"] = "you@you.you"
    message["Subject"] = "subject"
    message.set_content("Hello World")
    with client as session:
        session.login("foo", "bar")
        session.send_message(message)


def test_foobar():
    io_stream = io.StringIO()
    handler = aiosmtpd.handlers.Debugging(io_stream)
    controller = aiosmtpd.controller.Controller(handler)
    controller.start()
    foobar(controller.hostname, controller.port)
    controller.stop()

    assert "Hello World" in io_stream.getvalue()

依赖要求

pip install aiosmtpd

已尝试的修复方案

添加认证器

按照官方文档说明,aiosmtpd的认证功能默认激活,但需设置有效认证回调才会通过认证,于是添加了认证器:

[...]

def test_foobar():
    
    def authenticator(*args, **kwargs):
        return aiosmtpd.smtp.AuthResult(success=True)
    
    [...]
    controller = aiosmtpd.controller.Controller(handler, authenticator=authenticator)
    [...]

结果:仍报相同错误

自定义Handler实现认证方法

参考文档,继承Debugging Handler并实现handle_AUTH和具体认证机制方法:

[...]

class CustomDebugging(aiosmtpd.handlers.Debugging):

    async def handle_AUTH(self, *arg, **kwargs):
        return aiosmtpd.smtp.AuthResult(success=True)

    async def auth_PLAIN(self, *arg, **kwargs):
        return aiosmtpd.smtp.AuthResult(success=True)

    async def auth_LOGIN(self, *arg, **kwargs):
        return aiosmtpd.smtp.AuthResult(success=True)

def test_foobar():

    def authenticator(*args, **kwargs):
        return aiosmtpd.smtp.AuthResult(success=True)

    handler = CustomDebugging(io_stream)
    controller = aiosmtpd.controller.Controller(
        handler, authenticator=authenticator
    )
    [...]

结果:仍报相同错误


解决方案

问题核心是aiosmtpd默认SMTP类不会主动向客户端声明支持AUTH扩展,即便配置了认证器也无效。需要自定义SMTP类,在协议响应中添加AUTH支持声明,同时实现对应认证逻辑。

修改后的完整测试代码如下:

import email.message
import io
import smtplib

import aiosmtpd.controller
import aiosmtpd.handlers
import aiosmtpd.smtp
from aiosmtpd.smtp import AuthResult


class AuthEnabledSMTP(aiosmtpd.smtp.SMTP):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 向客户端声明支持PLAIN和LOGIN两种认证机制
        self.extensions["AUTH"] = "PLAIN LOGIN"

    async def auth_PLAIN(self, arg):
        # 测试场景下直接返回认证成功,可根据需求自定义校验逻辑
        return AuthResult(success=True)

    async def auth_LOGIN(self, arg):
        # 处理LOGIN认证请求,同样直接返回成功
        return AuthResult(success=True)


def foobar(host, port):
    client = smtplib.SMTP(host=host, port=port)
    message = email.message.EmailMessage()
    message["From"] = "me@me.me"
    message["To"] = "you@you.you"
    message["Subject"] = "subject"
    message.set_content("Hello World")
    with client as session:
        session.login("foo", "bar")
        session.send_message(message)


def test_foobar():
    io_stream = io.StringIO()
    handler = aiosmtpd.handlers.Debugging(io_stream)
    # 指定控制器使用自定义的支持AUTH的SMTP类
    controller = aiosmtpd.controller.Controller(
        handler,
        smtp_factory=AuthEnabledSMTP
    )
    controller.start()
    try:
        foobar(controller.hostname, controller.port)
        assert "Hello World" in io_stream.getvalue()
    finally:
        controller.stop()

关键说明

  1. 自定义SMTP类:继承aiosmtpd.smtp.SMTP,在初始化时给self.extensions添加"AUTH"项,明确告知客户端支持的认证机制(PLAIN和LOGIN是smtplib.login默认尝试的机制)。
  2. 实现认证方法:必须对应实现auth_PLAIN和auth_LOGIN方法,返回AuthResult(success=True)来通过认证。
  3. 指定SMTP工厂:创建Controller时传入smtp_factory=AuthEnabledSMTP,让服务器使用支持AUTH的SMTP实例。

修改后,客户端调用login时,服务器会正确响应AUTH扩展支持,认证请求会被通过,邮件内容也能正常写入IO流,测试可顺利执行。

内容的提问来源于stack exchange,提问作者Dorian Turba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:23:24