发送电子邮件

虽然Python通过smtplib模块使发送邮件变得相对容易,但Django提供了一些简单的包装器。 这些包装提供了更快的发送电子邮件,使开发过程中测试邮件发送变得容易,并为不能使用SMTP的平台提供支持。

该代码位于django.core.mail模块中。

快速示例

在两行中:

from django.core.mail import send_mail

send_mail(
    'Subject here',
    'Here is the message.',
    'from@example.com',
    ['to@example.com'],
    fail_silently=False,
)

邮件使用EMAIL_HOSTEMAIL_PORT设置中指定的SMTP主机和端口发送。 EMAIL_HOST_USEREMAIL_HOST_PASSWORD设置(如果设置)用于向SMTP服务器进行身份验证,并且EMAIL_USE_TLSEMAIL_USE_SSL

注意

django.core.mail发送的电子邮件的字符集将被设置为您的DEFAULT_CHARSET设置的值。

send_mail()

send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)[source]

发送电子邮件最简单的方法是使用django.core.mail.send_mail()

subjectmessagefrom_emailrecipient_list参数是必需的。

  • subject: A string.
  • message: A string.
  • from_email:一个字符串。
  • recipient_list: A list of strings, each an email address. recipient_list的每个成员都将在电子邮件的“收件人:”字段中看到其他收件人。
  • fail_silently:一个布尔值。 如果是Falsesend_mail会引发smtplib.SMTPException 请参阅smtplib文档以获取可能异常的列表,这些异常都是SMTPException的子类。
  • auth_user:用来验证SMTP服务器的可选用户名。 如果没有提供,Django将使用EMAIL_HOST_USER设置的值。
  • auth_password:用于验证SMTP服务器的可选密码。 如果没有提供,Django将使用EMAIL_HOST_PASSWORD设置的值。
  • connection:用于发送邮件的可选电子邮件后端。 如果未指定,则将使用默认后端的实例。 有关更多详细信息,请参阅Email backends上的文档。
  • html_message: If html_message is provided, the resulting email will be a multipart/alternative email with message as the text/plain content type and html_message as the text/html content type.

返回值将是成功传递消息的数量(可以是01,因为它只能发送一条消息)。

send_mass_mail()

send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)[source]

django.core.mail.send_mass_mail() is intended to handle mass emailing.

datatuple is a tuple in which each element is in this format:

(subject, message, from_email, recipient_list)

fail_silentlyauth_userauth_password具有与send_mail()中相同的功能。

datatuple的每个单独元素都会产生一个单独的电子邮件消息。 send_mail()一样,同一个recipient_list中的收件人都会在电子邮件的“收件人:”字段中看到其他地址。

例如,下面的代码会将两个不同的消息发送给两组不同的收件人;但是,只有一个到邮件服务器的连接将被打开:

message1 = ('Subject here', 'Here is the message', 'from@example.com', ['first@example.com', 'other@example.com'])
message2 = ('Another Subject', 'Here is another message', 'from@example.com', ['second@test.com'])
send_mass_mail((message1, message2), fail_silently=False)

返回值将是成功传递消息的数量。

send_mass_mail() vs. send_mail()

The main difference between send_mass_mail() and send_mail() is that send_mail() opens a connection to the mail server each time it’s executed, while send_mass_mail() uses a single connection for all of its messages. This makes send_mass_mail() slightly more efficient.

mail_admins()

mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)[source]

django.core.mail.mail_admins() is a shortcut for sending an email to the site admins, as defined in the ADMINS setting.

mail_admins()为主题添加EMAIL_SUBJECT_PREFIX设置的值,即“[Django] t7>

电子邮件的“发件人:”标题将成为SERVER_EMAIL设置的值。

这种方法为了方便和可读性而存在。

如果提供了html_message,那么产生的电子邮件将是messagemultipart / alternative电子邮件作为text / plain内容类型和html_message作为文本/ html内容类型。

mail_managers()

mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)[source]

django.core.mail.mail_managers() is just like mail_admins(), except it sends an email to the site managers, as defined in the MANAGERS setting.

实例¶ T0>

这发送一个电子邮件 约翰 @ T0>示例.COM @ T0>示例.COM,他们都出现在“To”中:

send_mail(
    'Subject',
    'Message.',
    'from@example.com',
    ['john@example.com', 'jane@example.com'],
)

这发送一条消息 约翰 @ T0>示例.COM @ T0>示例.COM,他们都收到一封单独的电子邮件:

datatuple = (
    ('Subject', 'Message.', 'from@example.com', ['john@example.com']),
    ('Subject', 'Message.', 'from@example.com', ['jane@example.com']),
)
send_mass_mail(datatuple)

防止标题注入

Header injection is a security exploit in which an attacker inserts extra email headers to control the “To:” and “From:” in email messages that your scripts generate.

上面概述的Django电子邮件功能通过禁止标题值中的换行来防止标题注入。 If any subject, from_email or recipient_list contains a newline (in either Unix, Windows or Mac style), the email function (e.g. send_mail()) will raise django.core.mail.BadHeaderError (a subclass of ValueError) and, hence, will not send the email. 在将所有数据传递给电子邮件功能之前,您有责任对其进行验证。

如果message在字符串的开头包含标题,标题将简单地打印为电子邮件的第一位。

这是一个示例视图,它从请求的POST数据中获取subjectmessagefrom_email,并将其发送到 管理员 @ T0>示例.COM 并在完成后重定向到“/ contact / thanks /”:

from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse, HttpResponseRedirect

def send_email(request):
    subject = request.POST.get('subject', '')
    message = request.POST.get('message', '')
    from_email = request.POST.get('from_email', '')
    if subject and message and from_email:
        try:
            send_mail(subject, message, from_email, ['admin@example.com'])
        except BadHeaderError:
            return HttpResponse('Invalid header found.')
        return HttpResponseRedirect('/contact/thanks/')
    else:
        # In reality we'd use a form class
        # to get proper validation errors.
        return HttpResponse('Make sure all fields are entered and valid.')

EmailMessage

Django的send_mail()send_mass_mail()函数实际上是使用EmailMessage类的精简包装器。

并不是EmailMessage类的所有功能都可以通过send_mail()和相关的包装函数获得。 如果您希望使用高级功能(如BCC收件人,文件附件或多部分电子邮件),则需要直接创建EmailMessage实例。

注意

这是一个设计功能。 send_mail() and related functions were originally the only interface Django provided. 然而,他们接受的参数列表随着时间的推移正在慢慢增长。 移动到更加面向对象的电子邮件设计是有意义的,并保留原来的功能只是为了向后兼容。

EmailMessage is responsible for creating the email message itself. 然后email backend负责发送电子邮件。

For convenience, EmailMessage provides a simple send() method for sending a single email. 如果您需要发送多条消息,则电子邮件后端API provides an alternative

EmailMessage Objects

EmailMessage[source]

使用以下参数初始化EmailMessage类(如果使用位置参数,则按给定顺序)。 所有参数都是可选的,可以在调用send()方法之前随时设置。

  • subject: The subject line of the email.
  • body:正文文本。 这应该是一个纯文本消息。
  • from_email:发件人的地址。 Both fred@example.com and Fred <fred@example.com> forms are legal. 如果省略,则使用DEFAULT_FROM_EMAIL设置。
  • to:收件人地址的列表或元组。
  • bcc:发送电子邮件时,“Bcc”标题中使用的地址列表或元组。
  • connection:电子邮件后端实例。 如果要为多个邮件使用相同的连接,请使用此参数。 如果省略,则在调用send()时创建新的连接。
  • attachments:放置邮件的附件列表。 这些可以是email.MIMEBase.MIMEBase实例或(文件名, 内容, mimetype) 三元组
  • headers:放置在消息上的额外标题的字典。 键是标题名称,值是标题值。 调用者需要确保标题名称和值的格式对于电子邮件来说是正确的。 相应的属性是extra_headers
  • cc:发送电子邮件时在“Cc”标题中使用的收件人地址的列表或元组。
  • reply_to:发送电子邮件时在“回复”标题中使用的收件人地址的列表或元组。

例如:

from django.core.mail import EmailMessage

email = EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to1@example.com', 'to2@example.com'],
    ['bcc@example.com'],
    reply_to=['another@example.com'],
    headers={'Message-ID': 'foo'},
)

该类有以下方法:

  • send(fail_silently=False) sends the message. 如果在构建电子邮件时指定了连接,则将使用该连接。 否则,默认后端的一个实例将被实例化和使用。 如果关键字参数fail_silentlyTrue,则发送消息时引发的异常将被撤销。 一个空的收件人列表不会引发异常。

  • message()构造一个django.core.mail.SafeMIMEText对象(Python的email.MIMEText.MIMEText类的一个子类)或django.core.mail.SafeMIMEMultipart对象。 如果您需要扩展EmailMessage类,则可能需要重写此方法以将所需的内容放入MIME对象。

  • recipients() returns a list of all the recipients of the message, whether they’re recorded in the to, cc or bcc attributes. 这是您在子类化时可能需要重写的另一种方法,因为在发送邮件时,需要将SMTP服务器告知收件人的完整列表。 如果添加另一种方法来指定类中的收件人,则也需要从此方法返回。

  • attach() creates a new file attachment and adds it to the message. 有两种方法可以调用attach()

    • 您可以将它传递给一个email.MIMEBase.MIMEBase实例。 这将直接插入到结果消息中。

    • 或者,您可以传递attach()三个参数:filenamecontentmimetype filename是电子邮件中出现的文件附件的名称,content是附件中包含的数据,mimetype是附件的可选MIME类型。 如果省略mimetype,则会从附件的文件名中猜出MIME内容类型。

      例如:

      message.attach('design.png', img_data, 'image/png')
      

      如果您指定message/rfc822mimetype,它也将接受django.core.mail.EmailMessageemail.message.Message

      对于以text/开头的mimetype,内容应该是一个字符串。 二进制数据将使用UTF-8进行解码,如果失败,则MIME类型将被更改为application/octet-stream,数据将保持不变。

      另外,message/rfc822附件将不再是违反 RFC 2046#section-5.2.1的base64编码,在EvolutionThunderbird中显示附件的问题。

  • attach_file() creates a new attachment using a file from your filesystem. 使用要附加的文件的路径进行调用,并可选择使用附件使用的MIME类型。 如果省略MIME类型,则会从文件名中猜出。 最简单的用法是:

    message.attach_file('/images/weather_map.png')
    

    对于以text/开头的MIME类型,二进制数据的处理方式与attach()中的相同。

在Django 1.11中更改:

当无法解码text/*附件的二进制数据时,将回退添加到MIME类型application/octet-stream

发送替代内容类型

在电子邮件中包含多个版本的内容可能很有用,经典的例子是发送消息的文本和HTML版本。 使用Django的电子邮件库,您可以使用EmailMultiAlternatives类执行此操作。 这个EmailMessage的子类有一个attach_alternative()方法用于在邮件中包含额外版本的邮件正文。 所有其他方法(包括类初始化)都是直接从EmailMessage继承的。

要发送文本和HTML组合,您可以编写:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.'
html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()

默认情况下,EmailMessage中的body参数的MIME类型是"text/plain" 这是一个很好的做法,因为它保证任何收件人都能够阅读电子邮件,而不管他们的邮件客户端。 但是,如果您确信收件人可以处理替代内容类型,则可以使用EmailMessage类中的content_subtype属性更改主要内容类型。 主要类型将始终是"text",但您可以更改子类型。 例如:

msg = EmailMessage(subject, html_content, from_email, [to])
msg.content_subtype = "html"  # Main content is now text/html
msg.send()

电子邮件后台

电子邮件的实际发送由电子邮件后端处理。

电子邮件后端类具有以下方法:

  • open() instantiates a long-lived email-sending connection.
  • close()关闭当前的电子邮件发送连接。
  • send_messages(email_messages) sends a list of EmailMessage objects. 如果连接未打开,则此调用将隐式打开连接,然后关闭连接。 如果连接已经打开,邮件发送完毕后将保持打开状态。

It can also be used as a context manager, which will automatically call open() and close() as needed:

from django.core import mail

with mail.get_connection() as connection:
    mail.EmailMessage(
        subject1, body1, from1, [to1],
        connection=connection,
    ).send()
    mail.EmailMessage(
        subject2, body2, from2, [to2],
        connection=connection,
    ).send()

获取电子邮件后端的实例

django.core.mail中的get_connection()函数返回您可以使用的电子邮件后端的实例。

get_connection(backend=None, fail_silently=False, *args, **kwargs)[source]

默认情况下,对get_connection()的调用将返回EMAIL_BACKEND中指定的电子邮件后端实例。 如果指定了backend参数,那么后端的一个实例将被实例化。

fail_silently参数控制后端如何处理错误。 如果fail_silently为True,则电子邮件发送过程中的异常将被忽略。

所有其他参数直接传递给电子邮件后端的构造函数。

Django附带有几个电子邮件发送后端。 除了SMTP后端(这是默认的)之外,这些后端只在测试和开发过程中有用。 如果您有特殊的电子邮件发送要求,您可以write your own email backend

SMTP后端

backends.smtp。EmailBackend(host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs)

这是默认的后端。 电子邮件将通过SMTP服务器发送。

如果参数是None,则从匹配设置中检索每个参数的值:

SMTP后端是由Django继承的默认配置。 如果您想明确指定,请在您的设置中输入以下内容:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

如果未指定,默认timeout将由socket.getdefaulttimeout()提供,默认为None(无超时)。

控制台后端

控制台后端不是发送真正的电子邮件,而是写入将被发送到标准输出的电子邮件。 默认情况下,控制台后端将写入stdout 通过在构建连接时提供stream关键字参数,您可以使用不同的类流对象。

要指定此后端,请在您的设置中添加以下内容:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

这个后端不适合在生产环境中使用 - 它是作为开发过程中可以使用的便利而提供的。

文件后端

文件后端将电子邮件写入文件。 为在此后端打开的每个新会话创建一个新文件。 当与get_connection()创建连接时,写入文件的目录取自EMAIL_FILE_PATH设置或file_path关键字。

要指定此后端,请在您的设置中添加以下内容:

EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location

这个后端不适合在生产环境中使用 - 它是作为开发过程中可以使用的便利而提供的。

内存后端

'locmem'后端将消息存储在django.core.mail模块的特殊属性中。 当发送第一封邮件时,会创建outbox属性。 这是一个带有EmailMessage实例的列表,用于发送每条消息。

要指定此后端,请在您的设置中添加以下内容:

EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

这个后端不适合在生产环境中使用 - 它是作为开发和测试过程中可以使用的便利而提供的。

虚拟后端

顾名思义,虚拟后端对你的消息没有任何作用。 要指定此后端,请在您的设置中添加以下内容:

EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'

这个后端不适合在生产环境中使用 - 它是作为开发过程中可以使用的便利而提供的。

定义自定义电子邮件后端

如果您需要更改电子邮件的发送方式,您可以编写自己的电子邮件后端。 您的设置文件中的EMAIL_BACKEND设置是您的后端类的Python导入路径。

自定义电子邮件后端应该位于django.core.mail.backends.base模块中的BaseEmailBackend子类。 自定义电子邮件后端必须实现send_messages(email_messages)方法。 这个方法接收一个EmailMessage实例的列表并返回成功发送消息的数量。 如果后端具有持久会话或连接的概念,则还应实现open()close()方法。 请参阅smtp.EmailBackend以获取参考实现。

发送多封电子邮件

建立和关闭SMTP连接(或任何其他网络连接)是一个昂贵的过程。 如果要发送大量电子邮件,则重复使用SMTP连接是有意义的,而不是在每次发送电子邮件时创建和销毁连接。

有两种方法告诉电子邮件后端重新使用连接。

首先,您可以使用send_messages()方法。 send_messages() takes a list of EmailMessage instances (or subclasses), and sends them all using a single connection.

例如,如果您有一个称为get_notification_email()的函数,它返回表示您希望发送的定期电子邮件的EmailMessage对象的列表,则可以使用单个呼叫send_messages:

from django.core import mail
connection = mail.get_connection()   # Use default email connection
messages = get_notification_email()
connection.send_messages(messages)

在这个例子中,对send_messages()的调用在后端打开一个连接,发送消息列表,然后再次关闭连接。

第二种方法是在电子邮件后端使用open()close()方法来手动控制连接。 send_messages() will not manually open or close the connection if it is already open, so if you manually open the connection, you can control when it is closed. 例如:

from django.core import mail
connection = mail.get_connection()

# Manually open the connection
connection.open()

# Construct an email message that uses the connection
email1 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to1@example.com'],
    connection=connection,
)
email1.send() # Send the email

# Construct two more messages
email2 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to2@example.com'],
)
email3 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to3@example.com'],
)

# Send the two emails in a single call -
connection.send_messages([email2, email3])
# The connection was already open so send_messages() doesn't close it.
# We need to manually close the connection.
connection.close()

为开发配置电子邮件

有时候你根本不想Django发送邮件。 例如,在开发一个网站的时候,你可能不想发送数以千计的电子邮件 - 但是你可能想验证那些电子邮件将在正确的条件下被发送给正确的人,这些电子邮件将包含正确的内容。

为本地开发配置电子邮件的最简单方法是使用console电子邮件后端。 这个后端将所有电子邮件重定向到标准输出,允许您检查邮件的内容。

在开发过程中,file电子邮件后端也是有用的 - 这个后端将每个SMTP连接的内容转储到一个可以在您闲暇时检查的文件。

另一种方法是使用“哑”SMTP服务器接收本地电子邮件,并将其显示到终端,但实际上并没有发送任何东西。 Python有一个内置的方法来完成这一个单一的命令:

python -m smtpd -n -c DebuggingServer localhost:1025

这个命令将启动一个简单的SMTP服务器监听localhost的端口1025。 这台服务器只是打印到标准输出所有电子邮件标题和电子邮件正文。 您只需要相应地设置EMAIL_HOSTEMAIL_PORT即可。 有关SMTP服务器选项的更详细的讨论,请参阅smtpd模块的Python文档。

有关在应用程序中发送电子邮件的单元测试的信息,请参阅测试文档的Email services部分。