Home > front end >  SMTPServerDisconnected When Sending via Flask-Mail on Gunicorn
SMTPServerDisconnected When Sending via Flask-Mail on Gunicorn

Time:08-11

I have a Flask app deployed with Gunicorn & Nginx and I am trying to debug a strange issue I am having with sending emails from the application (via Flask-Mail library). Sending emails works from my local development environment and also works on my server (on Digital Ocean) if I start my application via the flask run command. This is important as most of the answers I have found mention that their hosting provider blocks outgoing mail over the default SMTP port.

Once I try to send any email from the application hosted in Gunicorn I get the following error in my logs -

File "/usr/lib/python3.10/smtplib.py", line 365, in send
    raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first

My application is launched in Gunicorn via the below command -

gunicorn --workers 3 \
    --timeout 120 \
    --bind 0.0.0.0:9000 \
    --log-file=dt.log \
    --bind unix:dt.sock -m 007 \
    --log-level=info wsgi:app

I have created a very simple route to send an email and I see the same behavior as my existing code. This is the route I created.

@bp.route("/debugmail")
def debugmail():
    msg = Message(
        "An Email Subject!",
        sender=("Email Sender Name", "[email protected]"),
        recipients=["[email protected]"],
    )
    msg.body = "This is an email from the App (tons of uses for this)."
    
    # Also Tried Adding the Connect Command Here
    # mail.connect()
    mail.send(msg)
    return {"message": "Email sent!"}, 200

The configuration file I use for this app is below -

MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USE_SSL=False
[email protected]
MAIL_PASSWORD=app-specific-password

Any help or thoughts or tests for me to run would be greatly appreciated!

CodePudding user response:

It turns out that by using a .env file that Flask was able to read automatically, was not passed into the context of the Gunicorn runner.

As per the answer linked belo, I have created this file which guarantees that both my .flaskenv and .env load no matter the context.

Running flask app with gunicorn and environment variables

# gunicorn.conf.py
import os
from dotenv import load_dotenv

for env_file in ('.env', '.flaskenv'):
    env = os.path.join(os.getcwd(), env_file)
    if os.path.exists(env):
        load_dotenv(env)
  • Related