使用Flask-Mail在Gmail帐户中未发送邮件 [英] Mail Not Sent In Gmail Account Using Flask-Mail

查看:98
本文介绍了使用Flask-Mail在Gmail帐户中未发送邮件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过向Gmail帐户发送电子邮件来添加重置用户密码的功能.我一直在关注 CoreySchafer YouTube教程

I am trying to add a functionality of resetting user password by sending email to a Gmail account. I have been following CoreySchafer YouTube Tutorial and Miguel Grinberg Tutorial to achieve this.

总体思路是,将向用户提示密码重设请求表",他们将在其中输入要重设密码的电子邮件地址.单击请求重设密码"后,将显示一条消息,表明已将电子邮件发送到其Gmail帐户.通过单击电子邮件中的链接,用户将能够重置其密码.

The overall idea is user will be prompted with a Password Reset Request Form where they will enter the email address for which they want to reset the password. After clicking the "Request Reset Password", a message will be displayed that an email has been sent to their Gmail account. By clicking the link from the email, the user will be able to reset their password.

具有相关文件名的代码如下:

The codes with relevant file names are as follows:

文件:routes.py

File: routes.py

# Reset Password Request Route
@app.route("/reset_password", methods = ["GET", "POST"])
def reset_password_request():

    if current_user.is_authenticated:
        return redirect(url_for("dashboard"))

    form = ResetPasswordRequestForm()

    if form.validate_on_submit():
        user = User.query.filter_by(email = form.email.data).first()
        if user:
            send_password_reset_email(user)
            flash("Please check your email for the instructions to reset your password")
            return redirect(url_for("login"))

    return render_template("reset_password_request.html", title = "Request For Reset Password", form = form)

# Password Reset Route
@app.route("/reset_password/<token>", methods = ["GET", "POST"])
def reset_password(token):
    if current_user.is_authenticated:
        return redirect(url_for("dashboard"))

    user = User.verify_reset_password_token(token)

    if not user:
        flash("Invalid Token")
        return redirect(url_for("reset_password_request"))

    form = ResetPasswordForm()

    if form.validate_on_submit():
        user.set_password(form.password.data)
        db.session.commit()
        flash("Congratulations! Your password has been reset successfully.")
        return redirect(url_for("login"))

    return render_template("reset_password.html", title = "Reset Password", form = form) 

文件:forms.py

File: forms.py

# Reset Password Request Form
class ResetPasswordRequestForm(FlaskForm):
    email = StringField("Email", validators = [DataRequired(message = "Email Address is required."), Email()], render_kw = {"placeholder": "Email Address"})
    submit = SubmitField("Request Password Reset")

    def validate_email(self, email):
        user = User.query.filter_by(email = email.data).first()
        if user is None:
            raise ValidationError("There is no account with that email. You must register first.")

# Password Reset Form
class ResetPasswordForm(FlaskForm):
    password = PasswordField("Password", validators = [DataRequired(message = "Password is required.")], render_kw = {"placeholder": "Password"})
    confirm_password = PasswordField("Repeat Password", validators = [DataRequired(message = "Password Confirmation is required."), EqualTo("password")], render_kw = {"placeholder": "Confirm Password"})
    submit = SubmitField("Reset Password")

文件:email.py

File: email.py

from flask import render_template
from flask_mail import Message
from app import app, mail
from threading import Thread

# Sending Emails Asynchronously
def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)

# Email Sending Wrapper Function
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 = (app, msg)).start()

# Send Password Reset Email Function
def send_password_reset_email(user):
    token = user.get_reset_password_token()

    send_email("【Task Manager】Reset Your Password", 
    sender = app.config["ADMINS"][0], 
    recipients = [user.email], 
    text_body = render_template("email/reset_password.txt", user = user, token = token), 
    html_body = render_template("email/reset_password.html", user = user, token = token))

文件:models.py

File: models.py

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

# Reset Password Support in User Model
def get_reset_password_token(self, expires_sec = 1800):
    s = Serializer(app.config["SECRET_KEY"], expires_sec)
    return s.dumps({"user_id": self.id}).decode("utf-8")

# Verifying Reset Password Token in User Model
@staticmethod
def verify_reset_password_token(token):
    s = Serializer(app.config["SECRET_KEY"])
    try:
        user_id = s.loads(token)["user_id"]
    except:
        return None
    return User.query.get(user_id)

文件:reset_password_request.html

File: reset_password_request.html

{% extends "layout.html" %}

{% block content %}
    <h1>Task Manager</h1>
    <form action="" method="POST">
        {{ form.hidden_tag() }}
        <div>
            {{ form.email(size=64) }}
        </div>
        {% for error in form.email.errors %}
            <span style="color: red;">{{ error }}</span>
        {% endfor %}
        <div>
            {{ form.submit() }}
        </div>
    </form>
{% endblock %}

文件:reset_password.html

File: reset_password.html

{% extends "layout.html" %}

{% block content %}
    <h1>Task Manager</h1>
    <form action="" method="POST" novalidate>
        {{ form.hidden_tag() }}
        <div>
            {{ form.password(size=32) }}
        </div>
        {% for error in form.password.errors %}
            <span style="color: red;">{{ error }}</span>
        {% endfor %}
        <div>
            {{ form.confirm_password(size=32) }}
        </div>
        {% for error in form.confirm_password.errors %}
            <span style="color: red;">{{ error }}</span>
        {% endfor %}
        <div>
            {{ form.submit() }}
        </div>
    </form>
{% endblock %}

我已将环境变量保存在根目录的.env文件中.

I have saved the environment variables in .env file in the root directory.

SECRET_KEY="simple-is-better-than-complex"
MAIL_SERVER="smtp.googlemail.com"
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USERNAME="jeet.java.13"
MAIL_PASSWORD="pass123"

还在项目根目录中创建了config.py文件.

Also created the config.py file in the project root directory.

from dotenv import load_dotenv

load_dotenv(override=True)

import os

basedir = os.path.abspath(os.path.dirname(__file__))

# Application Configurations
class Config(object):

    # Function: Getting Environment Variables
    def get_env_var(name):
        try:
            return os.environ[name]
        except KeyError:
            message = "Expected Environment Variable '{}' Not Set!".format(name)
            raise Exception(message)

    # SECRET_KEY Configuration
    SECRET_KEY = os.getenv("SECRET_KEY")
    SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "tms.db")

    SQLALCHEMY_TRACK_MODIFICATIONS = False

    # EMAIL CONFIGURATION

    MAIL_SERVER = os.getenv("MAIL_SERVER")
    MAIL_PORT = int(os.getenv("MAIL_PORT")) or 25
    MAIL_USE_TLS = os.getenv("MAIL_USE_TLS")
    MAIL_USERNAME = os.getenv("MAIL_USERNAME")
    MAIL_PASSWORD = os.getenv("MAIL_PASSWORD")
    ADMINS = ["jeet.java.13@gmail.com"]

终端结果:

"POST /reset_password HTTP/1.1" 302 -

我还为我的Gmail帐户打开了安全性降低的应用程序",但仍无法发送电子邮件.在执行Flask应用程序期间,终端没有错误.

I have also turned ON the "Less Secure Apps" for my Gmail Account, but the email still can't be sent. There is no error in the terminal during the execution of the Flask Application.

期待您的大力支持.

推荐答案

问题已解决.在定义环境变量时,MAIL_USERNAME必须是完整的电子邮件(Gmail)地址;不仅是Gmail ID.

Problem solved. While defining the environment variables, MAIL_USERNAME need to be the full email(Gmail) address; not only the Gmail ID.

这篇关于使用Flask-Mail在Gmail帐户中未发送邮件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆