从不同的smtp服务器发送django服务器错误

时间:2015-10-08 08:13:32

标签: python django email smtp

我的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元组不为空时自动启用。

怎么可能实现?

提前致谢

3 个答案:

答案 0 :(得分:2)

您可以在设置上设置不同的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的一些学分:https://stackoverflow.com/a/14398138

答案 1 :(得分:1)

调整@ 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 https://stackoverflow.com/a/33010978/870121
    """
    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地址看起来很糟(如果有),并且/或者也损害我们发送域(myapp.com)的声誉?或者,您可能会发现它用完了每月发送的电子邮件数量上限。 因此,为重要的面向用户的电子邮件保留“ myapp.com”,并使用此awesomeAdminEmailHandler从其他电子邮件帐户发送5xx错误电子邮件。

在Gmail中的注释,如本例所示
Gmail是测试的好主意,但不是在生产中使用的好主意。 如果您首先允许“不安全的应用程序”,https://myaccount.google.com/lesssecureapps

,则SMTP可以像上面的代码段一样工作。

答案 2 :(得分:0)

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)