fabee
fabee

Reputation: 545

Flask mail does not send mail when DEBUG=False

I am writing a little web application based on Miguel Grinberg's Flasky. I use the exact same code for user confirmation emails. When DEBUG=True (for Flask), everything works like a charm. When DEBUG=False, however, I get the following error:

Traceback (most recent call last):
 File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
 File "/usr/lib/python3.4/threading.py", line 868, in run
 self._target(*self._args, **self._kwargs)
 File "/home/fabee/code/rowbot/app/email.py", line 9, in send_async_email
    mail.send(msg)
  File "/usr/local/lib/python3.4/dist-packages/flask_mail.py", line 491, in send
    with self.connect() as connection:
  File "/usr/local/lib/python3.4/dist-packages/flask_mail.py", line 144, in __enter__
self.host = self.configure_host()
  File "/usr/local/lib/python3.4/dist-packages/flask_mail.py", line 163, in configure_host
host.starttls()
  File "/usr/lib/python3.4/smtplib.py", line 671, in starttls
self.ehlo_or_helo_if_needed()
  File "/usr/lib/python3.4/smtplib.py", line 569, in ehlo_or_helo_if_needed
if not (200 <= self.ehlo()[0] <= 299):
  File "/usr/lib/python3.4/smtplib.py", line 423, in ehlo
self.putcmd(self.ehlo_msg, name or self.local_hostname)
  File "/usr/lib/python3.4/smtplib.py", line 349, in putcmd
self.send(str)
  File "/usr/lib/python3.4/smtplib.py", line 341, in send
raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first

I find this really hard to debug because I do not really understand what DEBUG=True really implies. Any hints and help on that is greatly appreciated.

Edit: Code

This is the file with the email methods:

from threading import Thread
from flask import current_app, render_template
from flask.ext.mail import Message
from . import mail


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

def send_email(to, subject, template, **kwargs):
    app = current_app._get_current_object()
    msg = Message(app.config['MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)

    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr

This is the code where mail gets created:

bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
pagedown = PageDown()

login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'


def create_app(config_name):
    app = Flask(__name__)
    QRcode(app)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    bootstrap.init_app(app)
    mail.init_app(app)
    moment.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    pagedown.init_app(app)

    if not app.debug and not app.testing and not app.config['SSL_DISABLE']:
        from flask.ext.sslify import SSLify
        sslify = SSLify(app)

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

    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/auth')


    ...

    return app

This is where the email is sent:

@auth.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(email=form.email.data,
                    username=form.username.data,
                    password=form.password.data,
                    name=form.realname.data,
                    role_id=Role.query.filter_by(name='User').first().id)
        db.session.add(user)
        db.session.commit()
        confirm_token = user.generate_token()
        reject_token = user.generate_token(action='reject')
        for admin in User.admins():
            send_email(admin.email, 'Please Confirm Row-Bot Account for User {0} ({1})'.format(user.username, user.name),
                   'auth/email/register', user=user, confirm_token=confirm_token, reject_token=reject_token)
        flash('A request email has been sent to our admins.')
        return redirect(url_for('auth.login'))
    return render_template('auth/register.html', form=form)

Upvotes: 4

Views: 2223

Answers (1)

formatkaka
formatkaka

Reputation: 1358

Couldn't figure out where you went wrong but can you try to match this

from flask import Flask, current_app

from flask_mail import Mail, Message

import threading
#mail = Mail()
app = Flask(__name__)

#DEBUG = True


app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT']= 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL']= False
app.config['MAIL_USERNAME'] = 'EMAIL_ID'
app.config['MAIL_PASSWORD'] = 'PASSWORD'

mail = Mail(app)

@app.route('/')
def send_mail():
    send_email('EMAIL_TO')
    return "Sent"


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

def send_email(to):
    app = current_app._get_current_object()
    msg = Message(subject='hello',
                  sender='SENDER', recipients=[to])
    thr = threading.Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr

#def send_email()

if __name__ == "__main__":
    app.run()

Please comment below if there is still problem.

And DEBUG = True means that the app is running in debug mode , and if there is any error the complete stack trace will be printed. If you don't run in debug mode then it will simply give an error like Internal Server error or something else.

Upvotes: 2

Related Questions