来自不同 smtp 服务器的电子邮件 django 服务器错误

Email django server errors from different smtp server

我的 settings.py 文件中有用于用户通知目的的 SMTP Sendgrid 设置:

EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'my_username'
EMAIL_HOST_PASSWORD = 'my_password'
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'my_from_email'

效果很好,但问题是我想为内置的内部服务器错误通知系统使用不同的 SMTP 服务器,当 DEBUG = False 且 ADMINS 元组不为空时,它会自动启用。

如何实现?

提前致谢

您可以在设置中设置不同的error handler

'handlers': {
    'null': {
        'level': 'DEBUG',
        'class': 'logging.NullHandler',
    },
    'console': {
        'level': 'DEBUG',
        'class': 'logging.StreamHandler',
        'formatter': 'simple'
    },
    'mail_admins': {
        'level': 'ERROR',
        'class': 'myAdminEmailHandler',
        'filters': ['special']
    }

并覆盖那里的连接:

from django.utils.log import AdminEmailHandler
from django.core.mail import get_connection


class myAdminEmailHandler( AdminEmailHandler ):

    def __init__(self, include_html=False, email_backend=None):
        AdminEmailHandler.__init__(self,include_html, email_backend)

        self.my_host = ''
        self.my_port = 587
        self.my_username = ''
        self.my_password = ''
        self.my_use_tls = True
        self.connection = get_connection(host=my_host, 
                                    port=my_port, 
                                    username=my_username, 
                                    password=my_password, 
                                    use_tls=my_use_tls)

免责声明,未经测试。 @Daniel Backman 的一些功劳:

Django 1.8 的代码并非 100% 准确

from django.utils.log import AdminEmailHandler
from django.core.mail import get_connection
from django.conf import settings
from django.core.mail.backends.smtp import EmailBackend
from django.core.mail.message import EmailMultiAlternatives

class SMTPConnection (EmailBackend):
    def __call__(self, *args, **kwargs):
       self.host = settings.ADMINS_SMTP["HOST"]
       self.port = settings.ADMINS_SMTP["PORT"]
       self.username = settings.ADMINS_SMTP["USERNAME"]
       self.password = settings.ADMINS_SMTP["PASSWORD"]
       self.use_tls = settings.ADMINS_SMTP["USE_TLS"]
       return self

class EmailAdmins( AdminEmailHandler ):
    def __init__(self, include_html=False, email_backend=None):
       self.include_html=include_html
       AdminEmailHandler.__init__(self, include_html, email_backend)
       self.connection =     SMTPConnection(host=settings.ADMINS_SMTP["HOST"],port=settings.ADMINS_SMTP["PORT"],username=settings.ADMINS_SMTP["USERNAME"],password=settings.ADMINS_SMTP["PASSWORD"],use_tls=settings.ADMINS_SMTP["USE_TLS"])

def send_mail(self, subject, message, *args, **kwargs):
    if not settings.ADMINS:
        return
    mail = EmailMultiAlternatives(subject='%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject),
                                  body=message, from_email=settings.ADMINS_SMTP["USERNAME"], to=[a[1] for a in settings.ADMINS],
                                  connection=self.connection,)
    mail.send(fail_silently=True)

调整@dani-herrera 的回答,这在 Django 1.11 中对我有用:修改 connection 属性 而不是 __init__

综上所述,完整代码如下

settings.py中:

# For transactional emails:
SENDGRID_API_KEY = "SG.1234ABCD"
EMAIL_HOST = "smtp.sendgrid.net"
EMAIL_HOST_USER='apikey'
EMAIL_HOST_PASSWORD=SENDGRID_API_KEY
# ... ^that's used for all emails EXCEPT server error alerts.

# Change one line in LOGGING, to use custom awesomeAdminEmailHandler for server emails:
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': { 'class': 'logging.StreamHandler' },
        'mail_admins': {
                        'level': 'ERROR',
                        # remove this default: 'class': 'django.utils.log.AdminEmailHandler',
                        # replace with custom smtp login for ERROR emails:
                        'class': 'myapp.email.adminsender.awesomeAdminEmailHandler', # yes, in quotes
                        # 'include_html': False, # The include_html argument of AdminEmailHandler is used to control whether the traceback email includes an HTML attachment containing the full content of the debug Web page that would have been produced if DEBUG were True.  This information is potentially very sensitive, and you may not want to send it over email.
                     }
    },
    'loggers': {
        # [Don't change anything]
        ...
        ...
    }
}

然后在 myapp/email/adminsender.py 文件中:

from django.utils.log import AdminEmailHandler
from django.core.mail import get_connection

class awesomeAdminEmailHandler( AdminEmailHandler ):
    """
        In this example, we create a special Gmail account just for sending error emails.
        Code inspired by 
    """
    def connection(self):
        my_host = "smtp.gmail.com"
        my_port = 587
        my_username = "myapperrorsender@gmail.com"
        my_password = "abcd1234"
        my_use_tls = True
        return get_connection(backend=self.email_backend,
                              host=my_host,
                              port=my_port,
                              username=my_username,
                              password=my_password,
                              use_tls=my_use_tls)

费心这样做的动机:
如果我们通过 Sendgrid 发送所有电子邮件,即交易应用程序(用户)电子邮件和服务器错误电子邮件,那是不理想的。
一个服务器错误可能会导致在 2 分钟内发送约 100 封电子邮件。
大多数这些电子邮件都不会打开。
这种低打开率可能会使您的专用 IP 地址看起来很糟糕(如果您有的话),and/or 也会损害我们发送域 (myapp.com) 的声誉吗?或者,您可能会发现它用完了您每月发送的电子邮件数量上限。 因此,为重要的面向用户的电子邮件保留 'myapp.com',并使用此 awesomeAdminEmailHandler 从不同的电子邮件帐户发送 5xx 错误电子邮件。

如本例所示,关于 Gmail 的注意事项
Gmail 是测试的好主意,但可能 不是 用于生产的好主意。 如果您首先允许 "insecure apps"、https://myaccount.google.com/lesssecureapps

,则 SMTP 将像上面的代码片段一样工作