仅获取 SMTPServerDisconnected:调用服务器时请先 运行 connect()
only getting SMTPServerDisconnected: please run connect() first when calling on server
我最近使用 Sendgrid smtp 作为后端启用了向 Django 发送电子邮件的功能
这是我的电子邮件设置:
#AUTO SEND EMAIL
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = 'the_sendgrid_key'
EMAIL_PORT = 587
在我的 api 之一中得到以下代码:
student = request.user
subject = 'test',
text_content = 'test'
email = EmailMultiAlternatives(subject, text_content, os.environ.get('DEFAULT_FROM_EMAIL'), to=[student.email])
email.attach_alternative(html_content, "text/html")
email.send()
在本地开发期间,每当我调用 api 时,电子邮件已发送并且我正常收到
但是当我在服务器上调用 api 时,它一直返回以下错误:
SMTPServerDisconnected: please run connect() first (Most recent call last)
File /root/study/api/views/views.py line 1470 in post args locals
email.send()
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
self.ehlo_or_helo_if_needed()
File /usr/lib/python3.8/smtplib.py line 604 in ehlo_or_helo_if_needed args locals
if not (200 <= self.ehlo()[0] <= 299):
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
SMTPServerDisconnected: please run connect() first
查找此错误后,只有有关错误电子邮件设置的答案,但我检查过电子邮件设置完全正确(因为我在本地收到了电子邮件)
另一个奇怪的事情是当我在服务器上 运行 python manage.py shell
并直接调用 email.send()
方法时没有弹出错误并且我收到了电子邮件。
我一直在寻找一个星期的解决方案,似乎无法找到为什么仅在调用包含该方法的 api 时才弹出错误,希望遇到类似问题的任何人都可以帮助我解决问题出来
更新:
我尝试按照评论中的建议在视图中手动打开和关闭:
from django.core.mail import EmailMultiAlternatives, get_connection, EmailMessage
connection = get_connection()
# Manually open the connection
connection.open()
# Construct an email message that uses the connection
email1 = EmailMessage(
subject,
text_content,
os.environ.get('DEFAULT_FROM_EMAIL'),
to=[student.email],
connection=connection,
)
email1.send() # Send the email
connection.close()
但仍然出现相同的 connect() 错误:
SMTPServerDisconnected: please run connect() first (Most recent call last)
File /root/study/api/views/views.py line 1474 in post args locals
connection.open()
Show 1 non-project frame
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
self.ehlo_or_helo_if_needed()
File /usr/lib/python3.8/smtplib.py line 604 in ehlo_or_helo_if_needed args locals
if not (200 <= self.ehlo()[0] <= 299):
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
SMTPServerDisconnected: please run connect() first
更新 2:
我的服务器启用了 SSL,运行使用 nginx 在 gunicorn 上运行以提供静态文件并重定向端口
gunicorn 配置:
[Unit]
Description=Gunicorn daemon for Django Project
Before=nginx.service
After=network.target
[Service]
WorkingDirectory=/root/study
ExecStart=/root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/bin/gunicorn --log-level=debug --access-logfile /var/log/gunicorn/access.log --error-logfile /var/log/gunicorn/error.log --workers 5 --bind unix:/var/log/gunicorn/hoola.sock base.wsgi:application
Restart=always
SyslogIdentifier=gunicorn
User=root
Group=www-data
[Install]
WantedBy=multi-user.target
nginx 配置:
user root;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
更新 5:
来自 rollbar 错误日志记录的更多详细错误回溯:
SMTPServerDisconnected: please run connect() first (Most recent call last)
File /root/study/api/views/views.py line 1729 in get args locals
email.send()
获取参数
“自我”
""
“请求”
""
获取局部变量
e
""
电子邮件
""
请求
""
自己
""
Hide 3 non-project frames
File /root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/lib/python3.8/site-packages/django/core/mail/message.py line 284 in send args locals
return self.get_connection(fail_silently).send_messages([self])
发送参数
“自我”
"
"fail_silently"
未知
发送局部变量
fail_silently
错误
自己
""
File /root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/lib/python3.8/site-packages/django/core/mail/backends/smtp.py line 102 in send_messages args locals
new_conn_created = self.open()
send_messages 个参数
“自我”
""
"email_messages
["]
send_messages 局部变量
email_messages
[""]
自己
""
File /root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/lib/python3.8/site-packages/django/core/mail/backends/smtp.py line 67 in open args locals
self.connection.starttls(keyfile=self.ssl_keyfile, certfile=self.ssl_certfile)
公开辩论
“自我”
""
打开局部变量
connection_params
{"local_hostname": "mydomain.io"}
自己
""
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
starttls 参数
“自我”
""
“密钥文件”
未知
“证书文件”
未知
“上下文”
未知
starttls 局部变量
证书文件
无
上下文
无
密钥文件
无
自己
""
File /usr/lib/python3.8/smtplib.py line 604 in ehlo_or_helo_if_needed args locals
if not (200 <= self.ehlo()[0] <= 299):
ehlo_or_helo_if_needed 个参数
“自我”
""
ehlo_or_helo_if_needed 个参数
自己
""
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
ehlo 参数
“自我”
""
“姓名”
未知
ehlo 局部变量
姓名
""
自己
""
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
putcmd 参数
“自我”
""
“cmd”
“ehlo”
“args”
"mydomain.io"
putcmd 局部变量
参数
"mydomain.io"
命令
“ehlo”
自己
""
海峡
"ehlo mydomain.io\r\n"
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
发送参数
“自我”
""
"s"
"ehlo mydomain.io\r\n"
发送局部变量
s
"ehlo mydomain.io\r\n"
自己
""
SMTPServerDisconnected: please run connect() first
所以我终于找到了为什么它似乎永远无法连接,这是因为我为 gunicorn 设置的整个项目都缺少 .env 文件变量。这就是为什么 EMAIL_HOST 和 EMAIL 配置在视图中 运行 时永远不会加载的原因。
我将 loadenv 添加到我的 wsgi.py 文件中,以便 gunicorn 可以加载它:
import os
from django.core.wsgi import get_wsgi_application
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env'))
#load env before running wsgi
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "base.settings")
application = get_wsgi_application()
还更改了我的 gunicorn.service 运行 命令的方式;
在 ExecStart 中,我从 base.wsgi:application
更改为 base.wsgi
,因此它还会加载整个 dotenv 变量,而不仅仅是应用程序
我最近使用 Sendgrid smtp 作为后端启用了向 Django 发送电子邮件的功能
这是我的电子邮件设置:
#AUTO SEND EMAIL
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = 'the_sendgrid_key'
EMAIL_PORT = 587
在我的 api 之一中得到以下代码:
student = request.user
subject = 'test',
text_content = 'test'
email = EmailMultiAlternatives(subject, text_content, os.environ.get('DEFAULT_FROM_EMAIL'), to=[student.email])
email.attach_alternative(html_content, "text/html")
email.send()
在本地开发期间,每当我调用 api 时,电子邮件已发送并且我正常收到
但是当我在服务器上调用 api 时,它一直返回以下错误:
SMTPServerDisconnected: please run connect() first (Most recent call last)
File /root/study/api/views/views.py line 1470 in post args locals
email.send()
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
self.ehlo_or_helo_if_needed()
File /usr/lib/python3.8/smtplib.py line 604 in ehlo_or_helo_if_needed args locals
if not (200 <= self.ehlo()[0] <= 299):
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
SMTPServerDisconnected: please run connect() first
查找此错误后,只有有关错误电子邮件设置的答案,但我检查过电子邮件设置完全正确(因为我在本地收到了电子邮件)
另一个奇怪的事情是当我在服务器上 运行 python manage.py shell
并直接调用 email.send()
方法时没有弹出错误并且我收到了电子邮件。
我一直在寻找一个星期的解决方案,似乎无法找到为什么仅在调用包含该方法的 api 时才弹出错误,希望遇到类似问题的任何人都可以帮助我解决问题出来
更新: 我尝试按照评论中的建议在视图中手动打开和关闭:
from django.core.mail import EmailMultiAlternatives, get_connection, EmailMessage
connection = get_connection()
# Manually open the connection
connection.open()
# Construct an email message that uses the connection
email1 = EmailMessage(
subject,
text_content,
os.environ.get('DEFAULT_FROM_EMAIL'),
to=[student.email],
connection=connection,
)
email1.send() # Send the email
connection.close()
但仍然出现相同的 connect() 错误:
SMTPServerDisconnected: please run connect() first (Most recent call last)
File /root/study/api/views/views.py line 1474 in post args locals
connection.open()
Show 1 non-project frame
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
self.ehlo_or_helo_if_needed()
File /usr/lib/python3.8/smtplib.py line 604 in ehlo_or_helo_if_needed args locals
if not (200 <= self.ehlo()[0] <= 299):
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
SMTPServerDisconnected: please run connect() first
更新 2:
我的服务器启用了 SSL,运行使用 nginx 在 gunicorn 上运行以提供静态文件并重定向端口
gunicorn 配置:
[Unit]
Description=Gunicorn daemon for Django Project
Before=nginx.service
After=network.target
[Service]
WorkingDirectory=/root/study
ExecStart=/root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/bin/gunicorn --log-level=debug --access-logfile /var/log/gunicorn/access.log --error-logfile /var/log/gunicorn/error.log --workers 5 --bind unix:/var/log/gunicorn/hoola.sock base.wsgi:application
Restart=always
SyslogIdentifier=gunicorn
User=root
Group=www-data
[Install]
WantedBy=multi-user.target
nginx 配置:
user root;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
更新 5: 来自 rollbar 错误日志记录的更多详细错误回溯:
SMTPServerDisconnected: please run connect() first (Most recent call last)
File /root/study/api/views/views.py line 1729 in get args locals
email.send()
获取参数 | |
---|---|
“自我” | " |
“请求” | " |
获取局部变量 | |
---|---|
e | " |
电子邮件 | " |
请求 | " |
自己 | " |
Hide 3 non-project frames
File /root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/lib/python3.8/site-packages/django/core/mail/message.py line 284 in send args locals
return self.get_connection(fail_silently).send_messages([self])
发送参数 | |
---|---|
“自我” | |
"fail_silently" | 未知 |
发送局部变量 | |
---|---|
fail_silently | 错误 |
自己 | " |
File /root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/lib/python3.8/site-packages/django/core/mail/backends/smtp.py line 102 in send_messages args locals
new_conn_created = self.open()
send_messages 个参数 | |
---|---|
“自我” | " |
"email_messages | [ |
send_messages 局部变量 | |
---|---|
email_messages | [" |
自己 | " |
File /root/.cache/pypoetry/virtualenvs/base.django-H96T9Ltg-py3.8/lib/python3.8/site-packages/django/core/mail/backends/smtp.py line 67 in open args locals
self.connection.starttls(keyfile=self.ssl_keyfile, certfile=self.ssl_certfile)
公开辩论 | |
---|---|
“自我” | " |
打开局部变量 | |
---|---|
connection_params | {"local_hostname": "mydomain.io"} |
自己 | " |
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
starttls 参数 | |
---|---|
“自我” | " |
“密钥文件” | 未知 |
“证书文件” | 未知 |
“上下文” | 未知 |
starttls 局部变量 | |
---|---|
证书文件 | 无 |
上下文 | 无 |
密钥文件 | 无 |
自己 | " |
File /usr/lib/python3.8/smtplib.py line 604 in ehlo_or_helo_if_needed args locals
if not (200 <= self.ehlo()[0] <= 299):
ehlo_or_helo_if_needed 个参数 | |
---|---|
“自我” | " |
ehlo_or_helo_if_needed 个参数 | |
---|---|
自己 | " |
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
ehlo 参数 | |
---|---|
“自我” | " |
“姓名” | 未知 |
ehlo 局部变量 | |
---|---|
姓名 | "" |
自己 | " |
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
putcmd 参数 | |
---|---|
“自我” | " |
“cmd” | “ehlo” |
“args” | "mydomain.io" |
putcmd 局部变量 | |
---|---|
参数 | "mydomain.io" |
命令 | “ehlo” |
自己 | " |
海峡 | "ehlo mydomain.io\r\n" |
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
发送参数 | |
---|---|
“自我” | " |
"s" | "ehlo mydomain.io\r\n" |
发送局部变量 | |
---|---|
s | "ehlo mydomain.io\r\n" |
自己 | " |
SMTPServerDisconnected: please run connect() first
所以我终于找到了为什么它似乎永远无法连接,这是因为我为 gunicorn 设置的整个项目都缺少 .env 文件变量。这就是为什么 EMAIL_HOST 和 EMAIL 配置在视图中 运行 时永远不会加载的原因。
我将 loadenv 添加到我的 wsgi.py 文件中,以便 gunicorn 可以加载它:
import os
from django.core.wsgi import get_wsgi_application
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env'))
#load env before running wsgi
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "base.settings")
application = get_wsgi_application()
还更改了我的 gunicorn.service 运行 命令的方式;
在 ExecStart 中,我从 base.wsgi:application
更改为 base.wsgi
,因此它还会加载整个 dotenv 变量,而不仅仅是应用程序