Django 1.8.2 目录

发送邮件

尽管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 主机和端口发送。如果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: 一个布尔值。如果设置为 False, send_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/alternativemessage 格式变成 text/plainhtml_message 格式变成 text/html

The return value will be the number of successfully delivered messages (which can be 0 or 1 since it can only send one message).

New in Django 1.7:

The html_message parameter was added.

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()用来处理大批量邮件任务

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

(subject, message, from_email, recipient_list)

fail_silently, auth_user , auth_passwordsend_mail()中的方法相同.

Each separate element of datatuple results in a separate email message. As in send_mail(), recipients in the same recipient_list will all see the other addresses in the email messages’ “To:” field.

For example, the following code would send two different messages to two different sets of recipients; however, only one connection to the mail server would be opened:

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)

The return value will be the number of successfully delivered messages.

send_mass_mail() vs. 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() is a shortcut for sending an email to the site admins, as defined in the ADMINS setting.

mail_admins() prefixes the subject with the value of the EMAIL_SUBJECT_PREFIX setting, which is "[Django] " by default.

The “From:” header of the email will be the value of the SERVER_EMAIL setting.

This method exists for convenience and readability.

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.

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.

Examples

This sends a single email to john@example.com and jane@example.com, with them both appearing in the “To:”:

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

This sends a message to john@example.com and jane@example.com, with them both receiving a separate email:

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

Preventing header injection

Header injection是一个安全漏洞,攻击者插入额外的电子邮件标题控制”TO:“和”FROM:“在你的脚本生成的电子邮件

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

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

这里有个简单的例子, subject, messagefrom_email 来自于 request’s POST 数据, 发送数据到 admin@example.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.')

The EmailMessage class

Django的 send_mail()send_mass_mail() 是利用了EmailMessage class.的简单封装。

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

Note

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

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

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

EmailMessage Objects

class EmailMessage

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

  • subject: The subject line of the email.
  • body: The body text. This should be a plain text message.
  • from_email: The sender’s address. Both fred@example.com and Fred <fred@example.com> forms are legal. If omitted, the DEFAULT_FROM_EMAIL setting is used.
  • to: A list or tuple of recipient addresses.
  • bcc: A list or tuple of addresses used in the “Bcc” header when sending the email.
  • connection: An email backend instance. Use this parameter if you want to use the same connection for multiple messages. If omitted, a new connection is created when send() is called.
  • attachments: A list of attachments to put on the message. These can be either email.MIMEBase.MIMEBase instances, or (filename, content, mimetype) triples.
  • headers: A dictionary of extra headers to put on the message. The keys are the header name, values are the header values. It’s up to the caller to ensure header names and values are in the correct format for an email message. The corresponding attribute is extra_headers.
  • cc: A list or tuple of recipient addresses used in the “Cc” header when sending the email.
  • reply_to: A list or tuple of recipient addresses used in the “Reply-To” header when sending the email.
Changed in Django 1.8:

The reply_to parameter was added.

For example:

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'})

The class has the following methods:

  • send(fail_silently=False) sends the message. If a connection was specified when the email was constructed, that connection will be used. Otherwise, an instance of the default backend will be instantiated and used. If the keyword argument fail_silently is True, exceptions raised while sending the message will be quashed. 如果接受者为空,这并不会引起异常!

  • message() constructs a django.core.mail.SafeMIMEText object (a subclass of Python’s email.MIMEText.MIMEText class) or a django.core.mail.SafeMIMEMultipart object holding the message to be sent. If you ever need to extend the EmailMessage class, you’ll probably want to override this method to put the content you want into the MIME object.

  • recipients() returns a list of all the recipients of the message, whether they’re recorded in the to, cc or bcc attributes. This is another method you might need to override when subclassing, because the SMTP server needs to be told the full list of recipients when the message is sent. If you add another way to specify recipients in your class, they need to be returned from this method as well.

  • attach() creates a new file attachment and adds it to the message. There are two ways to call attach():

    • You can pass it a single argument that is an email.MIMEBase.MIMEBase instance. This will be inserted directly into the resulting message.

    • Alternatively, you can pass attach() three arguments: filename, content and mimetype. filename is the name of the file attachment as it will appear in the email, content is the data that will be contained inside the attachment and mimetype is the optional MIME type for the attachment. 如果你忽略了 mimetype,  MIME content type将会从你的文件名来猜测。。

      For example:

      message.attach('design.png', img_data, 'image/png')
      
      Changed in Django 1.7:

      If you specify a mimetype of message/rfc822, it will also accept django.core.mail.EmailMessage and email.message.Message.

      In addition, message/rfc822 attachments will no longer be base64-encoded in violation of RFC 2046, which can cause issues with displaying the attachments in Evolution and Thunderbird.

  • attach_file() creates a new attachment using a file from your filesystem. Call it with the path of the file to attach and, optionally, the MIME type to use for the attachment. If the MIME type is omitted, it will be guessed from the filename. The simplest use would be:

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

Sending alternative content types

在你要包含各种乱七八糟的内容在邮件内容时,这非常的有用; 最经典的案例就是发送text和HTML的信息版本。用Django的 email库, 你可以用 EmailMultiAlternatives 这个类来完成。这个类是 EmailMessage 的子类,它有 attach_alternative() 来包含额外的邮件信息版本。All the other methods (including the class initialization) are inherited directly from EmailMessage.

To send a text and HTML combination, you could write:

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()

By default, the MIME type of the body parameter in an EmailMessage is "text/plain".

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()
New in Django 1.8:

新增上下文管理器协议。

获取邮件后端的一个实例

位于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 后端(默认),其它后端只用于测试和开发阶段。如果发送邮件有特殊的需求,你可以编写自己的邮件后端

SMTP 后端

class 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,则从settings 中获取对应的设置:

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

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
New in Django 1.7:

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

Changed in Django 1.8:

添加ssl_keyfilessl_certfile 参数以及对应的settings。添加(EMAIL_TIMEOUT) 设置以使得可以自定义timeout

Console 后端

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

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

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

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

File 后端

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

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

In-memory 后端

'locmem' 后端将邮件保存在django.core.mail 模块的一个特殊属性中。当一封邮件发送时将创建outbox 属性。它是EmailMessage 实例的一个列表,表示每个将要发送的邮件。

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

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

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

Dummy 后端

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

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

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

Defining a custom email backend

If you need to change how emails are sent you can write your own email backend. The EMAIL_BACKEND setting in your settings file is then the Python import path for your backend class.

Custom email backends should subclass BaseEmailBackend that is located in the django.core.mail.backends.base module. A custom email backend must implement the send_messages(email_messages) method. This method receives a list of EmailMessage instances and returns the number of successfully delivered messages. If your backend has any concept of a persistent session or connection, you should also implement the open() and close() methods. Refer to smtp.EmailBackend for a reference implementation.

Sending multiple emails

Establishing and closing an SMTP connection (or any other network connection, for that matter) is an expensive process. If you have a lot of emails to send, it makes sense to reuse an SMTP connection, rather than creating and destroying a connection every time you want to send an email.

There are two ways you tell an email backend to reuse a connection.

Firstly, you can use the send_messages() method. send_messages() takes a list of EmailMessage instances (or subclasses), and sends them all using a single connection.

For example, if you have a function called get_notification_email() that returns a list of EmailMessage objects representing some periodic email you wish to send out, you could send these emails using a single call to send_messages:

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

In this example, the call to send_messages() opens a connection on the backend, sends the list of messages, and then closes the connection again.

The second approach is to use the open() and close() methods on the email backend to manually control the connection. 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. For example:

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()

Configuring email for development

There are times when you do not want Django to send emails at all. For example, while developing a Web site, you probably don’t want to send out thousands of emails – but you may want to validate that emails will be sent to the right people under the right conditions, and that those emails will contain the correct content.

The easiest way to configure email for local development is to use the console email backend. This backend redirects all email to stdout, allowing you to inspect the content of mail.

The file email backend can also be useful during development – this backend dumps the contents of every SMTP connection to a file that can be inspected at your leisure.

Another approach is to use a “dumb” SMTP server that receives the emails locally and displays them to the terminal, but does not actually send anything. Python has a built-in way to accomplish this with a single command:

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

This command will start a simple SMTP server listening on port 1025 of localhost. This server simply prints to standard output all email headers and the email body. You then only need to set the EMAIL_HOST and EMAIL_PORT accordingly. For a more detailed discussion of SMTP server options, see the Python documentation for the smtpd module.

For information about unit-testing the sending of emails in your application, see the Email services section of the testing documentation.