简介
本文主要介绍Python标准库email的message和MIME类,并分析了相关的实现,能够是读者更好的使用email模块。
核心类Message
Message类是email的核心类,
它是email对象模型中基类,提供了设置和查询邮件头部,访问消息体的核心方法。从概念上讲,Message对象构成了邮件头部(Headers)和消息体(payloads)。头部格式在RFC 2822中进行了定义,每个头部由该项名字和值组成,并由冒号分割。消息体可以是简单消息对象的字符串或多个MIME容器的Message对象组成的多部分邮件。Message类在email.message模块中定义。
Message基类与MIME类的继承关系如下图所示:
MIMEBase基类
MIMEBase作为MIME相关对象基类继承了Message,拥有拥有Message操作邮件头部和邮件体的所有函数。MIME在邮件头部增加了Content-Type和MIME-Version两个头部信息,从下面MIMEBase的实现中可以清楚的看到这一点:
class MIMEBase(message.Message):
"""Base class for MIME specializations."""
def __init__(self, _maintype, _subtype, **_params):
"""This constructor adds a Content-Type: and a MIME-Version: header.
The Content-Type: header is taken from the _maintype and _subtype
arguments. Additional parameters for this header are taken from the
keyword arguments.
"""
message.Message.__init__(self)
ctype = '%s/%s' % (_maintype, _subtype)
self.add_header('Content-Type', ctype, **_params)
self['MIME-Version'] = '1.0'
多部分邮件类MIMEMultipart类
MIMEMultipart类用于实现多部分邮件的功能,缺省情况下它会创建Content-Type类型为mulitpart/mixed邮件。
class MIMEMultipart(MIMEBase):
"""Base class for MIME multipart/* type messages."""
def __init__(self, _subtype='mixed', boundary=None, _subparts=None,
**_params):
"""Creates a multipart/* type message.
By default, creates a multipart/mixed message, with proper
Content-Type and MIME-Version headers.
_subtype is the subtype of the multipart content type, defaulting to
`mixed'.
boundary is the multipart boundary string. By default it is
calculated as needed.
_subparts is a sequence of initial subparts for the payload. It
must be an iterable object, such as a list. You can always
attach new subparts to the message by using the attach() method.
Additional parameters for the Content-Type header are taken from the
keyword arguments (or passed into the _params argument).
"""
MIMEBase.__init__(self, 'multipart', _subtype, **_params)
# Initialise _payload to an empty list as the Message superclass's
# implementation of is_multipart assumes that _payload is a list for
# multipart messages.
self._payload = []
if _subparts:
for p in _subparts:
self.attach(p)
if boundary:
self.set_boundary(boundary)
在类初始化时,会将_payload初始化为空的列表,因为在Message超类中is_multipart方法假设_payload是一个列表,并用来存放多部分邮件内容,利用attach()方法可以将多部分邮件添加到列表中。这里来看一下超类Message中的相关实现:
class Message:
......
def is_multipart(self):
"""Return True if the message consists of multiple parts."""
return isinstance(self._payload, list)
#
# Payload manipulation.
#
def attach(self, payload):
"""Add the given payload to the current payload.
The current payload will always be a list of objects after this method
is called. If you want to set the payload to a scalar object, use
set_payload() instead.
"""
if self._payload is None:
self._payload = [payload]
else:
self._payload.append(payload)
......
非多部分邮件类MIMENonMultipart类
MIMENonMultipart类与MIMEMultipart类一样,继承自MIMEBase基类,其实现了自定义attach()方法,由于其是非多部分邮件类型实现,用户调用此方法,会抛出MutlipartConversionError异常。class MIMENonMultipart(MIMEBase):
"""Base class for MIME non-multipart type messages."""
def attach(self, payload):
# The public API prohibits attaching multiple subparts to MIMEBase
# derived subtypes since none of them are, by definition, of content
# type multipart/*
raise errors.MultipartConversionError(
'Cannot attach additional subparts to non-multipart/*')
MIMENonMultipart类是其它具体MIMEApplication, MIMEText,MIMEImage等其它类的基类,也就是说它们不运行用户使用attach()方法。它们是通过set_payload()方法来实现设置邮件payload功能的。
class Message:
......
def set_payload(self, payload, charset=None):
"""Set the payload to the given value.
Optional charset sets the message's default character set. See
set_charset() for details.
"""
self._payload = payload
if charset is not None:
self.set_charset(charset)
......
具体类实现
MIME模块提供了5个MIME具体类,各个具体类都提供了与名称对应的主消息类型的对象的支持,它们都继承了MIMENonMultipart类;关于MIME主类型的知识,可以参考 Python网络编程:E-mail服务(三)MIME详解。这里简单看一下MIMEText的实现:class MIMEText(MIMENonMultipart):
"""Class for generating text/* type MIME documents."""
def __init__(self, _text, _subtype='plain', _charset='us-ascii'):
"""Create a text/* type MIME document.
_text is the string for this message object.
_subtype is the MIME sub content type, defaulting to "plain".
_charset is the character set parameter added to the Content-Type
header. This defaults to "us-ascii". Note that as a side-effect, the
Content-Transfer-Encoding header will also be set.
"""
MIMENonMultipart.__init__(self, 'text', _subtype,
**{'charset': _charset})
self.set_payload(_text, _charset)
MIMEText在初始化时,将主类型设置为text类型,并通过set_payload()函数设置邮件体内容。
总结
结合E-mail的核心类Message和MIME相关类的实现,可以更深入的了解通过email标准库编写邮件的机制,高效的实现编写邮件相关的代码。