使用 Gmail 报告 Django 错误

Django error reporting with Gmail

我正在尝试设置我的 Django 帐户以接收错误报告 (docs here)。

我已将 ADMINS 添加到我的 settings.py。然后,根据文档:

In order to send email, Django requires a few settings telling it how to connect to your mail server. At the very least, you’ll need to specify EMAIL_HOST and possibly EMAIL_HOST_USER and EMAIL_HOST_PASSWORD, though other settings may be also required depending on your mail server’s configuration. Consult the Django settings documentation for a full list of email-related settings.

但这是我迷路的时候。 我有一个 Business Gmail 帐户,这是我想要在此处 link 的帐户。 This post 解释得很精彩,

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'myemail@mydomain.com'
EMAIL_HOST_PASSWORD = 'mypassword'

但上面写着:

In 2016 Gmail is not allowing this anymore.

显然,问题出在 EMAIL_HOST_PASSWORD 设置中,它必须是一个特定的密码,如 this other post 中所述。

但是,很难相信 Gmail 不允许这样做,尤其是对于您要为服务付费的企业帐户。

不幸的是,我找到的所有相关信息都早于 2016 年,因此不再有用。

有没有办法将 Django 应用程序与 Gmail 连接起来?

最终对我有用的解决方法是为此创建一个新的 Gmail 帐户。这目前有效,尽管我在其他地方读到的一些评论说的是相反的。

请注意,这个新帐户将没有两步验证,但安全性并不是一个大问题,因为该帐户将 "only" 处理 Django 电子邮件。

您可以使用 Gmail API 通过 Gmail 电子邮件地址发送授权电子邮件。一个好的起点是文档:https://developers.google.com/gmail/api/quickstart/python

我一直 运行 遇到这个问题,所以我记录了如何使用 API 博客 post:https://www.willcarh.art/blog/Automating-Emails-in-Python/

我最终构建了自己的 Python 实用程序来通过 Gmail API 发送电子邮件,这实在是太痛苦了。这是我最初的原型:

import os
import sys
import pickle
import base64
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from email.mime.text import MIMEText

def get_gmail_api_instance():
    """
    Setup Gmail API instance
    """
    if not os.path.exists('token.pickle'):
        return None
    with open('token.pickle', 'rb') as token:
        creds = pickle.load(token)
    service = build('gmail', 'v1', credentials=creds)
    return service

def create_message(sender, to, subject, message_text):
    """
    Create a message for an email
        :sender: (str) the email address of the sender
        :to: (str) the email address of the receiver
        :subject: (str) the subject of the email
        :message_text: (str) the content of the email
    """
    message = MIMEText(message_text)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject
    raw = base64.urlsafe_b64encode(message.as_bytes())
    raw = raw.decode()
    body = {'raw': raw}
    return body

def send_email(service, user_id, message):
    """
    Send an email via Gmail API
        :service: (googleapiclient.discovery.Resource) authorized Gmail API service instance
        :user_id: (str) sender's email address, used for special "me" value (authenticated Gmail account)
        :message: (base64) message to be sent
    """
    try:
        message = (service.users().messages().send(userId=user_id, body=message).execute())
        return message
    except Exception as e:
        print("err: problem sending email")
        print(e)

def main():
    """
    Set up Gmail API instance, use it to send an email
      'sender' is the Gmail address that is authenticated by the Gmail API
      'receiver' is the receiver's email address
      'subject' is the subject of our email
      'message_text' is the content of the email
    """
    # draft our message
    sender = 'pythonista@gmail.com'
    receiver = 'receiver@gmail.com'
    subject = 'Just checking in!'
    message_text = "Hi! How's it going?"

    # authenticate with Gmail API
    service = get_gmail_api_instance()
    if service == None:
        print("err: no credentials .pickle file found")
        sys.exit(1)

    # create message structure
    message = create_message(sender, receiver, subject, message_text)

    # send email
    result = send_email(service, sender, message)
    if not result == None:
        print(f"Message sent successfully! Message id: {result['id']}")

if __name__ == '__main__':
    main()

然后,要让 Django 在出现 404、500 等错误时发送电子邮件,请添加到相关 urls.py:

from django.conf.urls import handler404, handler500
handler404 = projectname_views.error_404
handler500 = projectname_views.error_500

并在相关 views.py 中添加:

import send_gmail
from django.shortcuts import render

def error_500(request):
    # call email function
    send_gmail.main()
    response = render(request, '500_errror_template.html')
    response.status_code = 500
    return response

GitHub 上面代码的要点:https://gist.github.com/wcarhart/b4f509c46ad1515a9954d356aaf10df1

我想提供截至 2021 年 8 月的更新。

我只使用 Django 附带的库在企业 gmail 帐户上工作。

在settings.py

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'myname@mydomain.com'
EMAIL_HOST_PASSWORD = 'myappspecificpassword'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

对于密码,您需要为相关帐户生成一个应用专用密码。您可以通过访问此 link 来做到这一点:https://security.google.com/settings/u/3/security/apppasswords.

注意:您必须为您发送的帐户启用双因素身份验证。这必须通过您发送的帐户启用 -- 而不是管理员帐户。

这样做,我可以在 views.py

的视图中使用此片段发送电子邮件
        from django.core.mail import EmailMessage
        ...


        email = EmailMessage(
        'Hello',
        'Body goes here',
        'bob@example.com',
        ['user@mydomain.com'],
        ['bcc@example.com'],
        reply_to=['myuser@mydomain.com'],
        headers={'Message-ID': 'foo'},
        )
        
        email.send()