Docker容器部署FastAPI应用时Python SMTP邮件发送失败
问题根因
你访问到的{"message":"Hello world! From FastAPI running on Uvicorn with Gunicorn. Using Python 3.7"}是tiangolo/uvicorn-gunicorn-fastapi:python3.7基础镜像内置的演示应用返回的,你的test.py从未被服务加载,核心原因有两点:
- 该基础镜像默认工作目录为
/app,默认启动规则是加载该目录下main.py文件内名为app的FastAPI实例作为服务入口。你在Dockerfile里只是把test.py复制到了容器根目录,既没有放到指定的/app路径,文件名也不符合默认加载规则,服务启动时直接运行了内置演示代码,完全没读到你写的业务逻辑。 - 你的
test.py中root路由函数执行完发邮件逻辑后没有定义返回值,就算代码被正确加载,接口请求也会直接抛出响应格式错误,无法正常完成流程。
修复步骤
1. 修改Dockerfile
将代码复制到镜像指定的/app目录,通过环境变量明确指定服务加载的模块,不需要强制修改test.py的文件名,修改后的内容如下:
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 # 复制依赖文件到工作目录并安装 COPY ./requirements.txt /app/requirements.txt RUN pip install --no-cache-dir -r /app/requirements.txt # 复制业务代码到工作目录 COPY ./test.py /app/test.py # 指定服务加载test.py内的app实例 ENV MODULE_NAME=test
原Dockerfile中添加的find.json无实际作用,可直接删除相关行。
2. 补全路由返回值
在test.py的root函数末尾添加接口返回内容,修改后完整代码如下:
from fastapi import FastAPI import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText app = FastAPI() @app.get("/") async def root(): from_address = 'myemail@harvard.edu' to_address = 'bilalhussain.v1@gmail.com' message = MIMEMultipart('Foobar') message['From'] = from_address message['To'] = to_address content = MIMEText('Here is the second email', 'plain') message.attach(content) mail = smtplib.SMTP('smtp.gmail.com', 587) mail.ehlo() mail.starttls() mail.login(from_address, 'password') mail.sendmail(from_address,to_address, message.as_string()) mail.close() return {"status": "success", "msg": "邮件发送完成"}
3. 重新构建运行容器
依次执行以下命令:
docker build -t test . docker run -p 80:80 -it test
修改完成后再访问http://127.0.0.1/,就不会出现默认演示响应,服务会正常执行发邮件逻辑,最后返回你定义的成功结果。
额外注意事项
- 代码中硬编码了邮箱账号和密码,部署到Azure时建议改为读取环境变量,不要明文存储敏感信息。
- Gmail SMTP服务不支持直接使用账号登录密码鉴权,需要提前在谷歌账号后台生成应用专用密码,同时确认账号开启了SMTP/IMAP权限,否则会出现登录失败问题。
- 部分Azure订阅默认会封禁虚拟机25端口的出站流量,如果后续部署后出现SMTP连接超时问题,优先检查端口限制,可提工单申请解封,或者使用465、587端口提交邮件发送请求。
内容的提问来源于stack exchange,提问作者Eliot Kim
相关产品推荐
相关产品推荐

