maintype = part.get_content_maintype()
if maintype == 'multipart': # multipart/: container
continue
elif fulltype == 'message/rfc822': # 4E: skip message/rfc822
continue # skip all message/ too?
else:
filename, contype = self.partName(part, ix)
yield (filename, contype, part)
def partName(self, part, ix):
"""
extract filename and content type from message part;
filename: tries Content-Disposition, then Content-Type
name param, or generates one based on mimetype guess;
"""
filename = part.get_filename() # filename in msg hdrs?
contype = part.get_content_type() # lowercase maintype/subtype
if not filename:
filename = part.get_param('name') # try content-type name
if not filename:
if contype == 'text/plain': # hardcode plain text ext
ext = '.txt' # else guesses .ksh!
else:
ext = mimetypes.guess_extension(contype)
if not ext: ext = '.bin' # use a generic default
filename = 'part-%03d%s' % (ix, ext)
return (filename, contype)
def saveParts(self, savedir, message):
"""
store all parts of a message as files in a local directory;
returns [('maintype/subtype', 'filename')] list for use by
callers, but does not open any parts or attachments here;
get_payload decodes base64, quoted-printable, uuencoded data;
mail parser may give us a None payload for oddball types we
probably should skip over: convert to str here to be safe;
"""
if not os.path.exists(savedir):
os.mkdir(savedir)
partfiles = []
for (filename, contype, part) in self.walkNamedParts(message):
fullname = os.path.join(savedir, filename)
fileobj = open(fullname, 'wb') # use binary mode
content = part.get_payload(decode=1) # decode base64,qp,uu
if not isinstance(content, bytes): # 4E: need bytes for rb
content = b'(no content)' # decode=1 returns bytes,
fileobj.write(content) # but some payloads None
fileobj.close() # 4E: not str(content)
partfiles.append((contype, fullname)) # for caller to open
return partfiles
def saveOnePart(self, savedir, partname, message):
"""
ditto, but find and save just one part by name
"""
978 | Chapter 13: Client-Side Scripting