0001 """Generic MIME writer. 0002 0003 This module defines the class MimeWriter. The MimeWriter class implements 0004 a basic formatter for creating MIME multi-part files. It doesn't seek around 0005 the output file nor does it use large amounts of buffer space. You must write 0006 the parts out in the order that they should occur in the final file. 0007 MimeWriter does buffer the headers you add, allowing you to rearrange their 0008 order. 0009 0010 """ 0011 0012 0013 import mimetools 0014 0015 __all__ = ["MimeWriter"] 0016 0017 class MimeWriter: 0018 0019 """Generic MIME writer. 0020 0021 Methods: 0022 0023 __init__() 0024 addheader() 0025 flushheaders() 0026 startbody() 0027 startmultipartbody() 0028 nextpart() 0029 lastpart() 0030 0031 A MIME writer is much more primitive than a MIME parser. It 0032 doesn't seek around on the output file, and it doesn't use large 0033 amounts of buffer space, so you have to write the parts in the 0034 order they should occur on the output file. It does buffer the 0035 headers you add, allowing you to rearrange their order. 0036 0037 General usage is: 0038 0039 f = <open the output file> 0040 w = MimeWriter(f) 0041 ...call w.addheader(key, value) 0 or more times... 0042 0043 followed by either: 0044 0045 f = w.startbody(content_type) 0046 ...call f.write(data) for body data... 0047 0048 or: 0049 0050 w.startmultipartbody(subtype) 0051 for each part: 0052 subwriter = w.nextpart() 0053 ...use the subwriter's methods to create the subpart... 0054 w.lastpart() 0055 0056 The subwriter is another MimeWriter instance, and should be 0057 treated in the same way as the toplevel MimeWriter. This way, 0058 writing recursive body parts is easy. 0059 0060 Warning: don't forget to call lastpart()! 0061 0062 XXX There should be more state so calls made in the wrong order 0063 are detected. 0064 0065 Some special cases: 0066 0067 - startbody() just returns the file passed to the constructor; 0068 but don't use this knowledge, as it may be changed. 0069 0070 - startmultipartbody() actually returns a file as well; 0071 this can be used to write the initial 'if you can read this your 0072 mailer is not MIME-aware' message. 0073 0074 - If you call flushheaders(), the headers accumulated so far are 0075 written out (and forgotten); this is useful if you don't need a 0076 body part at all, e.g. for a subpart of type message/rfc822 0077 that's (mis)used to store some header-like information. 0078 0079 - Passing a keyword argument 'prefix=<flag>' to addheader(), 0080 start*body() affects where the header is inserted; 0 means 0081 append at the end, 1 means insert at the start; default is 0082 append for addheader(), but insert for start*body(), which use 0083 it to determine where the Content-Type header goes. 0084 0085 """ 0086 0087 def __init__(self, fp): 0088 self._fp = fp 0089 self._headers = [] 0090 0091 def addheader(self, key, value, prefix=0): 0092 """Add a header line to the MIME message. 0093 0094 The key is the name of the header, where the value obviously provides 0095 the value of the header. The optional argument prefix determines 0096 where the header is inserted; 0 means append at the end, 1 means 0097 insert at the start. The default is to append. 0098 0099 """ 0100 lines = value.split("\n") 0101 while lines and not lines[-1]: del lines[-1] 0102 while lines and not lines[0]: del lines[0] 0103 for i in range(1, len(lines)): 0104 lines[i] = " " + lines[i].strip() 0105 value = "\n".join(lines) + "\n" 0106 line = key + ": " + value 0107 if prefix: 0108 self._headers.insert(0, line) 0109 else: 0110 self._headers.append(line) 0111 0112 def flushheaders(self): 0113 """Writes out and forgets all headers accumulated so far. 0114 0115 This is useful if you don't need a body part at all; for example, 0116 for a subpart of type message/rfc822 that's (mis)used to store some 0117 header-like information. 0118 0119 """ 0120 self._fp.writelines(self._headers) 0121 self._headers = [] 0122 0123 def startbody(self, ctype, plist=[], prefix=1): 0124 """Returns a file-like object for writing the body of the message. 0125 0126 The content-type is set to the provided ctype, and the optional 0127 parameter, plist, provides additional parameters for the 0128 content-type declaration. The optional argument prefix determines 0129 where the header is inserted; 0 means append at the end, 1 means 0130 insert at the start. The default is to insert at the start. 0131 0132 """ 0133 for name, value in plist: 0134 ctype = ctype + ';\n %s=\"%s\"' % (name, value) 0135 self.addheader("Content-Type", ctype, prefix=prefix) 0136 self.flushheaders() 0137 self._fp.write("\n") 0138 return self._fp 0139 0140 def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1): 0141 """Returns a file-like object for writing the body of the message. 0142 0143 Additionally, this method initializes the multi-part code, where the 0144 subtype parameter provides the multipart subtype, the boundary 0145 parameter may provide a user-defined boundary specification, and the 0146 plist parameter provides optional parameters for the subtype. The 0147 optional argument, prefix, determines where the header is inserted; 0148 0 means append at the end, 1 means insert at the start. The default 0149 is to insert at the start. Subparts should be created using the 0150 nextpart() method. 0151 0152 """ 0153 self._boundary = boundary or mimetools.choose_boundary() 0154 return self.startbody("multipart/" + subtype, 0155 [("boundary", self._boundary)] + plist, 0156 prefix=prefix) 0157 0158 def nextpart(self): 0159 """Returns a new instance of MimeWriter which represents an 0160 individual part in a multipart message. 0161 0162 This may be used to write the part as well as used for creating 0163 recursively complex multipart messages. The message must first be 0164 initialized with the startmultipartbody() method before using the 0165 nextpart() method. 0166 0167 """ 0168 self._fp.write("\n--" + self._boundary + "\n") 0169 return self.__class__(self._fp) 0170 0171 def lastpart(self): 0172 """This is used to designate the last part of a multipart message. 0173 0174 It should always be used when writing multipart messages. 0175 0176 """ 0177 self._fp.write("\n--" + self._boundary + "--\n") 0178 0179 0180 if __name__ == '__main__': 0181 import test.test_MimeWriter 0182
Generated by PyXR 0.9.4