首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用flask-mail验证电子邮件

使用flask-mail验证电子邮件
EN

Stack Overflow用户
提问于 2020-08-25 22:54:45
回答 3查看 2K关注 0票数 1

我希望使用flask-mail将电子邮件验证添加到我的web应用程序中,在阅读文档后,我似乎必须使用以下命令创建一个Mail实例:

代码语言:javascript
复制
app = Flask(__name__)
mail = Mail(app)

然后导入应用程序和邮件实例。

但是,我当前的代码在一个函数中创建了Flask和Mail实例,如下所示:

代码语言:javascript
复制
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager 

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)

    app.config["SECRET_KEY"] = "9OLWxND4o83j4K4iuopO"
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite"

    db.init_app(app)

    login_manager = LoginManager()
    login_manager.login_view = "auth.login"
    login_manager.init_app(app)

    from .models import User

    @login_manager.user_loader
    def load_user(user_id):
        return User.query.get(int(user_id))

    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint)

    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

上面的代码在我的__init__.py文件中。我不能将Mail实例导入到我注册用户的其他文件中,因为实际上还没有定义一个用户,它只在一个函数中。基本代码来自本教程:https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login,现在我在其中添加了电子邮件验证功能。要运行web应用程序,我在Python REPL中输入db.create_all(app=create_app()),这将创建我的sqlite数据库,并且create_all()函数是唯一被调用的时候。然后我在我的powershell终端中输入Flask run

EN

回答 3

Stack Overflow用户

发布于 2020-08-25 23:34:21

解决方案是两阶段初始化,几乎所有Flask扩展都支持:

代码语言:javascript
复制
from flask import Flask
from flask_mail import Mail

mail = Mail()


def create_app():
    app = Flask(__name__)
    ...
    mail.init_app(app)
    ...

这允许您从另一个模块导入mail

我最近刚刚实现了电子邮件验证,我遵循了这个旧的,但仍然有效的教程:

http://www.patricksoftwareblog.com/confirming-users-email-address/

票数 0
EN

Stack Overflow用户

发布于 2021-04-21 02:05:58

与许多其他扩展一样,在安装flask-mail之后,您需要在__init__.py文件中创建一个mail对象。使用如下所示的结构,使用蓝图,您可以在flask应用程序中添加电子邮件支持。

代码语言:javascript
复制
project_folder
    | --- app.py
    | --- config.py
    | --- app/
          | --- email.py
          | --- models.py
          | --- __init__.py
          | --- main/
                 | --- __init__.py
                 | --- routes.py
                 | --- email.py
          | --- auth/
                 | --- __init__.py
                 | --- routes.py
          | --- templates/
                 | --- auth/
                        | --- register.html

在应用程序工厂中创建mail对象:

代码语言:javascript
复制
# app/__init.py

from flask import Flask
from flask_mail import Mail
# ...

mail = Mail()
# ...


def create_app():
    app = Flask(__name__)
    # ...

    mail.init_app(app)
    # ...

创建一个电子邮件模块,该模块将处理应用程序的所有电子邮件支持需求,如下所示:

代码语言:javascript
复制
# app/email.py

from threading import Thread
from flask import current_app
from flask_mail import Message
from app import mail


def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)


def send_email(subject, sender, recipients, text_body, html_body):
    msg = Message(subject, sender=sender, recipients=recipients)
    msg.body = text_body
    msg.html = html_body
    Thread(target=send_async_email,
           args=(current_app._get_current_object(), msg)).start()

上面,我已经导入了我们在__init__.py文件中创建的mail。因为我们使用的是工厂函数,所以我从flask导入了current_app,这将有助于访问应用程序的配置变量。这些变量是完成电子邮件支持所必需的。线程化可确保应用程序在执行电子邮件设置时不会变慢。

我假设你想发送一封电子邮件给一个已经注册的用户。因此,在auth包中,您将需要创建一个helper方法来向用户发送电子邮件。

代码语言:javascript
复制
# app/auth/email.py

from flask import render_template, current_app
from app.email import send_email


def send_congrats_email(user):
    send_email('[Congrats] You are registered'),
               sender=current_app.config['ADMINS'][0],
               recipients=[user.email],
               text_body=render_template('email/reset_password.txt',
                                         user=user),
               html_body=render_template('email/reset_password.html',
                                         user=user)

在您的auth/routes.py中,创建一个用于注册的视图函数:

代码语言:javascript
复制
# app/auth/routes.py

from app.auth.email import send_congrats_email

@bp.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('main.index'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        send_congrats_email(user)
        flash('Check your email for our congrats message')
        return redirect(url_for('auth.login'))
    return render_template('auth/register.html', title='Register',
                           form=form)

确保在config模块中设置了电子邮件配置:

代码语言:javascript
复制
import os 
from dotenv import load_dotenv

basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(basedir, '.env')


class Config(object):
    # Database configuration
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL?ssl=require') or \
        'sqlite:///' + os.path.join(basedir, 'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    # Form protection
    SECRET_KEY = os.environ.get('SECRET_KEY')

    # Email configuration
    MAIL_SERVER = os.environ.get('MAIL_SERVER')
    MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
    MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    ADMINS = os.environ.get('ADMINS')

这样,当调用register()视图函数时,您的电子邮件消息(在app/templates/email/中的模板中可以看到)将发送给新注册的用户。

票数 0
EN

Stack Overflow用户

发布于 2022-01-31 21:59:57

我最近遇到了同样的问题,我决定通过为(我的)电子邮件库创建一个Flask扩展来解决它。这个扩展(Flask-Redmail)非常类似于Flask-Mail,但它的功能更丰富,并且依赖于一个经过良好测试和健壮的库,称为Red Mail

我在这里写下了我是如何做到的:https://flask-redmail.readthedocs.io/en/latest/cookbook.html#verification-email

简而言之,您需要做的是:

  • 获取电子邮件(和密码)用户以未经验证的用户身份将用户specified
  • Store到您的用户数据库
  • 使用标识用户的唯一URL向用户发送电子邮件
  • 创建此URL端点并将用户设置为在访问时进行验证。

为了实现这些,我建议使用:

用于创建唯一tokens

接下来,我将演示如何做到这一点。为您的应用程序创建文件(即app.py):

代码语言:javascript
复制
from flask import Flask
from flask_redmail import RedMail¨
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

email = RedMail()
db = SQLAlchemy()
login_manager = LoginManager()

def create_app():
    app = Flask(__name__)
    
    # Configure the sender
    app.config["EMAIL_HOST"] = "localhost"
    app.config["EMAIL_PORT"] = 587
    app.config["EMAIL_USER"] = "me@example.com"
    app.config["EMAIL_PASSWORD"] = "<PASSWORD>"

    # Set some other relevant configurations
    app.config["SECRET_KEY"] = "GUI interface with VBA"
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app_data.db"

    email.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)

    # Import and set the blueprints/routes
    ...

创建用户类并将登录名设置为models.py

代码语言:javascript
复制
from app import db, login_manager
from flask_login import UserMixin

@login_manager.user_loader
def load_user(user_id):
    return User.query.filter_by(id=user_id).first()

class User(UserMixin, db.Model):
    __tablename__ = 'user'

    email = db.Column(db.String, primary_key=True)
    password = db.Column(db.String, nullable=False)
    verified = db.Column(db.Boolean, default=False)

然后是路径,例如作为views.py

代码语言:javascript
复制
from flask import request, current_app, abort, render_template, BluePrint

# Import your custom instances and models
from app import email, db
from models import User

auth_page = Blueprint('auth', __name__)

@auth_page.route("/create-user", methods=["GET", "POST"])
def create_user():
    if request.method == "GET":
        return render_template("create_user.html")
    elif request.method == "POST":
        # Now we create the user

        # Getting form data (what user inputted)
        data = request.form.to_dict()
        email = data["email"]
        password = data["password"]

        # Verifying the user does not exist
        old_user = User.query.filter_by(id=email).first()
        if old_user:
            abort(403)

        # Encrypt the password here (for example with Bcrypt)
        ...

        # Creating the user
        user = User(
            email=email, 
            password=password,
            verified=False
        )
        db.session.add(user)
        db.session.commit()

        # Create a secure token (string) that identifies the user
        token = jwt.encode({"email": email}, current_app.config["SECRET_KEY"])
        
        # Send verification email
        email.send(
            subject="Verify email",
            receivers=email,
            html_template="email/verify.html",
            body_params={
                "token": token
            }
        )

然后我们创建电子邮件正文。默认情况下,Flask-Redmail会从应用程序的Jinja环境中查找HTML模板。只需创建文件templates/email/verify.html即可完成此操作

代码语言:javascript
复制
<h1>Hi,</h1>
<p>
    in order to use our services, please click the link below:
    <be>
    <a href={{ url_for('verify_email', token=token, _external=True) }}>verify email</a>
</p>
<p>If you did not create an account, you may ignore this message.</p>

最后,我们创建一个路由来处理验证:

代码语言:javascript
复制
@auth_page.route("/vefify-email/<token>")
def verify_email(token):
    data = jwt.decode(token, current_app.config["SECRET_KEY"])
    email = data["email"]

    user = User.query.filter_by(email=email).first()
    user.verified = True
    db.session.commit()

请注意,您需要在存储User类的位置执行templates/create_user.htmlmodels.py

一些相关链接:

有关Red Mail的更多信息:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63581599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档