发送邮件

尽管Python 通过smtplib 模块使得发送邮件很简单,Django 仍然在此基础上提供了几个轻量的封装包。 这些封装包使得发送邮件非常快速、让开发中测试发送邮件变得很简单、并且支持不使用SMTP 的平台。

这些代码包含在django.core.mail模块中。

Quick example

两行代码实现:

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 主机和端口发送。 如果settings中设置了 EMAIL_HOST_USEREMAIL_HOST_PASSWORD 它们将被用来验证SMTP主机, 并且如果设置了 EMAIL_USE_TLSEMAIL_USE_SSL 它们将控制是否使用相应的加密链接。

django.core.mail发送邮件时使用的字符集将按照你在settings中的 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:一个字符串。
  • message:一个字符串。
  • from_email:一个字符串。
  • recipient_list:一个由邮箱地址组成的字符串列表。 recipient_list 中的每一个成员都会在邮件信息的“To:”区域看到其它成员。
  • fail_silently: 一个布尔值。 如果它是Falsesend_mail将会引发一个smtplib.SMTPException 查看 smtplib 文档中列车出的所有可能的异常, 它们都是 SMTPException的子类。
  • auth_user: 可选的用户名用来验证SMTP服务器。 如果没有提供这个值, Django 将会使用settings中 EMAIL_HOST_USER 的值。
  • auth_password: 可选的密码用来验证 SMTP 服务器。 如果没有提供这个值, Django 将会使用settings中 EMAIL_HOST_PASSWORD 的值。
  • connection: 可选的用来发送邮件的电子邮件后端。 如果没有指定,将使用缺省的后端实例。 查看 Email backends 文档来获取更多细节。
  • html_message: 如果提供了 html_message ,会导致邮件变成 multipart/alternativehtml_message 格式变成 text/plainmessage 格式变成 text/html

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

send_mass_mail()

send_mass_maildatatuplefail_silently = Falseauth_user = Noneauth_password = Noneconnection = None[source]

django.core.mail.send_mass_mail()用来处理大批量邮件任务

datatuple是一个元组,其中元素的格式如下

(subject, message, from_email, recipient_list)

fail_silently, auth_user , auth_passwordsend_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()send_mail()

send_mass_mail()send_mail()的主要差别是 send_mail() 每次运行时打开一个到邮箱服务器的连接,而 send_mass_mail() 对于所有的信息都只使用一个连接。 这使得 send_mass_mail() 更高效点.

mail_admins()

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

django.core.mail.mail_admins()是向ADMINS设置中定义的网站管理员发送电子邮件的快捷方式。

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

电子邮件的“From:”标头将是SERVER_EMAIL设置的值。

此方法的存在是为了方便和可读性。

如果提供了html_message,则生成的电子邮件将是多部分/备用电子邮件message作为文本/普通内容类型和html_message作为text / html内容类型。

mail_managers()

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

django.core.mail.mail_managers()就像mail_admins(),除了它向网站管理员发送电子邮件,如MANAGERS

实例¶ 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是一个安全漏洞,攻击者插入额外的电子邮件标题控制”TO:“和”FROM:“在你的脚本生成的电子邮件

Django的电子邮件上述的功能概述都是通过标头值禁止换行来防止头注入。 如果任意的 ValueError, recipient_list 或者subject 包含一个新行 (in either Unix, Windows or Mac style), 则email功能函数 (e.g. send_mail()) 将会引起 from_email (django.core.mail.BadHeaderError的子类) 因此,并不会发送邮件。 你有责任在把数据发送到email功能函数之前进行验证。

如果一条 message字符串包含了一个header开头,这个header将会被简单的打印为这条email的第一个字节。

这是一个从请求的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 class.的简单封装。

并不是所有的 EmailMessage类 的特性都可以通过 send_mail() 和相关的封装函数来实现的。 如果你想用更高级的特性, 比如 BCC’ed recipients, 附件上传, 多部分邮件, 你需要直接创建 EmailMessage 实例。

这是一个设计特点。 send_mail() 和相关的函数是django最初提供的接口。 然而,.参数列表随着时间的推移不断增长。 转向面向对象设计的邮件信息,并且保留最初的功能以向后兼任是明智之举。

EmailMessage 负责创建电子邮件本身。 email backend 才是负责发送email的。

方便起见, EmailMessage 提供了一个简单的 send() 方法来发送单一邮件。. 如果你需要发送多份邮件, email的后端 API provides an alternative.

EmailMessage对象

EmailMessage[source]

EmailMessage 这个类由一下这些参数来实例化 (in the given order, if positional arguments are used). 所有参数都是可选的并且可以在 send() 方法之前的任意时间设置。

  • subject:电子邮件的主题行。
  • body:正文文本。 这应该是纯文本消息。
  • from_email:发件人的地址。 表单合法,fred@example.comFred < fred@example.com> 如果省略,则使用DEFAULT_FROM_EMAIL设置。
  • to:收件人地址的列表或元组。
  • bcc:发送电子邮件时在“密件抄送”标头中使用的地址列表或元组。
  • connection:电子邮件后端实例。 如果要对多个消息使用相同的连接,请使用此参数。 如果省略,则在调用send()时创建新连接。
  • attachments:要放在邮件上的附件列表。 这些可以是email.MIMEBase.MIMEBase实例,或(filename, 内容, 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)发送消息。 如果在构建电子邮件时指定了连接,则将使用该连接。 否则,将实例化并使用默认后端的实例。 如果关键字参数fail_silentlyTrue,则发送消息时抛出的异常将被取消。 如果接受者为空,这并不会引起异常!

  • message()构造一个django.core.mail.SafeMIMEText对象(Python的email.MIMEText.MIMEText类的子类)或django.core.mail.SafeMIMEMultipart对象持有要发送的消息。 如果您需要扩展EmailMessage类,那么您可能想要覆盖此方法,将所需的内容放入MIME对象中。

  • recipients()返回邮件的所有收件人列表,无论这些收件人是记录在toccbcc属性。 这是您在子类化时可能需要覆盖的另一种方法,因为在发送消息时,需要告知SMTP服务器收件人的完整列表。 如果您添加另一种方式来指定类中的收件人,则还需要从此方法返回。

  • attach()创建一个新文件附件并将其添加到消息中。 有两种方法调用attach()

    • 您可以传递一个参数,它是一个email.MIMEBase.MIMEBase实例。 这将直接插入到生成的消息中。

    • 或者,您可以传递attach()三个参数:filenamecontentmimetype filename是电子邮件中显示的文件附件的名称,content是附件中包含的数据,mimetype是附件的可选MIME类型。 如果你忽略了 mimetype, MIME content type将会从你的文件名来猜测。。

      像这样:

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

      如果您指定mimetypemessage/rfc822,它也会接受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()使用文件系统中的文件创建新附件。 使用要附加的文件的路径和可选的用于附件的MIME类型调用它。 如果省略MIME类型,则将从文件名中猜出。 最简单的用法是:

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

    对于以text/开始的MIME类型,二进制数据按照attach()的方式进行处理。

在Django更改1.11:

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

发送替代内容类型

在电子邮件中包含多个版本的内容可能是有用的;典型的例子是发送消息的文本和HTML版本。 用Django的 email库, 你可以用 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()

默认情况下,EmailMessagebody参数的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() 实例化一个用于发送邮件的长连接。
  • close() 关闭当前的邮件发送连接。
  • send_messages(email_messages) 发送一个EmailMessage 对象的列表。 如果连接没有打开,该调用将隐式打开连接,并在之后关闭连接。 如果连接已经打开,它在邮件发送之后会保持打开状态。

它还可以用作上下文管理器,在需要的时候自动调用open()close()

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。EmailBackendhost = Noneport = Noneusername = Nonepassword = t4>,use_tls = Nonefail_silently = Falseuse_ssl = Nonetimeout = Nonessl_keyfile =无ssl_certfile =无** kwargs

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

每个参数的值如果为None,则从settings 中获取对应的设置:

SMTP 后端是Django 内在的默认配置。 如果你想显示指定,可以将下面这行放到settings 中:

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

如果没有指定,默认的timeoutsocket.getdefaulttimeout() 提供的值,它默认是None(不会超时)。

控制台后端

Console 后端不真正发送邮件,而只是向标准输出打印出邮件。 默认情况下,console 后端打印到stdout 你可以通过在构造connection 时提供stream 参数,来使用一个不同的流对象。

如要指定这个后端,可以将下面这行放入你的settings 中:

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

这个后端不能用于生产环境 —— 它只是为了开发方便。

文件后端

File 后端将邮件写到文件中。 该后端的每个会话将创建一个新的文件。 文件的目录从EMAIL_FILE_PATH 设置或者get_connection()file_path 关键字参数获取。

如要指定这个后端,可以将下面这行放入你的settings 中:

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 实例的一个列表,表示每个将要发送的邮件。

如要指定这个后端,可以将下面这行放入你的settings 中:

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

这个后端不能用于生成环境 —— 它只是为了开发和测试方便。

虚假后端

和名字一样,dummy 后端什么也不做。 如要指定这个后端,可以将下面这行放入你的settings 中:

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

这个后端不能用于生产环境 —— 它只是为了开发方便。

定义自定义邮件后端

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

自定义电子邮件后端应该位于BaseEmailBackend模块中的django.core.mail.backends.base 自定义电子邮件后端必须实施send_messages(email_messages)方法。 此方法接收EmailMessage实例的列表,并返回已成功传递的邮件数。 如果您的后端有任何持续会话或连接的概念,您还应该实现open()close()方法。 参考smtp.EmailBackend作参考实现。

发送多个电子邮件

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

有两种方法可以让电子邮件后端重复使用连接。

首先,您可以使用send_messages()方法。 send_messages()获取EmailMessage实例(或子类)的列表,并使用单个连接发送它们。

例如,如果您有一个名为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()将不会手动打开或关闭已打开的连接,因此如果您手动打开连接,则可以控制它何时关闭。 像这样:

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电子邮件后端。 此后端将所有电子邮件重定向到stdout,允许您检查邮件的内容。

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

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

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

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

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