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)