1. The purpose of writing this blog
The main record is how to achieve this function through django : send a single email that satisfies [the value of the email body is an html page + multiple attachments];
To send a single email that satisfies [the value of the email body is an html page + multiple attachments], you can use the class EmailMultiAlternative ;
The EmailMultiAlternative class provides three methods: attach_file() , attach_alternative() , send() . The main functions of these three methods are:
- The main function of attach_file(): treat a specified file as an email attachment;
- The main function of attach_alternative(): make the body of the email a specified html page;
- The main function of send(): execute the action of sending mail;
The complete operation process can be seen in the following content;
Second, the complete operation process
1. The first step: add mailbox configuration information in [ settings.py ]
# 配置qq邮箱信息
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 值必须为这个
EMAIL_USE_SSL = True # SSL加密方式,值必须为True
EMAIL_HOST = 'smtp.qq.com' # 发送邮件的qq邮箱的SMTP服务器
EMAIL_PORT = 465 # QQ邮箱对应的SMTP服务器端口
EMAIL_HOST_USER = '[email protected]' # 发件人
EMAIL_HOST_PASSWORD = 'xolnfbqgdybxji11' # qq授权码(不能使用qq密码只能使用qq授权码)
EMAIL_FROM = 'Rainbow<[email protected]>' # 邮件显示的发件人
2. Step 2: Add a view function in [ helloworld/hello/views.py ]
3. Step 3 : Add url matching rules in [ helloworld/helloworld/urls.py ]
url(r"^send_email_004/$",views.send_email_004),
4. Step 4 : Restart the service
5. Step 5 : Enter the url address [ http://0.0.0.0:8000/send_email_004/ ] on any browser and check the result after accessing
3. Related knowledge points
1. Simple analysis of the source code of the method [ __init__ ] in the EmailMultiAlternatives class
class EmailMultiAlternatives(EmailMessage):
"""
A version of EmailMessage that makes it easy to send multipart/alternative
messages. For example, including text and HTML versions of the text is
made easier.
"""
alternative_subtype = 'alternative'
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
connection=None, attachments=None, headers=None, alternatives=None,
cc=None, reply_to=None):
"""
Initialize a single email message (which can be sent to multiple
recipients).
"""
super().__init__(
subject, body, from_email, to, bcc, connection, attachments,
headers, cc, reply_to,
)
self.alternatives = alternatives or []
Analysis of several main input parameters in the method [ __init__ ]:
- subject: (required, the data type is a string) the subject of the email;
- body: (required, the data type is a string) the body of the email;
- from_email: (not required, the data type is a string) sending email;
- to: (not required, the data type is a list) Each value in the list is an email address for receiving mail;
2. Simple analysis of the source code of the method [ attach_file ] in the class EmailMultiAlternatives
def attach_file(self, path, mimetype=None):
"""
Attach a file from the filesystem.
Set the mimetype to DEFAULT_ATTACHMENT_MIME_TYPE if it isn't specified
and cannot be guessed.
For a text/* mimetype (guessed or specified), decode the file's content
as UTF-8. If that fails, set the mimetype to
DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content.
"""
path = Path(path)
with path.open('rb') as file:
content = file.read()
self.attach(path.name, content, mimetype)
It can be roughly seen from the source code of the method [ attach_file ] that, in fact, the method [ attach_file ] is a further encapsulation of the method [ attach ];
3. Simple analysis of the source code of the method [ attach ] in the class EmailMultiAlternatives
def attach(self, filename=None, content=None, mimetype=None):
"""
Attach a file with the given filename and content. The filename can
be omitted and the mimetype is guessed, if not provided.
If the first parameter is a MIMEBase subclass, insert it directly
into the resulting message attachments.
For a text/* mimetype (guessed or specified), when a bytes object is
specified as content, decode it as UTF-8. If that fails, set the
mimetype to DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content.
"""
if isinstance(filename, MIMEBase):
assert content is None
assert mimetype is None
self.attachments.append(filename)
else:
assert content is not None
mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1)
if basetype == 'text':
if isinstance(content, bytes):
try:
content = content.decode()
except UnicodeDecodeError:
# If mimetype suggests the file is text but it's
# actually binary, read() raises a UnicodeDecodeError.
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
self.attachments.append((filename, content, mimetype))
Intercept this part of the source code:
mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1)
It can be easily seen from this part of the source code: when the input parameter mimetype value is None , django will automatically infer the value of the MIME content type according to the attachment file name and assign it to the input parameter mimetype , and then enter the new value of the parameter mimetype for subsequent related processing;
4. The resource storage location of each application
What are resources? For example: a picture, an html page, a css , a js , a video, a pdf , a word , a txt , etc. These are all different resource types;
Each project application has a corresponding resource, so how to determine the resource storage location of each application? How to decide the idea, personal approach is mainly this idea step:
- The first step: The resource storage location of each application is set to a manually added folder under the root directory of each application, for example, the new folder is named [public];
- Step 2: Add different folders corresponding to different resource types in the folder [public], for example, the new folders are named [css] and [word];
- Step 3: Add different folders corresponding to different data tables/different business modules in the folder [word], for example, the new folders are named [user] and [test];
The main purpose of this thinking step is: the resources of each application are maintained in their respective application directories, which greatly reduces the coupling of project codes and facilitates subsequent maintenance;
Taking an application [ hello ] as an example, the specific file hierarchy corresponding to the resource storage location of the application [ hello ] is roughly as follows: