Django邮件发送详解:从send_mail到Backend底层机制
本文深入解析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邮件开发或相关工作中具有参考学习价值,感谢支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









