---
title: "发送邮件"
version: 5.1
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/5.1/topics/email/
canonical: https://djangodocs.dev/zh-hans/5.1/topics/email/
---
# 发送邮件

虽然 Python 通过 [`smtplib`](https://docs.python.org/3/library/smtplib.html#module-smtplib) 模块提供了邮件发送的接口，但是 Django 在其基础上提供了更简化的支持。这些封装意在加快邮件发送，在开发时测试发送邮件，在不支持 SMTP 的平台上支持发送邮件。

这些代码位于 `django.core.mail` 模块。

## 快速示例

使用 [`send_mail()`](#django.core.mail.send_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,
)
```

当需要额外的邮件发送功能时，使用 [`EmailMessage`](#django.core.mail.EmailMessage) 或 [`EmailMultiAlternatives`](#django.core.mail.EmailMultiAlternatives)。例如，发送包含 HTML 和纯文本版本的多部分邮件，使用特定模板和自定义标头，可以采用以下方法：

```
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string

# First, render the plain text content.
text_content = render_to_string(
    "templates/emails/my_email.txt",
    context={"my_variable": 42},
)

# Secondly, render the HTML content.
html_content = render_to_string(
    "templates/emails/my_email.html",
    context={"my_variable": 42},
)

# Then, create a multipart email instance.
msg = EmailMultiAlternatives(
    "Subject here",
    text_content,
    "from@example.com",
    ["to@example.com"],
    headers={"List-Unsubscribe": "<mailto:unsub@example.com>"},
)

# Lastly, attach the HTML content to the email instance and send.
msg.attach_alternative(html_content, "text/html")
msg.send()
```

邮件是通过 SMTP 主机和端口发送的，由配置项 [`EMAIL_HOST`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST) 和 [`EMAIL_PORT`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_PORT) 指定。如果配置了 [`EMAIL_HOST_USER`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST_USER) 和 [`EMAIL_HOST_PASSWORD`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST_PASSWORD) ，那么它们将被用来验证  SMTP 服务器。配置项 [`EMAIL_USE_TLS`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_USE_TLS) 和 [`EMAIL_USE_SSL`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_USE_SSL) 控制是否使用安全连接。

> **Note**
>
> 通过 `django.core.mail` 发送的邮件的字符编码由 [`DEFAULT_CHARSET`](/zh-hans/5.1/ref/settings/#std-setting-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)`

在大多数情况里，你可以使用 `django.core.mail.send_mail()` 来发送邮件。

参数 `subject`, `message`, `from_email` 和 `recipient_list` 是必须的。

- `subject`: 一个字符串。
- `message`: 一个字符串。
- `from_email` ：字符串。如果为 `None` ，Django 将使用 [`DEFAULT_FROM_EMAIL`](/zh-hans/5.1/ref/settings/#std-setting-DEFAULT_FROM_EMAIL) 设置的值。
- `recipient_list`: 一个字符串列表，每项都是一个邮箱地址。`recipient_list` 中的每个成员都可以在邮件的 "收件人:" 中看到其他的收件人。
- `fail_silently`: 一个布尔值。若为 `False`， `send_mail()` 会在发生错误时抛出 [`smtplib.SMTPException`](https://docs.python.org/3/library/smtplib.html#smtplib.SMTPException) 。可在 [`smtplib`](https://docs.python.org/3/library/smtplib.html#module-smtplib) 文档找到一系列可能的异常，它们都是 [`SMTPException`](https://docs.python.org/3/library/smtplib.html#smtplib.SMTPException) 的子类。
- `auth_user`: 可选的用户名，用于验证登陆 SMTP 服务器。 若未提供，Django 会使用 [`EMAIL_HOST_USER`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST_USER) 指定的值。
- `auth_password`: 可选的密码，用于验证登陆 SMTP 服务器。若未提供， Django 会使用 [`EMAIL_HOST_PASSWORD`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST_PASSWORD) 指定的值。
- `connection`: 可选参数，发送邮件使用的后端。若未指定，则使用默认的后端。查询 [邮件后端](#topic-email-backends) 文档获取更多细节。
- `html_message`: 若提供了 `html_message`，会使邮件成为 `multipart/alternative` 的实例， `message` 的内容类型则是 `text/plain` ，并且 `html_message` 的内容类型是 `text/html` 。

返回值会是成功发送的信息的数量（只能是 `0` 或 `1` ，因为同时只能发送一条消息）。

## `send_mass_mail()`

#### `send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)`

`django.core.mail.send_mass_mail()` 用于批量发送邮件。

`datatuple` 是一个元组，形式如下:

```
(subject, message, from_email, recipient_list)
```

`fail_silently`， `auth_user` 和 `auth_password` 拥有在 [`send_mail()`](#django.core.mail.send_mail) 中一样的功能。

`datatuple` 参数的每个元素会生成一份独立的邮件内容。就像 [`send_mail()`](#django.core.mail.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()`](#django.core.mail.send_mass_mail) and
[`send_mail()`](#django.core.mail.send_mail) is that
[`send_mail()`](#django.core.mail.send_mail) opens a connection to the mail server
each time it's executed, while [`send_mass_mail()`](#django.core.mail.send_mass_mail) uses
a single connection for all of its messages. This makes
[`send_mass_mail()`](#django.core.mail.send_mass_mail) slightly more efficient.

## `mail_admins()`

#### `mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)`

`django.core.mail.mail_admins()` 是定义在 [`ADMINS`](/zh-hans/5.1/ref/settings/#std-setting-ADMINS) 配置项中，用于向网站所有者快速发送邮件。

`mail_admins()` 在主题前面添加 [`EMAIL_SUBJECT_PREFIX`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_SUBJECT_PREFIX) 指定的前缀，默认是 `"[Django] "` 。

邮件头的 "发件人:" 由 [`SERVER_EMAIL`](/zh-hans/5.1/ref/settings/#std-setting-SERVER_EMAIL) 配置项指定。

创建这个方法是为了方便和可读性。

若提供了 `html_message`，会使邮件成为 `multipart/alternative` 的实例， `message` 的内容类型则是 `text/plain` ，并且 `html_message` 的内容类型是 `text/html` 。

## `mail_managers()`

#### `mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)`

`django.core.mail.mail_managers()` 类似 `mail_admins()`，但它向 [`MANAGERS`](/zh-hans/5.1/ref/settings/#std-setting-MANAGERS) 指定的管理员们发送邮件。

## 示例

以下发送了一封邮件给 [john@example.com](mailto:john@example.com) 和 [jane@example.com](mailto:jane@example.com)，他们都出现在 "收件人:":

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

以下分别发送了一封邮件给 [john@example.com](mailto:john@example.com) 和 [jane@example.com](mailto:jane@example.com)，他们收到了独立的邮件:

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

## 防止头注入

[Header injection](http://www.nyphp.org/phundamentals/8_Preventing-Email-Header-Injection.html) 是一个开发漏洞，攻击者可以利用它在邮件头插入额外信息，以控制脚本生成的邮件中的  "收件人:" 和 "发件人:" 内容。

Django 的邮件函数包含了以上所有的反头注入功能，通过在头中禁止新的行。如果 `subject`， `from_email` 或 `recipient_list` 包含了新行（不管是 Unix，Windows 或 Mac 格式中的哪一种），邮件函数（比如 [`send_mail()`](#django.core.mail.send_mail) ）都会抛出一个 `django.core.mail.BadHeaderError` （ `ValueError` 的子类），这会中断邮件发送。你需要在将参数传给邮件函数前确保数据的有效性和合法性。

如果邮件的 `内容` 的开始部分包含了邮件头信息，这些头信息只会作为邮件内容原样打印。

以下是一个实例视图，从请求的 POST 数据中获取 `subject`， `message` 和 `from_email`，并将其发送至 [admin@example.com](mailto:admin@example.com) ，成功后再重定向至 "/contact/thanks/"

```
from django.core.mail import BadHeaderError, send_mail
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()`](#django.core.mail.send_mail) 和 [`send_mass_mail()`](#django.core.mail.send_mass_mail) 函数仅是对类 [`EmailMessage`](#django.core.mail.EmailMessage) 的简单封装利用。

通过 [`send_mail()`](#django.core.mail.send_mail) 和其它关联的封装函数，不是所有 [`EmailMessage`](#django.core.mail.EmailMessage) 的功能都是可用的。如果你想用进阶功能，比如密送收件人，附件，分段邮件，你需要直接创建 [`EmailMessage`](#django.core.mail.EmailMessage) 的实例。

> **Note**
>
> 这是一种设计方式。最初 Django 只提供了 [`send_mail()`](#django.core.mail.send_mail) 和其它关联的函数。但是，随着时间的推移，它们的参数列表在慢慢地变长。所以，我们转向了更加面向对象的设计。在兼顾发送邮件的功能的同时，出于向后兼容的考虑，保留了这些函数。

[`EmailMessage`](#django.core.mail.EmailMessage) 用于创建邮件消息。 [邮件后端](#topic-email-backends) 用于发送邮件。

出于方便起见， [`EmailMessage`](#django.core.mail.EmailMessage) 提供了一个 `send()` 方法，用于发送一封邮件。如果你需要发送多封邮件，邮件后端 API [提供了选择](#topics-sending-multiple-emails)。

### `EmailMessage` 对象

#### `class EmailMessage`

类 [`EmailMessage`](#django.core.mail.EmailMessage) 通过以下参数构造（可选参数要按指定顺序提供）。所以的参数都是可选的，且可在调用 `send()` 方法前设置。

- `subject`: 邮件的主题。
- `body`: 邮件内容，需要为纯文本格式。
- `from_email`: 发件人地址。  `fred@example.com` 和 `Fred <fred@example.com>` 形式都是合法的。若省略，则使用 [`DEFAULT_FROM_EMAIL`](/zh-hans/5.1/ref/settings/#std-setting-DEFAULT_FROM_EMAIL) 配置的值。
- `to`: 一个包含收件人地址的列表或元组。
- `bcc`: 一个包含地址的列表或元组，指定“密送”对象。
- `connection`：一个 [邮件后端](#topic-email-backends) 实例。如果你通过 `send()` 发送 `EmailMessage` 并希望为多条消息使用相同的连接，请使用此参数。如果省略，则在调用 `send()` 时会创建一个新连接。使用 [send\_messages()](#topics-sending-multiple-emails) 时，此参数将被忽略。
- `attachments`: 附加在邮件中的附件列表。 可以是 [`MIMEBase`](https://docs.python.org/3/library/email.mime.html#email.mime.base.MIMEBase) 的实例，或 `(文件名，内容，mimetype)` 的元组。
- `headers`: 一个字典，包含邮件中额外的头信息。字典的关键字是头的名称，值为头的值。需要由调用者确保头名和值的正确性。对应的属性是 `extra_headers` 。
- `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_silently` 为 `True`，则在发送邮件消息时引发的异常将被抑制。如果收件人列表为空，不会引发异常。如果消息成功发送，将返回 `1`，否则返回 `0`。
- `message()` 构建了一个 `django.core.mail.SafeMIMEText` 对象（ [`MIMEText`](https://docs.python.org/3/library/email.mime.html#email.mime.text.MIMEText) 的子类）或一个 `django.core.mail.SafeMIMEMultipart` 对象用于存储邮件内容。如果你想继承 [`EmailMessage`](#django.core.mail.EmailMessage) ，你可能期望重写这个方法，在 MIME 对象中放入你期望的内容。
- `recipients()` 返回一个包含邮件所以收件人的列表，不管他们是收件人，抄送人，密送人中的哪一个。这可能是另一个你在创建子类时想复现的方法，因为 SMTP 服务器需要你在发送邮件时告诉它完整的收件人列表。如果你在子类中实现了另一个方法，指定收件人列表，这个方法必须也返回相同的结果。
- `attach()` 创建一个新的附件，并加到邮件。有两种调用 `attach()` 的方式:

  - 可以仅传送一个 [`MIMEBase`](https://docs.python.org/3/library/email.mime.html#email.mime.base.MIMEBase) 的实例。这会被直接插入邮件。
  - 另一个可选的方案，你可以向 `attach()` 传递 3 个参数： `filename` ， `content` 和 `mimetype`。 `filename` 是文件附件的名字，它会显示在邮件中， `content` 是附件包含的数据，而 `mimetype` 是一个可选参数，指定附件的 MIME 类型。如果你省略了 `mimetype`，MIME 类型将会参考附件的文件名。

    例如：

    ```
    message.attach("design.png", img_data, "image/png")
    ```

    如果你指定 `message/rfc822` 的 `mimetype`，它也会接受 [`django.core.mail.EmailMessage`](#django.core.mail.EmailMessage) 和 [`email.message.Message`](https://docs.python.org/3/library/email.compat32-message.html#email.message.Message)。

    对于以 `text/` 开头的 `mimetype` 类型，其内容应该是字符串。二进制数据将尝试以 UTF-8 解码，如果失败了，MIME 类型会被改为 `application/octet-stream` ，并不会修改数据内容。

    此外， `message/rfc822` 附件不再是 base64 编码，因为违反了 [**RFC 2046 Section 5.2.1**](https://datatracker.ietf.org/doc/html/rfc2046.html#section-5.2.1) 。之前在 [Evolution](https://bugzilla.gnome.org/show_bug.cgi?id=651197) 和 [Thunderbird](https://bugzilla.mozilla.org/show_bug.cgi?id=333880) 会造成显示问题。
- `attach_file()` 通过从本地文件系统中选择一个文件的方式创建附件。调用时，传入文件的路径。附件的 MIME 类型是可选的。如果省略了 MIME 类型，会参考文件名。你可以这样使用：

  ```
  message.attach_file("/images/weather_map.png")
  ```

  对于 MIME 类型以 `text/` 开头的，二进制数据的处理方式与 `attach()` 中的一样。

### 发送可选的内容类型。

#### 发送多个内容版本

在电子邮件中包含多个版本的内容可能很有用；经典的例子是同时发送文本和 HTML 版本的消息。使用 Django 的邮件库，你可以通过 [`EmailMultiAlternatives`](#django.core.mail.EmailMultiAlternatives) 类来实现这一点。

#### `class EmailMultiAlternatives`

[`EmailMessage`](#django.core.mail.EmailMessage) 的一个子类，它有一个额外的 `attach_alternative()` 方法，用于在电子邮件中包含消息正文的额外版本。所有其他方法（包括类初始化）都直接从 [`EmailMessage`](#django.core.mail.EmailMessage) 继承。

#### `attach_alternative(content, mimetype)`

在电子邮件中附加消息正文的替代表示。

例如，要发送文本和 HTML 组合，你可以这样写：

```
from django.core.mail import EmailMultiAlternatives

subject = "hello"
from_email = "from@example.com"
to = "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`](#django.core.mail.EmailMessage) 的 `body` 参数的 MIME 类型是 `"text/plain"`。经验告诉我们，不改它会更好。因为这样能确保不管收件人使用何种邮件客户端都可以正常的阅读邮件。不过，如果你能确保你的收件人都能处理可选的内容类型，你可以使用 [`EmailMessage`](#django.core.mail.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`](#django.core.mail.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()`](#django.core.mail.get_connection) 函数返回一个你能使用的邮件后端实例。

#### `get_connection(backend=None, fail_silently=False, *args, **kwargs)`

默认情况下，调用 `get_connection()` 会返回配置项 [`EMAIL_BACKEND`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_BACKEND) 指定的后端。如果你传入了 `backend` 参数，将会返回该后端的实例。

`fail_silently` 控制后端怎么处理错误。若 `fail_silently` 为 True，发送邮件过程中的异常都会被和谐掉。

剩余的参数将直接传给邮件后端的构造器。

Django 自带了几种邮件后端。除了 SMTP 后端（默认值）外，这些后端应仅在开发和测试阶段使用。如果对发送邮件有特殊的需求，你可以 [编写自定义后端](#topic-custom-email-backend)。

#### 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`，则会从匹配的设置项中读取：

- `host`: [`EMAIL_HOST`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST)
- `port`: [`EMAIL_PORT`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_PORT)
- `username`: [`EMAIL_HOST_USER`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST_USER)
- `password`: [`EMAIL_HOST_PASSWORD`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST_PASSWORD)
- `use_tls`: [`EMAIL_USE_TLS`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_USE_TLS)
- `use_ssl`: [`EMAIL_USE_SSL`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_USE_SSL)
- `timeout`: [`EMAIL_TIMEOUT`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_TIMEOUT)
- `ssl_keyfile`: [`EMAIL_SSL_KEYFILE`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_SSL_KEYFILE)
- `ssl_certfile`: [`EMAIL_SSL_CERTFILE`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_SSL_CERTFILE)

SMTP 后端是 Django 默认配置的。如果你想显示的指定，将以下内容放入你的配置中：

```
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
```

若未指定，`timeout` 的默认值将由 [`socket.getdefaulttimeout()`](https://docs.python.org/3/library/socket.html#socket.getdefaulttimeout) 的返回值确定，其默认值为 `None` （无超时）。

#### 控制台后端

控制台后端仅将邮件发送至标准输出，而不是真的发送。默认情况下，控制台后端输出至 `stdout`。在创建连接时，你可以提供 `stream` 关键字参数来使用另一个类似 stream 的对象。

为了使用该后端，将以下代码加入你的配置中：

```
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
```

该后端不是为了在生产环境使用的——出于方便的目的，让你在开发阶段使用。

#### 文件后端

文件后端将邮件写入文件。对该后端的每次会话都会创建新文件。存储这些文件的目录可以从配置项 [`EMAIL_FILE_PATH`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_FILE_PATH) 获取，也可在调用 [`get_connection()`](#django.core.mail.get_connection) 时以关键字参数 `file_path` 指定。

为了使用该后端，将以下代码加入你的配置中：

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

该后端不是为了在生产环境使用的——出于方便的目的，让你在开发阶段使用。

#### 内存后端

该缓存式后端将内容存在 `django.core.mail` 模块的某个属性值中。`outbox` 属性会在第一条消息发送时创建。这是一个列表，每项都是一个 [`EmailMessage`](#django.core.mail.EmailMessage) 实例，代表一条要被发送的消息。

为了使用该后端，将以下代码加入你的配置中：

```
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
```

该后端不是为了在生产环境使用的——出于方便的目的，让你在开发阶段使用。

Django 的测试器 [自动为测试使用这个后端](/zh-hans/5.1/topics/testing/tools/#topics-testing-email)。

#### 虚拟后端

就像该后端的名字表示的一样，该后端对你发送的消息什么也不做。指定该后端，将以下代码加入你的配置中：

```
EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
```

该后端不是为了在生产环境使用的——出于方便的目的，让你在开发阶段使用。

### 自定义邮件后端

若你需要修改邮件发送的方式，你可以编写自定义的邮件后端。后面要在 [`EMAIL_BACKEND`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_BACKEND) 配置项中指定你的后端类的路径。

自定义邮件后端需继承 `django.core.mail.backends.base` 模块中的 `BaseEmailBackend` 类。自定义邮件后端类必须实现 `send_messages(email_messages)` 方法。该方法接受一个包含 [`EmailMessage`](#django.core.mail.EmailMessage) 对象的列表。若你的后端还处理了持久性会话和连接，你还需要实现 `open()` 和 `close()` 方法。可以参考 `smtp.EmailBackend` 的实现。

### 发送多封邮件

创建和关闭 SMTP 连接（或其它网络连接）是一项耗时的进程。如果你有很多封邮件要发送，复用连接就显得很有意义，而不是在每次发送邮件时创建和关闭连接。

有两种方式可以让邮件后端复用连接。

首先，你可以在连接上使用 `send_messages()` 方法。这需要一个 [``EmailMessage`（或其子类）实例的列表，并使用该单一连接发送它们。因此，在单个消息上设置的任何 :class:`connection``](#django.core.mail.EmailMessage) 都会被忽略。

举个例子，你有一个函数，叫做 `get_notification_email()` ，他会返回一个包含 [`EmailMessage`](#django.core.mail.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](#topic-email-console-backend) 电子邮件后端。该后端将所有电子邮件重定向到 `stdout`，允许您查看邮件的内容。

[文件](#topic-email-file-backend) 邮件后端在开发时也很有用——这个后端将每次 SMTP 连接的内容输出至一个文件，你可以在你闲暇时查看这个文件。

另一种方法是使用一个“哑”SMTP 服务器，它在本地接收电子邮件并将其显示到终端，但实际上并不发送任何内容。[aiosmtpd](https://pypi.org/project/aiosmtpd/) 包提供了一种实现此目的的方法：

```shell
python -m pip install aiosmtpd

python -m aiosmtpd -n -l localhost:8025
```

这个命令将启动一个最小的 SMTP 服务器，监听在 localhost 的 8025 端口上。该服务器将打印所有电子邮件头和电子邮件正文到标准输出。然后，您只需要相应地设置 [`EMAIL_HOST`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_HOST) 和 [`EMAIL_PORT`](/zh-hans/5.1/ref/settings/#std-setting-EMAIL_PORT)。有关 SMTP 服务器选项的更详细讨论，请参阅 [aiosmtpd](https://aiosmtpd.readthedocs.io/en/latest/) 模块的文档。

关于发送邮件的单元测试资料，参见测试文档中 [邮件服务](/zh-hans/5.1/topics/testing/tools/#topics-testing-email) 章节。
