Django 官方文档 发送email
尽管使用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)
使用项目的settings中通过EMAIL_HOST和EMAIL_PORT设置的SMTP主机和端口发送邮件。 EMAIL_HOST_USER和EMAIL_HOST_PASSWORD用于授权SMTP服务器,EMAIL_USE_TLS和EMAIL_USE_SSL控制是否使用安全连接。
注意:
django.core.mail发送电子邮件使用的字符集通过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:发送人的email,格式为字符串;
-
recipient_list:字符串数组,每项都是邮箱地址。recipient_list的每个成员都将在电子邮件的“To:”字段中看到其他收件人。
-
fail_silently:布尔值,如果为False,send_mail出现错误时将引发smtplib.SMTPException。查看smtplib文档查看可能出现的异常,这些异常都是SMTPException的子类。
-
auth_user: 用于向SMTP服务器进行身份验证的可选用户名。 如果未提供此项,Django将使用EMAIL_HOST_USER设置的值。
-
auth_password: 用于向SMTP服务器进行身份验证的可选密码。 如果未提供此项,Django将使用 EMAIL_HOST_PASSWORD设置的值。
-
connection:发送邮件的可选邮件后端。如果没有指定将使用默认后端的实例。内容详见Email backends。
-
html_message: 如果提供html_message,生成的电子邮件将是一个使用message作为text/plain内容类型的多部分/可替代电子邮件,html_message为text/html内容类型。
send_mail的返回值为成功发送邮件的数量(由于它可以只发送一条信息,因此值可能是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()中的功能一样。
datatuple的每个单独元素产生单独的电子邮件消息。 但是send_mail()中同一recipient_list中的收件人将看到电子邮件的“To:”字段中的其他地址。
例如,以下代码将只打开一个到邮件服务器的链接而向两个不同的收件人发送两个不同的消息:
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()
send_mass_mail()和send_mail()最大的区别在于send_mail()在每次发送邮件时都要打开一个邮件服务器的连接,而send_mass_mail()使用一个连接发送所有邮件。 这使得send_mass_mail()更有效率。
mail_admin()
mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)
django.core.mail.mail_admins()
是向ADMINS设置中定义的网站管理员发送电子邮件给的快捷方式。
mail_admins()
使用 EMAIL_SUBJECT_PREFIX定义的值(默认为"[Django]")对主题进行预处理。
SERVER_EMAIL设置电子邮件的“From:”标头的值。
这个方法的存在是为了方便和易读。
如果提供html_message,则生成的电子邮件将是一个多部分/替代电子邮件,它的message为text/html类型,html_message也为text/html类型。
mail_manager()
mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)
django.core.mail.mail_managers() 与mail_admins()类似,区别在于它用于向settings中的MANAGERS中定义的值发送邮件。
例子
下面的例子向john@example.com和jane@example.com发送单个邮件,它们都出现在“收件人:”中:
send_mail('Subject','Message.','from@example.com',['john@example.com', 'jane@example.com'],)
下面的例子向john@example.com和
jane@example.com发送邮件,他们都收到了各自的邮件:
datatuple = (
('Subject', 'Message.', 'from@example.com', ['john@example.com']),
('Subject', 'Message.', 'from@example.com', ['jane@example.com']),
)
send_mass_mail(datatuple)
防止标头注入
标头注入是一种安全漏洞,攻击者可以使用它插入额外的电子邮件头来控制脚本生成的电子邮件的“To:”和“From:”。
上面列出的Django电子邮件函数通过禁止标头中包含换行符来防止标题插入。如果subject,from_email或recipient_list中的任何一个包含换行符(无论Unix,Windows还是Mac中的样式),电子邮件函数(例如send_mail())将引发django.core.mail.BadHeaderError(ValueError的子类)并且停止发送电子邮件。我们需要在将所有数据传递到电子邮件函数之前对其进行验证。
如果消息的开头包含标头,则标头将被显示在消息的开头部分。
下面是一个示例,视图从请求的POST数据中获取subject, message和from_email,将其发送到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.')
EmailMessage类
Django的send_mail()和send_mass_mail()函数实际上是EmailMessage类的封装。
我们无法通过send_mail()和相关的封装函数获取所有的EmailMessage类特性。如果希望使用暗送收件人(bcc)、文件附件或多部分邮件等高级特性,则需要直接创建EmailMessage实例。
注意
这是一个设计特性。 send_mail()和相关函数最初是Django提供的唯一接口。然而,慢慢地它们接受的参数列表不断增加。使电子邮件更加面向对象并保留原始功能(仅用于向后兼容)的设计是有意义的。
EmailMessage负责创建电子邮件消息本身。
电子邮件后端负责发送电子邮件。
为了方便起见,EmailMessage提供一个简单的send()方法来发送单个电子邮件。如果需要发送多封邮件,则电子邮件后端API提供了另一种选择。
EmailMessage对象
class EmailMessage
EmailMessage类使用以下参数(如果使用位置参数则需要按给定顺序设置)初始化。所有参数都是可选的,并且可以在调用send()方法之前的任何时间设置。
-
subject:电子邮件的主题。
-
body:正文文本。应该是纯文本消息。
-
from_email:发件人地址。
fred@example.com
和Fred <fred@example.com>
两种格式都是合法的。如果省略,则使用DEFAULT_FROM_EMAIL设定的地址。 -
to: 收件人地址列表或元组。
-
bcc:发送电子邮件时在“暗送”标头中使用的地址的列表或元组。
-
connection:一个邮件后端实例。如果希望为多条信息使用相同的连接则使用该参数。如果忽略,当调用send()时将产生新的连接。
-
attachments: 放到邮件中的附件列表。可以是email.MIMEBase.MIMEBase实例,或(filename,content,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,发送电子邮件时引发的异常将被掩盖。收件人为空列表将不会引发任何异常。
-
message()
构造一个
django.core.mail.SafeMIMEText
对象(Python中
email.MIMEText.MIMEText
的子类)django.core.mail.SafeMIMEMultipart
对象来保存要发送的消息。 如果需要扩展EmailMessage类,需要重写这个方法把想要的内容放到MIME对象中。 -
recipients()
返回所有邮件接收者(包括to、cc、bcc属性)的列表。这是另一个可能需要重写的函数,因为发送消息时需要告诉SMTP服务器所有接收者的列表。如果在子类中增加另一种指定接收者的方法,它们也需要从这个方法中返回。
-
attach()
创建一个新的邮件附件并将其添加到邮件。有两种方法调用attach():
-
只传入一个
email.MIMEBase.MIMEBase
实例,直接将其填入邮件; -
传入filename, content和mimetype三个参数。filename是文件附件的名字,它将出现在邮件中,content是将包含在附件中的数据,minetype是用于附件的可选MIME类型。如果忽略mimetype,将通过附件的文件名称猜测MIME类型。
例如:
-
message.attach('design.png', img_data, 'image/png')
如果指定minetype为message/rfc822
,它也将接收django.core.mail.EmailMessage
和email.message.Message
。 此外,message/rfc822附件不再是base64-encoded,这违反[RFC 2046#section-5.2.1(https://tools.ietf.org/html/rfc2046.html#section-5.2.1),在Evolution和Thunderbird中显示附件时可能出现问题。
- attach_file 使用文件系统中的文件创建附件,使用文件路径进行添加,并且可以为附件选择MIME类型。如果忽略MIME类型,将通过文件名称猜测其类型。最简单的用法为:
message.attach_file('/images/weather_map.png')
Django 1.11中的变化
当text/* 使用二进制时,向MIME类型application/octet-stream添加fallback将无法decode。
发送可替换内容类型
在电子邮件中包含多个版本的内容可能很有用; 经典的例子是同时发送消息的文本格式版本和HTML格式版本。 Django的电子邮件库的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()
默认情况下,EmailMessage正文的MIME类型为“text/plain”。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)
默认情况下,调用get_connection()将返回一个由EMAIL_BACKEND指定的邮件后端实例。如果指定了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时将从相应的设置中获取:
-
host: EMAIL_HOST
-
port: EMAIL_PORT
-
username: EMAIL_HOST_USER
-
password: EMAIL_HOST_PASSWORD
-
use_tls: EMAIL_USE_TLS
-
use_ssl: EMAIL_USE_SSL
-
timeout: EMAIL_TIMEOUT
-
ssl_keyfile: EMAIL_SSL_KEYFILE
-
ssl_certfile: EMAIL_SSL_CERTFILE
SMTP后端是Django的默认配置。 如果要明确指定,请在settings中输入以下内容:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
如果没有指定timeout,它将使用socket.getdefaulttimeout()
提供的值(默认情况下为None,即没有timeout)。
Console后端
console不会真正发送邮件,它只用于实现发送到标准接口的邮件。默认情况下,console后端写到stdout。构造连接时可以通过为其提供stream关键字参数来使用其他的流类对象。
要指定此后端,请在您的settings中输入以下内容:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
这个后端不是用于实际产品-它用于开发过程以便于开发。
File后端
这个后端将邮件写到文件中。此后端将为其打开的每个新会话创建一个新文件。写入文件的目录通过EMAIL_FILE_PATH设置或get_connection()
创建连接时的file_path关键字设置。
要指定此后端,请在您的设置中输入以下内容:
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属性,这是属性是要发送的电子邮件的EmailMassage实例列表。
要指定此后端,请在您的settings中输入以下内容:
EMAIL_BACKEND ='django.core.mail.backends.locmem.EmailBackend'
这个后端不是用于实际产品-只是为了方便开发和测试。
虚拟后端
顾名思义,虚拟后端对您的邮件没有任何作用。 要指定此后端,请在您的settings中输入以下内容:
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
这个后端不是用于实际产品-它用于开发过程以便于开发。
定义自定义邮件后端
我们可以通过自定义邮件后端更改电子邮件的发送方式。我们可以通过将settings文件中的EMAIL_BACKEND设置为自定义邮件后端来告诉python导入该后端。
自定义电子邮件后端应该是django.core.mail.backends.base
模块的BaseEmailBackend
的子类。 自定义电子邮件后端必须实现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_message()在后端打开连接,发送信息列表,并关闭连接。
第二个方法是在邮件后端使用open()
和close()
方法控制连接。如果连接已经存在,send_message()
不会手动打开和关闭连接,因此,如果手动打开连接,可以控制什么时候关闭它。例如:
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()
为开发配置email
有时我们根本不希望Django发送邮件,比如,开发一个网站时我们不希望发出数以千计的邮件,但是却希望验证邮件能否正常发送邮件。
本地开发配置邮件最简单的方法是使用console邮件后端,这个后端将所有邮件重定向到stdout来供开发人员检查邮件内容。
file后端在开发过程中也非常有用,这个后端将每个SMTP连接的内容转储到可以随时检查的文件中。
另一种方法是使用“哑”SMTP服务器,它在本地接收电子邮件并将其显示到终端,但实际上不发送任何内容。 Python有一个内建方法来实现这一命令:
python -m smtpd -n -c DebuggingServer localhost:1025
这个命令将在本地的1025端口开启一个简单的SMTP服务器。这个服务器为输出打印全部邮件标头和邮件主体。这里只需相应设置EMAIL_HOST和EMAIL_PORT。 有关SMTP服务器选项的更详细的讨论,请参阅Python文档的smtpd模块。
有关在应用程序中进行电子邮件发送信息的单元测试,请参阅测试文档的电子邮件服务。
网友评论