您的位置:首页 > 理论基础 > 计算机网络

Python网络编程:E-mail服务(四) 编写传统邮件

2015-04-25 18:36 399 查看

简介

本文通过标准Python库的email模块提供MIMEText类,进行传统email的编写,从而对email模块有一个初步的认识。

邮件编写

RFC 822定义了邮件的标准格式,在前面的文章对此也进行了相关介绍,这里我们通过MIMEText类,来编写一个传统邮件。
'''
Created on Apr 18, 2015

@author: jliu
'''

from email.Utils import formatdate, make_msgid
from email.mime.text import MIMEText

if __name__ == '__main__':
    message = '''Hello,\n   this is an autotest email.\n---Jinguang Liu.\n'''
    
    msg = MIMEText(message)
    msg['To'] = 'jinguang.liu@qq.com'
    msg['From'] = 'jliu@163.com'
    msg['Subject'] = 'This is a test email'
    msg['Date'] = formatdate(localtime=1)
    msg['Message-ID'] = make_msgid() 
    
    print msg.as_string()
查看一下程序运行的结果:
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
To: jinguang.liu@qq.com
From: jliu@163.com
Subject: This is a test email
Date: Sat, 25 Apr 2015 17:50:12 +0800
Message-ID: <20150425095012.3420.48931@bob-PC>

Hello,
this is an autotest email.
---Jinguang Liu.

代码解析

MIMEText类是用来创建文本类型的MIME对象,其类的实现如下:
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继承MIMENonMultipart类,实现单非多部分邮件的编写。_text参数是作为负载的字符串,_subtype是子类型,缺省设置为plain类型的纯文本文件。_charset是字符编码。除非显示的讲_charset设置为None, 否则MIMEText对象会创建Content-Type和Content-Transfer-Encoding的头部。从上面的运行结果中可以看出这点。
添加头部非常简单,按照msg['To'] = 'jinguang.liu@qq.com'格式很容易的就可以添加。这部分的工作是在基类Message中实现的,通过list类模拟字典功能,下面列出了源码中的相关实现:
class Message:
"""Basic message object.

A message object is defined as something that has a bunch of RFC 2822
headers and a payload.  It may optionally have an envelope header
(a.k.a. Unix-From or From_ header).  If the message is a container (i.e. a
multipart or a message/rfc822), then the payload is a list of Message
objects, otherwise it is a string.

Message objects implement part of the `mapping' interface, which assumes
there is exactly one occurrence of the header per message.  Some headers
do in fact appear multiple times (e.g. Received) and for those headers,
you must use the explicit API to set or get all the headers.  Not all of
the mapping methods are implemented.
"""
def __init__(self):
self._headers = []
self._unixfrom = None
self._payload = None
self._charset = None
# Defaults for multipart messages
self.preamble = self.epilogue = None
self.defects = []
# Default content type
self._default_type = 'text/plain'

#
# MAPPING INTERFACE (partial)
#
def __len__(self):
"""Return the total number of headers, including duplicates."""
return len(self._headers)

def __getitem__(self, name):
"""Get a header value.

Return None if the header is missing instead of raising an exception.

Note that if the header appeared multiple times, exactly which
occurrence gets returned is undefined.  Use get_all() to get all
the values matching a header field name.
"""
return self.get(name)

def __setitem__(self, name, val):
"""Set the value of a header.

Note: this does not overwrite an existing header with the same field
name.  Use __delitem__() first to delete any existing headers.
"""
self._headers.append((name, val))

def __delitem__(self, name):
"""Delete all occurrences of a header, if present.

Does not raise an exception if the header is missing.
"""
name = name.lower()
newheaders = []
for k, v in self._headers:
if k.lower() != name:
newheaders.append((k, v))
self._headers = newheaders

def __contains__(self, name):
return name.lower() in [k.lower() for k, v in self._headers]

def has_key(self, name):
"""Return true if the message contains the header."""
missing = object()
return self.get(name, missing) is not missing

def keys(self):
"""Return a list of all the message's header field names.

These will be sorted in the order they appeared in the original
message, or were added to the message, and may contain duplicates.
Any fields deleted and re-inserted are always appended to the header
list.
"""
return [k for k, v in self._headers]

def values(self):
"""Return a list of all the message's header values.

These will be sorted in the order they appeared in the original
message, or were added to the message, and may contain duplicates.
Any fields deleted and re-inserted are always appended to the header
list.
"""
return [v for k, v in self._headers]

def items(self):
"""Get all the message's header fields and values.

These will be sorted in the order they appeared in the original
message, or were added to the message, and may contain duplicates.
Any fields deleted and re-inserted are always appended to the header
list.
"""
return self._headers[:]

def get(self, name, failobj=None):
"""Get a header value.

Like __getitem__() but return failobj instead of None when the field
is missing.
"""
name = name.lower()
for k, v in self._headers:
if k.lower() == name:
return v
return failobj

在这个传统邮件编写的例子中,还使用了email.utils提供了两个方法来增加Date和Message-ID两个头部:

formatdate([timeval[, localtime][, usegmt]]) :返回RFC 28822(替代RFC 822)定义的日期字符串,格式:Fri, 09 Nov 2001 01:08:47 -0000

make_msgid([idstring]):返回与RFC 2822兼容的Message-ID字符串

最后,通过as_string()方法,可以获取邮件的字符串。

总结

通过email模块的MIMEText类来实现传统邮件的编写,并介绍了email相关类、接口的实现和使用。通过本文的介绍,读者应该比较容易的写出纯文本格式的邮件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: