Flask-Mail初始化报错:__init__()仅接受1个位置参数但传入2个
Flask-Mail初始化Message报错:TypeError: init() takes 1 positional argument but 2 were given
问题背景
开发基于FastAPI挂载Flask的网站,实现邮件确认路由时触发上述错误,且单独使用Flask也会出现该问题。
相关代码
app.init.py
from flask import Flask from flask_bootstrap import Bootstrap from app.config import DevelopmentConfig from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager from fastapi import FastAPI, Request from fastapi.middleware.wsgi import WSGIMiddleware from flask_migrate import Migrate app = FastAPI() flask_app = Flask(__name__) app.mount("/", WSGIMiddleware(flask_app))
运行文件
from app import app import uvicorn if __name__ == "__main__": uvicorn.run(app)
视图文件(views.py)
from app import flask_app from flask import render_template, request, redirect, url_for, abort, flash from itsdangerous import URLSafeTimedSerializer, TimestampSigner from flask_mail import Mail, Message mail = Mail() mail.init_app(flask_app) serializer = URLSafeTimedSerializer(flask_app.config["SECRET_KEY"]) timestamp = TimestampSigner(flask_app.config["SECRET_KEY"]) @flask_app.route("/confirm", methods=["POST", "GET"]) @login_required def confirm(): image = get_photo("cafe") user_email = current_user.email message = "请点击下方链接确认你的邮箱地址" token = serializer.dumps(user_email, salt="email-confirm") unsubscribe_token = serializer.dumps(user_email, salt="unsubscribe") link = url_for("confirm_email", token=token, _external=True) unsubscribe = url_for("unsubscribe", token=unsubscribe_token, _external=True) site_mail = flask_app.config["MAIL_USERNAME"] print(site_mail) msg = Message("Confirm Email", sender=site_mail, recipients=user_email) msg.body = render_template("public/email/single-news.html", user=current_user, link=link, image=image, message=message, unsubscribe=unsubscribe) msg.html = render_template("public/email/single-news.html", user=current_user, link=link, image=image, message=message, unsubscribe=unsubscribe) mail.send(msg) return redirect(url_for("index"))
Flask配置文件
class Config: DEBUG = True TESTING = False SESSION_COOKIE_SECURE = True SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:tool789@localhost/city" SQLALCHEMY_TRACK_MODIFICATIONS = False JSON_AS_ASCII = True JSON_SORT_KEYS = True IJSONFY_MIMETYPE = 'application/json' SECRET_KEY = "b'\xf1L\xdb5D\x96M\xe5\xd1\x9f\x16+\xf4%A\x1e\xb9\xafm\xb8g\x1ct\x0e'" MAIL_SERVER = "smtp.gmail.com" MAIL_USERNAME = "myemail" MAIL_PASSWORD = "password" MAIL_PORT = 465 MAIL_DEBUG = False MAIL_USE_SSL = True MAIL_USE_TSL = False
错误信息
FastAPI搭配Flask时的报错
INFO: 127.0.0.1:60517 - "GET /confirm HTTP/1.1" 500 Internal Server Error ERROR: Exception in ASGI application Traceback (most recent call last): File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 429, in run_asgi result = await app( # type: ignore[func-returns-value] File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 78, in __call__ return await self.app(scope, receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\fastapi\applications.py", line 276, in __call__ await super().__call__(scope, receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\applications.py", line 122, in __call__ await self.middleware_stack(scope, receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__ raise exc File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\errors.py", line 162, in __call__ await self.app(scope, receive, _send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\exceptions.py", line 79, in __call__ raise exc File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\exceptions.py", line 68, in __call__ await self.app(scope, receive, sender) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__ raise e File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__ await self.app(scope, receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\routing.py", line 718, in __call__ await route.handle(scope, receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\routing.py", line 443, in handle await self.app(scope, receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\wsgi.py", line 71, in __call__ await responder(receive, send) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\wsgi.py", line 98, in __call__ await anyio.to_thread.run_sync(self.wsgi, environ, self.start_response) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\anyio\to_thread.py", line 31, in run_sync return await get_asynclib().run_sync_in_worker_thread( File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 937, in run_sync_in_worker_thread return await future File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 867, in run result = context.run(func, *args) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\starlette\middleware\wsgi.py", line 132, in wsgi for chunk in self.app(environ, start_response): File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 2551, in __call__ return self.wsgi_app(environ, start_response) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 2531, in wsgi_app response = self.handle_exception(e) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 2528, in wsgi_app response = self.full_dispatch_request() File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 1825, in full_dispatch_request rv = self.handle_user_exception(e) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 1823, in full_dispatch_request rv = self.dispatch_request() File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 1799, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask_login\utils.py", line 290, in decorated_view return current_app.ensure_sync(func)(*args, **kwargs) File "C:\Users\Pourya\PycharmProjects\favoritecafe\app\views.py", line 260, in confirm msg = Message("Confirm Email", sender=site_mail, recipients=user_email) TypeError: __init__() takes 1 positional argument but 2 were given
单独使用Flask时的报错
127.0.0.1 - - [09/Apr/2023 18:21:09] "GET /confirm HTTP/1.1" 500 - Traceback (most recent call last): File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 2551, in __call__ return self.wsgi_app(environ, start_response) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 2531, in wsgi_app response = self.handle_exception(e) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 2528, in wsgi_app response = self.full_dispatch_request() File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 1825, in full_dispatch_request rv = self.handle_user_exception(e) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 1823, in full_dispatch_request rv = self.dispatch_request() File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask\app.py", line 1799, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) File "C:\Users\Pourya\PycharmProjects\favoritecafe\venv\lib\site-packages\flask_login\utils.py", line 290, in decorated_view return current_app.ensure_sync(func)(*args, **kwargs) File "C:\Users\Pourya\PycharmProjects\favoritecafe\app\views.py", line 258, in confirm msg = Message("Confirm", sender=site_mail, recipients=user_email) TypeError: __init__() takes 1 positional argument but 2 were given
解决方案
核心原因
- Flask-Mail版本差异:新版Flask-Mail(如3.x系列)重构了
Message类,构造函数不再支持位置参数传邮件标题,必须用subject关键字参数指定;旧版虽支持位置参数,但recipients要求传入列表而非单个字符串。 - 参数格式错误:
recipients参数需传入列表类型,直接传单个邮箱字符串会导致参数解析异常。
修复步骤
- 调整Message初始化代码
将原代码:
msg = Message("Confirm Email", sender=site_mail, recipients=user_email)
修改为对应版本的写法:
- 若使用新版Flask-Mail(3.x+):
msg = Message(subject="Confirm Email", sender=site_mail, recipients=[user_email])
- 若使用旧版Flask-Mail(0.9.1及以下):
msg = Message("Confirm Email", sender=site_mail, recipients=[user_email])
重点:无论版本,recipients必须用列表包裹,即使只有一个收件人。
- 确认Flask-Mail版本
执行命令查看当前版本:
pip show flask-mail
根据版本选择对应的初始化方式,避免版本不兼容问题。
- 加载Flask配置
在app.__init__.py中添加配置加载代码,否则邮件配置不会生效:
# 假设你使用的是Config类 from app.config import Config flask_app.config.from_object(Config)
内容的提问来源于stack exchange,提问作者Pourya Mohamadi
相关产品推荐
相关产品推荐

