仅断开SMTPServerDisconnected:在服务器上调用时,请先运行connect()

2024-04-26 21:42:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近启用了以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,在gunicorn上运行,使用nginx为静态文件提供服务并重定向端口

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()
^{tb1}$
^{tb2}$
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])
^{tb3}$
^{tb4}$
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 arguments
"self""<class 'django.core.mail.backends.smtp.EmailBackend'>"
"email_messages[<class'django.core.mail.message.EmailMultiAlternatives'>"]
send_messages local variables
email_messages["<class 'django.core.mail.message.EmailMultiAlternatives'>"]
self"<class 'django.core.mail.backends.smtp.EmailBackend'>"
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)
open arguments
"self""<class 'django.core.mail.backends.smtp.EmailBackend'>"
open local variables
connection_params{"local_hostname": "mydomain.io"}
self"<class 'django.core.mail.backends.smtp.EmailBackend'>"
File /usr/lib/python3.8/smtplib.py line 753 in starttls args locals
starttls arguments
"self""<class 'smtplib.SMTP'>"
"keyfile"unknown
"certfile"unknown
"context"inknown
starttls local variables
certfilenull
contextnull
keyfilenull
self"<class 'smtplib.SMTP'>"
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 arguments
"self""<class 'smtplib.SMTP'>"
ehlo_or_helo_if_needed arguments
self"<class 'smtplib.SMTP'>"
File /usr/lib/python3.8/smtplib.py line 444 in ehlo args locals
self.putcmd(self.ehlo_msg, name or self.local_hostname)
ehlo arguments
"self""<class 'smtplib.SMTP'>"
"name"unknown
ehlo local variables
name""
self"<class 'smtplib.SMTP'>"
File /usr/lib/python3.8/smtplib.py line 371 in putcmd args locals
self.send(str)
putcmd arguments
"self""<class 'smtplib.SMTP'>"
"cmd""ehlo"
"args""mydomain.io"
putcmd local variables
args"mydomain.io"
cmd"ehlo"
self"<class 'smtplib.SMTP'>"
str"ehlo mydomain.io\r\n"
File /usr/lib/python3.8/smtplib.py line 363 in send args locals
raise SMTPServerDisconnected('please run connect() first')
send arguments
"self""<class 'smtplib.SMTP'>"
"s""ehlo mydomain.io\r\n"
send local variables
s"ehlo mydomain.io\r\n"
self"<class 'smtplib.SMTP'>"
SMTPServerDisconnected: please run connect() first

Tags: djangoinpyselfsendlibusrline
1条回答
网友
1楼 · 发布于 2024-04-26 21:42:43

所以我最终发现了为什么它似乎从未连接,这是因为我的整个gunicorn项目设置缺少.env文件变量。这就是为什么在视图中运行时从不加载电子邮件\u主机和电子邮件配置的原因

我将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变量,而不仅仅是应用程序

相关问题 更多 >