I'm following this tutorial: http://blog.miguelgrinberg.com/post/using-celery-with-flask .
I've imported all the packages and running the app I've got no errors. But when I press send, I'm not getting any mail in my mail account. I've added a print statement in the send_async_email. It seems the celery task is not executing. My code:
app = Flask(__name__)
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
app.config['SECRET_KEY'] = 'super_secret_key'
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = 'my_mail#gmail.com'
app.config['MAIL_PASSWORD'] = 'password'
app.config['MAIL_DEFAULT_SENDER'] = 'sender#gmail.com'
mail = Mail(app)
#celery.task
def send_async_email(msg):
print "msg sent"
with app.app_context():
mail.send(msg)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('index.html', email=session.get('email', ''))
email = request.form['email']
session['email'] = email
# send the email
msg = Message('Hello from Flask',
sender=app.config['MAIL_USERNAME'],
recipients=['ikram.tanjib#gmail.com'])
msg.body = 'This is a test email sent from a background Celery task.'
if request.form['submit'] == 'Send':
# send right away
send_async_email.apply_async(args=[msg])
flash('Sending email to {0}'.format(email))
else:
# send in one minute
send_async_email.apply_async(args=[msg], countdown=60)
flash('An email will be sent to {0} in one minute'.format(email))
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
Edit: Solved my own problem
I didn't start the celery worker venv/bin/celery worker -A app.celery --loglevel=info.
In project folder activated virtualenv and ran the celery worker venv/bin/celery worker -A app.celery --loglevel=info. And now it's working.
Related
I have a Flask server.
In route.py I have this:
from flask_mail import Mail
app = flask.Flask(__name__, static_folder='static')
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'source#gmail.com'
app.config['MAIL_PASSWORD'] = 'password.'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail= Mail(app)
I want to send mail in a function situated in another script using flask_mail.Message() and mail.send, how can I do it?
have a look at this example:
email.py
from flask_mail import Message
from app import mail
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
mail.send(msg)
source: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-x-email-support
(Great tutorial on flask in general)
I am trying to understand this tutorial code.
from flask import Flask
from flask_mail import Mail, Message
app =Flask(__name__)
mail=Mail(app) # <-- This
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId#gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app) # <-- This
#app.route("/")
def index():
msg = Message('Hello', sender = 'yourId#gmail.com', recipients = ['id1#gmail.com'])
msg.body = "Hello Flask message sent from Flask-Mail"
mail.send(msg)
return "Sent"
if __name__ == '__main__':
app.run(debug = True)
At the line 5 and 13, Mail object are instantiated and assigned to mail.
Even if I comment out the first instantiation in line 5, I can still send emails, so can I say it is just a typo, or it is necessary?
The first mail=Mail(app) is not needed. The primary fuctionality in the Mail() constructor is to read the app configuration. So since the appropriate app config variables are not set before line 5, the first Mail() object would likely not even work.
I've just started working with Celery on my latest project with work; I'm having a bit of trouble with executing tasks asynchronously.
All the code is taken from Miguel Grinbergs 'Using Celery with Flask'
When sending the mail without executing a task, it sends perfectly fine. Though when I attempt to send the mail delayed, it fails out giving me an error as follows.
smtplib.SMTPSenderRefused: (530, b'5.5.1 Authentication Required. Learn more at\n5.5.1 https://support.google.com/mail/answer/14257 h19sm960819igq.6 - gsmtp', 'email-removed#gmail.com')
Here's the code I'm using, in my Flask app.
import os
import time
from flask import Flask, request, render_template, session, flash, redirect, url_for, jsonify
from flask.ext.mail import Mail, Message
from celery import Celery
app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-duper-secret'
# Celery Configuration
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
# Configuration for Flask-Mail
app.config['MAIL_SERVER'] = "smtp.gmail.com"
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USERNAME'] = 'email-removed#gmail.com'
app.config['MAIL_PASSWORD'] = 'password-removed'
app.config['MAIL_DEFAULT_SENDER'] = 'email-removed#gmail.com'
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
mail = Mail(app)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('index.html', email=session.get('email', ''))
email = request.form['email']
session['email'] = email
msg = Message("Hello from Flask", recipients=[email])
msg.body = "This is a test message from the flask application!"
if request.form['submit'] == "Send":
send_async_email(msg)
flash('Sending email to {0}'.format(email))
else:
send_async_email.apply_async(args=[msg], countdown=20)
flash('An email to {0} will be sent in a minute.'.format(email))
return redirect(url_for('index'))
#celery.task()
def send_async_email(msg):
with app.app_context():
mail.send(msg)
if __name__ == "__main__":
app.run(debug=True)
I'd appreciate some insight, and perhaps an explanation on how to make this work, and why it isn't working.
I've also looked upon other threads here, and turned on insecure-application access for my google accounts, along with nulling the captcha as suggested in the errors returned URL.
I am trying to follow this tutorial. When I try to submit the contact form, which should trigger the email, I get an internal server error. The error log says:
RuntimeError: The curent application was not configured with Flask-Mail
The instructions say to use from flask.ext.mail to import but I've seen that it might be from flask_mail now. I've also tried changing the mail port from 465 to 587. Neither of these changes have been fixed the problem. My most up to date code is:
from flask import Flask, render_template, request, flash
from forms import ContactForm
from flask_mail import Mail, Message
mail = Mail()
app = Flask(__name__)
app.secret_key = 'development key'
app.config["MAIL_SERVER"] = "smtp.gmail.com"
app.config["MAIL_PORT"] = 587
app.config["MAIL_USE_SSL"] = True
app.config["MAIL_USERNAME"] = 'contact_email#gmail.com' ## CHANGE THIS
app.config["MAIL_PASSWORD"] = 'password'
mail.init_app(app)
app = Flask(__name__)
app.secret_key = 'Oh Wow This Is A Super Secret Development Key'
#app.route('/')
def home():
return render_template('home.html')
#app.route('/about')
def about():
return render_template('about.html')
#app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if request.method == 'POST':
if form.validate() == False:
flash('All fields are required.')
return render_template('contact.html', form=form)
else:
msg = Message(form.subject.data, sender='contact_email#gmail.com', recipients=['recipient#gmail.com'])
msg.body = """
From: %s <%s>
%s
""" % (form.name.data, form.email.data, form.message.data)
mail.send(msg)
return render_template('contact.html', success=True)
elif request.method == 'GET':
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
You created a second app (presumably by accident) after configuring the initial app. Right now the "first" app is configured and has the extension registered, but the "second" app is used to register the routes and call .run().
Remove the line after mail.init_app(app), the second app = Flask(__name__) that creates another app.
I have a sample web application (flask with flask-login running on heroku) at this URL: http://twittaclone.herokuapp.com.
When I run it on my localhost the login functionality works fine. When I push to heroku it freaks out and does not allow users to login (it does allow user registration). Database modifications are being made.
Why would flask login not work on heroku?
app = Flask(__name__)
mysql = MySQL()
app.config['MYSQL_DATABASE_HOST'] = os.environ['MYSQL_DATABASE_HOST'] if 'MYSQL_DATABASE_HOST' in os.environ else config.MYSQL_DATABASE_HOST
app.config['MYSQL_DATABASE_PORT'] = os.environ['MYSQL_DATABASE_PORT'] if 'MYSQL_DATABASE_PORT' in os.environ else config.MYSQL_DATABASE_PORT
app.config['MYSQL_DATABASE_USER'] = os.environ['MYSQL_DATABASE_USER'] if 'MYSQL_DATABASE_USER' in os.environ else config.MYSQL_DATABASE_USER
app.config['MYSQL_DATABASE_PASSWORD'] = os.environ['MYSQL_DATABASE_PASSWORD'] if 'MYSQL_DATABASE_PASSWORD' in os.environ else config.MYSQL_DATABASE_PASSWORD
app.config['MYSQL_DATABASE_DB'] = os.environ['MYSQL_DATABASE_DB'] if 'MYSQL_DATABASE_DB' in os.environ else config.MYSQL_DATABASE_DB
mysql.init_app(app)
if 'SECRET_KEY' in os.environ: app.config['SECRET_KEY'] = os.environ['SECRET_KEY']
else: app.config['SECRET_KEY'] = os.urandom(24)
def connect_db(): return mysql.connect()
###
# Routing for your application.
###
login_manager = LoginManager()
login_manager.login_view = "login"
#login_manager.user_loader
def load_user(username):
g.db = connect_db()
return get_user(username)
login_manager.init_app(app)
#app.route('/')
def home(): return render_template('home.html')
def connect_db(): return mysql.connect()
#app.before_request
def before_request():
g.user = current_user
g.db = connect_db()
#app.teardown_request
def tear_down(exception):
g.db.close()
#app.route('/main/')
#login_required
def main():
print("in main")
tweets, user = get_main()
follower_count, followee_count = get_follower_info(g.user.username)
return render_template('main.html', user=user, tweets=tweets, followercount = follower_count, followeecount = followee_count)
#app.route('/login/', methods=['GET', 'POST'])
def login():
"""Logs the user in."""
if request.method == 'GET':
if current_user is user_logged_in: logout_user()
error = None
if request.method == 'POST':
user = get_user(request.form['username'])
if user is None:
error = 'Invalid username'
elif not check_password_hash(user.password, request.form['password']):
error = 'Invalid password'
else:
flash('You were logged in')
login_user(user)
return redirect(url_for('main'))
return render_template('login.html', error=error)
Many years later but this solves your issue: Heroku gunicorn flask login is not working properly
Updated Procfile:
web: gunicorn app:app --preload
Documentation on preloading for gunicorn: https://docs.gunicorn.org/en/stable/settings.html
I'm pretty sure that Heroku uses PostgreSQL. Try referring to their documents https://devcenter.heroku.com/articles/heroku-postgresql