在Python中内置了smtplib
邮件发送模块,Django在此基础上进行了简单地封装,让我们在Django环境中可以更方便更灵活的发送邮件。
所有的功能都在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, )
导入功能模块,然后发送邮件,so easy!
默认情况下,使用配置文件中的EMAIL_HOST
和EMAIL_PORT
设置SMTP服务器主机和端口,EMAIL_HOST_USER
和EMAIL_HOST_PASSWORD
是用户名和密码。如果设置了EMAIL_USE_TLS
和EMAIL_USE_SSL
,它们将控制是否使用相应的加密链接。
配置参考:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.sina.com' EMAIL_PORT = 25 EMAIL_HOST_USER = 'xxx@sina.com' EMAIL_HOST_PASSWORD = 'xxxxxxxxxxx'
send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)
大多数情况下,我们使用send_mail()
方法足矣,它接收一系列参数,其中的subject
、message
、from_email
和recipient_list
参数是必须的,其它的可选。
subject
:邮件主题。字符串。message
:邮件具体内容。字符串。from_email
:邮件发送者。字符串。recipient_list
:收件人。一个由邮箱地址组成的字符串列表。recipient_list
中的每一个成员都会在邮件信息的“To:”区域看到其它成员。fail_silently
: 一个布尔值。默认值为False,表示send_mail
发送失败时,将会引发一个smtplib.SMTPException
异常。auth_user
: 可选的用户名用来验证SMTP服务器,如果你要特别指定使用哪个邮箱帐号,就指定这个参数。如果没有提供这个值,Django将会使用settings中EMAIL_HOST_USER
的值。如果两者都不提供,那你还发什么???auth_password
: 可选的密码用来验证SMTP服务器。如果没有提供这个值,Django 将会使用settings中EMAIL_HOST_PASSWORD
的值。和上面那个参数是一家的。connection
: 可选的用来发送邮件的电子邮件后端。html_message
: 如果提供了html_message
,可以发送带HTML代码的多媒体邮件。send_mail()
方法的返回值是成功发送的邮件数量(只会是0或1,因为它只能发送一封邮件)。
示例:
send_mail( 'Subject', 'Message.', 'from@example.com', ['john@example.com', 'jane@example.com'], )
send_mass_mail(datantuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)
send_mass_mail()
用来处理批量邮件的发送任务,也就是所谓的群发。
它的参数中,datatuple是必需参数,接收一个二维元组,二维元组的每个元素也是一个元组,并且格式如下:
(subject, message, from_email, recipient_list)
所有参数的意义与send_mail()
中的相同。
例如,以下代码将向两组不同的收件人发送两封不同的邮件,但复用了同一条连接:
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()
的返回值是成功发送的邮件数量。
使用send_mail()
方法时,每调用一次,它会和SMTP服务器建立一次连接,也就是发一次连一次,效率很低。而send_mass_mail()
,则只建立一次连接,就将所有的邮件都发送出去,效率比较高。
mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)
向定义在ADMINS
配置项中的网站管理员快速发送邮件。
它会在邮件主题前面添加 EMAIL_SUBJECT_PREFIX
配置项指定的前缀,默认是[Django]
。
邮件的 发件人由 SERVER_EMAIL
配置项指定。
这个方法主要是为了方便快捷和突出邮件主题更醒目。
mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)
类似 mail_admins()
,不同的是,它是向 MANAGERS
配置项指定的管理员们发送邮件。
有时候,我们要根据用户表单的输入来构造电子邮件,这就存在头部注入攻击的风险,Django给我们提供了一定的防范能力,但是更多时候,还需要你自己编写安全防范代码。
下面是一个例子,接收用户输入的主题、邮件内容和发送方,将邮件发送到系统管理员:
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.")
如果检查到用户的输入带有头部注入攻击的可能性,会弹出BadHeaderError异常。
Django 的 send_mail()
和 send_mass_mail()
函数其实是对 EmailMessage
类的简单封装利用。
如果你想用进阶功能,比如密送收件人,附件,分段邮件,需要直接创建 EmailMessage
的实例。
EmailMessage
负责构造邮件,邮件后端负责发送邮件。
EmailMessage
类通过以下参数构造邮件(可选参数要按指定顺序提供)。所有的参数都是可选的,且可在调用 send()
方法前设置。
subject
: 邮件的主题。body
: 邮件内容,需要为纯文本格式。from_email
: 发件人地址。 fred@example.com
和 Fred
形式都是合法的。若省略,则使用 DEFAULT_FROM_EMAIL
配置的值。to
: 一个包含收件人地址的列表或元组。bcc
: 一个包含地址的列表或元组,指定“密送”对象。connection
: 一个邮件后端的实例。若在发送多份邮件时,若想复用连接,则设置此参数。如果省略,在调用 send()
时总会创建新连接。attachments
: 附加在邮件中的附件列表。 可以是 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"}, )
EmailMessage
类拥有以下方法:
send(fail_silently=False)
发送邮件。若在构建邮件时指定了连接,则会使用这个连接。否则,会实例化并使用一个默认的后端。若指定关键字参数 fail_silently
为 True
,发送邮件时抛出的异常会被和谐掉。一个空的收件人列表不会抛出异常。
message()
构建了一个 django.core.mail.SafeMIMEText
对象( MIMEText
的子类)或一个 django.core.mail.SafeMIMEMultipart
对象用于存储邮件内容。如果你继承了 EmailMessage
,你可能需要重写这个方法,在 MIME 对象中放入你期望的内容。
recipients()
返回一个包含邮件所有收件人的列表,不管他们是收件人,抄送人,密送人中的哪一个。这可能是另一个你在创建子类时想重写的方法,因为 SMTP 服务器需要你在发送邮件时告诉它完整的收件人列表。如果你在子类中实现了另一个方法,指定收件人列表,这个方法必须也返回相同的结果。
attach()
创建一个新的附件,并加到邮件。有两种调用 attach()
的方式:
可以仅传送一个 MIMEBase
的实例。这会被直接插入邮件。
可以向 attach()
传递 3 个参数: filename
, content
和 mimetype
。 filename
是文件附件的名字,它会显示在邮件中, content
是附件包含的数据,而 mimetype
是一个可选参数,指定附件的 MIME 类型。如果你省略了 mimetype
,MIME 类型将会参考附件的文件名。
例如:
message.attach('design.png', img_data, 'image/png')
对于以 text/
开头的 mimetype
类型,其内容应该是字符串。二进制数据则将尝试以 UTF-8 解码,如果失败了,MIME 类型会被改为application/octet-stream
,并不会修改数据内容。
attach_file()
通过从本地文件系统中选择一个文件的方式创建附件。调用时,传入文件的路径。附件的 MIME 类型是可选的。如果省略了 MIME 类型,会参考文件名。比如:
python
message.attach_file('/images/weather_map.png')
默认情况下,发送的邮件都是纯文本格式的。但有时候我们希望能在邮件里带一些超级链接、图片,甚至视频和JS动作。
Django为我们提供了一个EmailMultiAlternatives
类,可以同时发送文本和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()
发送邮件的动作是由邮件后端执行的。
邮件后端类拥有以下方法:
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
参数,将会返回指定后端的实例。
fail_silently
控制后端怎么处理错误。若 fail_silently
为 True,发送邮件过程中的异常都会被和谐掉。
剩余的参数将直接传给邮件后端的构造器。
Django 自带了几种邮件后端。除了 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
,则会从settings.py
中相应设置项中读取:
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
控制台后端仅将邮件发送至标准输出,而不是真的发送。默认情况下,控制台后端输出至 stdout
。在创建连接时,你可以提供 stream
关键字参数来使用另一个类似 stream 的对象。
要使用该后端,请如下配置:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
该后端不是为了在生产环境使用的,只是方便你在开发阶段测试使用。
文件后端将邮件写入文件。
存储这些文件的目录可以使用配置项 EMAIL_FILE_PATH
指定,也可在调用 get_connection()
时以关键字参数 file_path
指定。
要使用该后端,将以下代码加入你的配置中:
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' EMAIL_FILE_PATH = '/tmp/app-messages' # 文件的存储路径
该后端不是为了在生产环境使用的,只是方便你在开发阶段测试使用。
该缓存式后端将内容存在 django.core.mail
模块的某个属性值中。
要使用该后端,将以下代码加入你的配置中:
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
该后端不是为了在生产环境使用的,只是方便你在开发阶段测试使用。
Django 的测试器自动为测试使用这个后端。
就像该后端的名字表示的一样,该后端对你发送的消息什么也不做。
要使用该后端,将以下代码加入你的配置中:
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
该后端不是为了在生产环境使用的,只是方便你在开发阶段测试使用。
在开发和测试过程中,大多数情况下你并不想 Django 真的发送邮件。举个例子,在开发网站时,你可能并不期望发送成千上万封邮件——但你想要确保这些邮件会在正确的时间,包含正确的内容,发送给正确的人。
最简单的方式就是使用控制台后端。这个后端将所有的邮件重定向至标准输出,允许你观察邮件的内容。
文件后端在开发时也很有用——这个后端会将SMTP 连接的内容输出至一个文件,你可以在你闲暇时查看这个文件。
另一个方法是使用一个“哑巴” SMTP 服务器,它从本地接收邮件,并输出至终端,并不会真的发送什么。Python 有一个aiosmtpd
库可以实现这一功能:
python -m pip install aiosmtpd python -m aiosmtpd -n -l localhost:8025
该命令会在本机启动一个极小的 SMTP 服务器,监听 8025 端口。这个服务器会在标准输出打印所有的邮件头和邮件内容。
创建和关闭 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_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()
EMAIL_HOST_PASSWORD不是密码,而是qq邮箱的授权码
密码只是为了能通俗易懂而已,不需要追究字眼上的问题,还有请你委婉的讲出来好?注重以下他人的成果
os.environ['DJANGO_SETTINGS_MODULE']='mydjsite.setttings'和 django.setup()已配置过,但是还是出现报错:django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.这个怎么处理?
最有可能的是没有正确配置。 先参考http://www.liujiangblog.com/course/django/113 确保能跟着成功做一遍。
我发现是因为import导入了无关的模块而导致错误!按道理如果导入了多余的模块,应该没啥影响。看来若没有删掉或注释掉多余的模块很可能会导致意想不到的错误!
http://www.liujiangblog.com/course/django/163