转自:https://django-chinese-docs-14.readthedocs.org/en/latest/topics/email.html#django.core.mail.send_mail
尽管Python已经提供了相对易用的邮件发送模块 smtplib ,但Django仍对其做了轻度的封装。封装后的模块不仅发送邮件速度快,而且在开发环境下也很容易对邮件发送进行测试, 并对无法使用SMTP的平台也提供了支持。
封装代码在 django.core.mail 模块中。
只有两行:
Django发邮件功能要用到配置文件中的 EMAIL_HOST 和 EMAIL_PORT 配置项,分别用来指定发邮件服务器和端口。 如果SMTP服务器需要用户认证,还须设置 EMAIL_HOST_USER 和 EMAIL_HOST_PASSWORD 配置项,指定用户名和密码。 而 EMAIL_USE_TLS 配置项则决定是否使用安全加密链接。
Note
由 django.core.mail 发送的邮件,其字符集都由 DEFAULT_CHARSET 配置项决定。
发邮件的最便捷方式就是使用 django.core.mail.send_mail() 。
subject, message, from_email and recipient_list 这四个参数是必须的。
django.core.mail.send_mass_mail() 适合处理群发邮件。
datatuple 是一个元组,其中每个元素格式如下:
fail_silently, auth_user 和 auth_password 与上面 send_mail() 中提到的一样。
datatuple 中每个元素都对应一封单独的邮件。与上面 send_mail() 一样,出现在 recipient_list 中的收件人同样会在 “收件人/To:” 字段中看到该邮件的其他所有收件人。
举个例子,下面的代码会给双组不同的收件人发送两封不同的邮件;但仅仅打开一次邮件服务器的链接:
send_mass_mail() 和 send_mail() 的区别在于: send_mail() 每发送一封邮件就会打开一次邮件服务器链接,而send_mass_mail() 则是打开一次链接,发送所有的邮件。 send_mass_mail() 明显更高效。
django.core.mail.mail_admins() 是一个给网站后台管理员(admin)发邮件的快捷方法,管理员设置放在 ADMINS配置项。
mail_admins() 使用 EMAIL_SUBJECT_PREFIX 配置项的值做为邮件标题的前缀,默认情况下是 "[Django] " 。
邮件的”From:”头的内容就是 SERVER_EMAIL 配置项的值。
该方法方便使用且易于理解。
如果提供了 html_message 参数,会导致邮件变成 multipart/alternative , message 格式变成 text/plain ,html_message 格式变成 text/html 。
django.core.mail.mail_managers() is just like mail_admins() ,不同之处在于该方法的邮件接收人是网站负责人(manager), 可以在 MANAGERS 配置项设置网站负责人。
该例同时给 [email protected] 和 [email protected] 发送同一封邮件,这两个邮箱地址都会出现在 “收件人/To:” 一栏:
该例则是分别为 [email protected] 和 [email protected] 分别发送同一封邮件,每人收到的邮件只显示唯一一个收件人:
Header injection (邮件头信息注入)是可以被骇客(黑客hacker是指伟大的程序员,骇客Cracker和Attacker是指无知无耻的狗盗之辈)利用的安全漏洞。 他们会利用该漏洞,在代码生成的邮件报文中添加额外的邮件头信息(header)以控制 “收件人/To:” 和 “发件人/From:” 。
之前所提及的Django邮件函式都禁止在头信息中添加换行,从而避免注入。只要 subject , from_email 和recipient_list 包含换行(不管是Windows格式,还是Unix或是Mac OS 格式) ,发送函式 (比如 send_mail()) 都会抛出 django.core.mail.BadHeaderError 异常( ValueError 的一个子类),也不会发送该邮件。 因此在给邮件函式传递参数之前,一定要对所有数据进行验证。
如果 message 在文本最开始处含有头信息,那么这些头信息就会被打印成邮件内容的第一个比特。
下面这个view例子, subject , message 和 from_email 从request POST中取值,然后发送邮件到[email protected], 发送成功后重定向到”/contact/thanks/”:
Django的 send_mail() 和 send_mass_mail() 函式事实上是对 EmailMessage 类使用方式 的一个轻度封装。
send_mail() 和相关的其他封装函式并没有充分使用 EmailMessage 类的所有特性。 要想使用更多特性,比如暗送(BCC)给收件人,加入附件,或是多用途格式(multi-part)邮件,都要直接创建 EmailMessage 实例。
Note
这是一个设计特性: send_mail() 和其他相关函式是最初只是由Django提供的一组接口。 但是其接收的参数数量却随着Django的发展而慢慢增长。这样就能理解为什么要将邮件报文使用面向对象设计重新设计,同时又保留原有函式以保证后端兼容,
EmailMessage 仅仅负责创建邮件报文,而 email backend 则负责邮件发送。
为了方便起见, EmailMessage 提供了一个简单的 send() 方法用以发送纯文本邮件。如果想发送多用途格式邮件,可以使用后端API 发送多用途邮件.
EmailMessage 类使用下列参数初始化(除非使用位置参数,否则默认顺序如下)。所有参数均可选,均可在调用send() 方法之前的任何时间对其赋值。
例如:
该类方法如下:
send(fail_silently=False) 发送邮件报文。如果在构造邮件时如果指定了某个链接(connection),就会使用该链接发邮件。 否则,就会使用默认后端的实例发邮件。如果关键字参数 fail_silently 为 True ,就会忽略邮件发送时抛出的异常。
message() 构造了一个 django.core.mail.SafeMIMEText 对象 (Python的 email.MIMEText.MIMEText 类的子类) 或是 django.core.mail.SafeMIMEMultipart 对象(该对象保存即将发送出去邮件报文)。如需扩展EmailMessage 类,一般情况下要覆写该方法,将你所需的内容添加到MIME对象中。
recipients() 返回邮件中所有收件人的列表,不管收件人是在 to 还是 bcc 属性中。这是另一个经常被继承覆写的方法, 因为SMTP服务器在发送邮件报文时,要接收完整的收件人列表。即使你自己的类使用其他方式来指定收件人,也仍然需要使用该方法返回收件人列表。
attach() 创建一个新的文件附件,并把它添加到邮件报文中。 有两种方法调用 attach():
传递一个单独的 email.MIMEBase.MIMEBase 实例做为参数。该实例会直接添加到最终的邮件报文中。
或者,给 attach() 传递三个参数: filename, content 和 mimetype. filename 是出现在邮件中的附件文件的名称, content 是附件的内容,而 mimetype 是附件所使用的MIME类型。 如果忽略 mimetype, Django会自动根据附件文件名来推测MIME内容类型。
例如:
attach_file() 使用当前文件系统下的某个文件做为附件。调用时,传入某个文件的完整路径,以及该附件的MIME类型(可选的)。 忽略MIME类型的话,Django会自动根据附件文件名来推测MIME类型。最简单的用法如下:
在同一封邮件中包含多种版本的内容是非常有用的;典型的例子就是发送既有纯文本版本内容又有HTML版本内容的邮件。 在Django的邮件库中,可以使用 EmailMultiAlternatives 类来达到该目的。 EmailMessage 的子类有一个attach_alternative() 方法用来包含其他版本的邮件主体内容。所有其他方法(包括类的初始化方法)都直接继承自EmailMessage 。
发送一封文本/HTML混合邮件,代码如下:
默认情况下,:class:~django.core.mail.EmailMessage 类中的 body 参数的MIME类型是 "text/plain" 。 大多数情况下,没必要更改该MIME,因为这样能保证每个收件人能够阅读该邮件,而不论他们使用的是什么邮件客户端。 不过,在能确保收件人能处理多用途邮件的情况下,可以使用:class:~django.core.mail.EmailMessage 类的 content_subtype属性 来更改邮件内容类型。主类型总是 "text" ,子类型可以设置为别的版本(比如html),例如:
实际上发送邮件的工作是由邮件发送后端处理的。
邮件后端类有下列方法:
django.core.mail 的 get_connection() 函式返回你当前使用的邮件后端的实例。
默认情况下,对 get_connection() 的调用会返回一个邮件后端实例,具体是哪个后端由 EMAIL_BACKEND 配置项决定。 如果指定了``backend`` 参数,就会对该后端进行实例化。
fail_silently 参数决定后端如何处理错误。 如果 fail_silently 为 True ,发送邮件进程引发的异常将会被忽略。
其他的所有参数都会被直接传递给邮件后端的构造函式
Django提供了几种不同的邮件发送后端。除了SMTP backend之外(也是默认的邮件发送后端), 其他后端仅适用于测试和开发过程。如果有特珠的邮件发送要求,可以 编写自己的邮件发送后端.
SMTP后端,这也是默认的后端(backend)。邮件会通过SMTP服务器进行发送。服务器地址和认证凭证都由配置文件中的EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD 和 EMAIL_USE_TLS 配置项来指定。
SMTP后端是Django默认的配置。若想明确指定,可配置文件中进行如下配置:
SMTPConnection 对象
在Django1.2以前,Django提供了一个 SMTPConnection 类。该类提供了一套直接控制SMTP用以发送邮件的方式。 该类已经被弃用了,Django转而使用更通用的邮件后端API。
出于向上兼容性的考虑, SMTPConnection 仍然保留在 django.core.mail 中,做为SMTP backend的别名。 新代码应该使用 get_connection() 以代替。
控制台后端。控制台后端并不会发送真实的邮件,而是仅仅将邮件内容发送到标准输出。默认情况下, 控制台后端会写到 stdout 。可以在构造链接时提供 stream 关键字参数以使用不同的类流(stream-like)对象
要指定该后端,只要在配置文件中设置:
该后端并不建议在生产环境下使用–它仅仅是为开发提供方便。
文件后端。文件后端将邮件写到一个文件中,在该后端中,每打开一个新session,就会创建一个新文件。文件存放在哪个目录下是由 EMAIL_FILE_PATH 配置项或是在使用 get_connection() 创建链接(connection)时由 file_path 关键字决定。
要指定该后端,只要在配置文件中设置:
该后端并不建议在生产环境下使用–它仅仅是为开发提供方便。
内存后端。 'locmem' 后端将邮件报文保存到 django.core.mail 模块的一个特定属性 outbox 中。发送第一封邮件时, outbox 属性就会被创建。 该属性是一个列表,每个 EmailMessage 实例的邮件报文都会添加到该列表中。
要指定该后端,只要在配置文件中设置:
该后端并不建议在生产环境下使用–它仅仅是为开发和测试提供方便。
空后端。如名所示,该后端不会做任何事情。要指定该后端,只要在配置文件中设置:
该后端并不建议在生产环境下使用–它仅仅是为开发提供方便。
如果要改变邮件的发送方式,可以自己写一个邮件发送后端。 将 EMAIL_BACKEND 配置项设为自定义后端的python引用路径。
自定义邮件后端应该继承 BaseEmailBackend ,该类位于 django.core.mail.backends.base 模块。 自定义邮件后端必须实现 send_messages(email_messages) 方法。该方法接收一个列表,列表元素是 EmailMessage 实例,并返回一组发送成功的消息。 如果自定义后端还涉及持久化session或connection,还应该实现 open() 和 close() 方法。smtp.EmailBackend 可以做为一个现成的参考。
建立和关闭一个SMTP链接(connection)是一个代价高昂的过程(对于这种情况,任何网络链接都是如此)。 因此要想发送更多邮件,重用SMTP链接就显得很有意义;而不是每次发送一封邮件,都要创建和销毁一个链接。
有两种方式可以重用链接。
第一种方式,可以使用 send_messages() 方法。 send_messages() 接收一个 EmailMessage (或是子类)实例的列表, 然后用单独一个链接来发送列表中的内容。
例如,你有一个名为 get_notification_email() 的函式,用以定时发送邮件,它返回一个 EmailMessage 对象的列表。 调用一次 send_messages 就可以发送完这些邮件:
在这个例子中,调用 send_messages() 会在后端打开一个链接(connection),发送列表中的邮件报文,然后再关闭链接。
第二种方式是在邮件后端使用 open() 和 close() 方法手动控制链接。 在已经打开链接的情况下, send_messages()不会自动打开和关闭链接。因此在该情况下,要手动决定何时关闭链接。 举个例子:
有几种情况下,我们并不想让Django发送邮件。比如:开发网站时,一般不想发送数以千计的邮件,但又想验证一下在正确环境下邮件是否会发送给目标人群, 以及这些邮件内容是否正确。
测试发送邮件的最简单方式就是使用 console 邮件发送后端。它直接将所有邮件输出到stdout,从而可以检查邮件内容是否正确。
file 后端在开发过程中也非常有用–它将每封邮件的内容都写到一个指定的文件中,从而方便检查。
还有一种方式是使用 “dumb” SMTP 服务器,它在本地接收所有邮件,并在终端显示出邮件,但事实上不能发送任何邮件。 Python有一个内置的方式可以实现该服务,只须一条命令行:
该命令会启动一个简单的SMTP服务器,用以监听本地的1025端口。该服务器简单的将所有邮件的头信息和邮件主体打印到标准输出。 然后只须更改 EMAIL_HOST 和 EMAIL_PORT 即可。
更多关于本地测试和处理邮件的细节资料,请查看Python文档 smtpd 模块。
SMTPConnection 类已弃用,转而使用通用邮件后端(backend)API。
出于向上兼容性的考虑, SMTPConnection 仍然保留在 django.core.mail 中,且做为 SMTP backend. 的别名。新代码应该使用 get_connection() 取代。