Django邮件发送详解:从send_mail到Backend底层机制

Chloe
Chloe
发布时间:2026-10-13 | 5人浏览过
原创

本文深入解析Django核心邮件模块django.core.mail。详细对比send_mail与send_mass_mail的使用场景及性能差异,演示如何通过EmailMessage类实现抄送、密送及附件功能。进一步剖析Backend机制,包括默认SMTP后端、Console/Dummy后端的配置,以及如何通过自定义Backend和控制连接生命周期来优化批量邮件发送效率。

Django邮件模块概述

前言

在Python标准库中,smtplib模块提供了基础的邮件发送功能,而Django对该模块进行了高层封装,极大简化了Web应用中的邮件处理流程。

Django处理邮件的核心模块位于django.core.mail中。

基础发送函数:send_mail与send_mass_mail

两个常用函数

该模块提供了两个最常用的便捷函数,使用方式非常直观:


def send_mail(subject, message, from_email, recipient_list,
       fail_silently=False, auth_user=None, auth_password=None,
       connection=None, html_message=None):
  pass     
  
      
def send_mass_mail(datatuple, fail_silently=False, auth_user=None,
          auth_password=None, connection=None):
  pass

# 参数介绍  
# subject: 邮件主题 
# message: 邮件内容 
# from_email: 发件人 
# recipient_list: 收件人,这是一个列表,可以有多个收件人 
# 以上4个在参数 在send_mass_mail中,会写在datatuple这个元组中 
# fail_silently: 是否报错,True的话表忽略异常 
# auth_user&auth_password:账号密码 
# connection: 表示这个的链接对象,后续会提到 
# html_message: send_mail方法独有,可以比较简单地实现一个html文本的传输,具体我也没使用过,不是很了解。

通常情况下,我们需要在Django的settings.py配置文件中进行邮件服务器相关配置。除了必须指定的host(主机)和port(端口)外,通常建议将账号(auth_user)和密码(auth_password)也写入配置文件中。这样在每次调用发送函数时无需重复传递这些敏感参数;若调用时未显式提供这两个值,系统会自动读取settings中的配置。

发送函数的返回值表示成功发送的消息数量,而非接收人的数量。一般使用send_mail时,无论收件人列表有多少人,只要发送成功,返回值通常为1。


# settings.py
# 我使用的是新浪的,host可以在对应邮箱的设置中找到
EMAIL_HOST = 'smtp.sina.com'
EMAIL_PORT = 25
# 你的邮箱账号与密码
EMAIL_HOST_USER = 'viptestfordjango@sina.com'
EMAIL_HOST_PASSWORD = '******'
# 由于使用25端口,一般都不使用TLS机密,SSL和TSL只需要设置一个,他们同时为True或False
EMAIL_USE_TLS = False
# 发件人,只有这个变量名可以自己自定义,设置在这里是为了减少每次去写
EMAIL_FROM = 'viptestfordjango@sina.com'

实例


from django.core.mail import send_mail, send_mass_mail
from string import lowercase,uppercase,digits
from random import randint
from project.settings import EMAIL_FROM
def send_code_email(email):
  """
  发送验证码
  """
  # 0-9 a-z A-z
  code = ''
  seeds= lowercase+uppercase+digits
  length = len(seeds)
  # 生成4位验证码
  for i in range(4):
    code += seeds[randint(0, length-1)]
  send_title = '重置密码'
  send_message = '你的验证码是:{0}。'.format(code)
  send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])


def send_hello_email(email1, email2):
  """
  给email1发送 新年好
  给email2发送 Happy New Year
  """
  # message格式(subject, message, from_email, recipient_list)
  message1 = ('新年好', '新年好', 'EMAIL_FROM', [email])
  message2 = ('Happy New Year', 'Happy New Year', EMAIL_FROM, [email2])
  send_status=send_mass_mail((message1, message2), fail_silently=False)

从上述示例可以明显看出两个函数的区别:send_mail用于一次性发送单个邮件内容(可包含多个收件人),而send_mass_mail则允许一次性发送多个不同的邮件内容(每个内容对应不同的收件人或主题)。

从底层机制理解,上述两个函数都接受一个connection参数。结合该参数可知,send_mail每次调用仅建立一次连接并发送一种邮件内容;而send_mass_mail可以在一次连接中发送多个不同的邮件内容,从而显著提高效率。

高级邮件功能:EmailMessage类详解

高级功能

前述两个便捷函数实际上是对EmailMessage类的封装,旨在提供简单易用的接口,但其功能相对有限,例如不支持抄送(cc)、密送(bcc)以及附件添加(attachments)。若需使用这些高级功能,必须直接使用EmailMessage类。

EmailMessage


# 类定义
class EmailMessage(object):
  def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
         connection=None, attachments=None, headers=None, cc=None,
         reply_to=None):
  pass
  
# 使用
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'},
)

在EmailMessage类的参数中,抄送列表(cc)、密送列表(bcc)以及回复地址列表(reply_to)均接受列表类型的数据。

值得注意的是attachments参数,它同样是一个列表。其元素可以是MIMEBase对象,也可以是包含三个元素的元组:(filename, content, mimetype),分别代表显示的文件名、文件数据内容以及文件的MIME类型。

该类还提供了一些实用方法,主要介绍两个:send()用于发送邮件,以及attach()用于添加附件。

底层机制:Backend与连接管理

直接使用Backend

如果像上面那样直接调用EmailMessage.send(),每次连接仅发送一个邮件对象。若想在一次连接中发送多个邮件,该如何操作?

此时,我们需要深入了解Backend(后端)机制。

Django的邮件发送功能由Backend控制,该类提供几个关键方法:

open():用于打开一个网络连接。

close():用于关闭网络连接。

send_messages(email_messages):接收一个EmailMessage对象的列表,并将多个邮件发送出去。EmailMessage的send()方法内部正是调用此方法,只是传递的参数仅为包含自身的列表[self]。

因此,如果我们能手动控制连接的打开与关闭,就能实现多个EmailMessage对象通过同一次连接发送。此时,我们可以考虑使用上下文管理器来自动控制连接的开启与关闭:


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

这种手动管理连接的方式显得较为繁琐。我们更希望直接调用send_messages(),并传递一个EmailMessage对象的列表。注意到前文提到的get_connection()函数,它可以直接获取到一个Backend对象,随后直接调用该对象的send_messages()方法即可。


from django.core import mail

connection = mail.get_connection()
# get_EmailMessage_list返回一个EmailMessage对象的列表
messages = get_EmailMessage_list()
connection.send_messages(messages)

当直接调用send_messages(messages)时,如果当前没有打开的连接,系统会自动先打开连接,执行发送操作后自动关闭连接。

这种方式虽然可行,但灵活性稍显不足。实际上,我们也可以完全手动控制open()与close()操作。


from django.core import mail

connection = mail.get_connection()
connection.open()

email1 = mail.EmailMessage(
  'Hello',
  'Body goes here',
  'from@example.com',
  ['to1@example.com'],
  connection=connection,
)
email1.send() 

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'],
)
connection.send_messages([email2, email3])

connection.close()

此示例展示了EmailMessage.send()与connection.send_messages()的配合使用,主要起演示作用,实际开发中无需同时混用这两种方式。

Backend类型配置与自定义

backend类型与定制

前文多次提及Backend,它究竟是什么?默认情况下,Django使用的是backends.smtp.EmailBackend。


# 在django.core.mail。backends.smtp.下
class EmailBackend(BaseEmailBackend):

  def __init__(self, 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):
    pass

该类继承自BaseEmailBackend,是Django默认的邮件后端,负责控制整个发送邮件的过程。虽然Django还提供了其他类型的Backend,但在常规应用中作用有限。

Console backend:将邮件内容直接输出到标准输出(stdout)中,常用于调试。

Dummy backend:不执行任何实际发送操作,仅用于测试。

你只需在settings配置文件中指定所使用的Backend类路径:


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

此外,还可以自定义Backend。你需要继承BaseEmailBackend,并实现send_messages(email_messages)、open以及close方法。不过,鉴于smtp.EmailBackend已提供完善的功能,通常无需自定义。

后言

本文内容主要基于Django 1.11官方文档整理,文字部分结合文档说明与个人理解编写,可能存在理解偏差,欢迎读者指正。

参考文章:

Django 1.11官方文档 email章节

总结

以上就是本文的全部内容,希望本文对大家在Django邮件开发或相关工作中具有参考学习价值,感谢支持。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表