|  | """Generic MIME writer. | 
|  |  | 
|  | This module defines the class MimeWriter.  The MimeWriter class implements | 
|  | a basic formatter for creating MIME multi-part files.  It doesn't seek around | 
|  | the output file nor does it use large amounts of buffer space. You must write | 
|  | the parts out in the order that they should occur in the final file. | 
|  | MimeWriter does buffer the headers you add, allowing you to rearrange their | 
|  | order. | 
|  |  | 
|  | """ | 
|  |  | 
|  |  | 
|  | import mimetools | 
|  |  | 
|  | __all__ = ["MimeWriter"] | 
|  |  | 
|  | import warnings | 
|  |  | 
|  | warnings.warn("the MimeWriter module is deprecated; use the email package instead", | 
|  | DeprecationWarning, 2) | 
|  |  | 
|  | class MimeWriter: | 
|  |  | 
|  | """Generic MIME writer. | 
|  |  | 
|  | Methods: | 
|  |  | 
|  | __init__() | 
|  | addheader() | 
|  | flushheaders() | 
|  | startbody() | 
|  | startmultipartbody() | 
|  | nextpart() | 
|  | lastpart() | 
|  |  | 
|  | A MIME writer is much more primitive than a MIME parser.  It | 
|  | doesn't seek around on the output file, and it doesn't use large | 
|  | amounts of buffer space, so you have to write the parts in the | 
|  | order they should occur on the output file.  It does buffer the | 
|  | headers you add, allowing you to rearrange their order. | 
|  |  | 
|  | General usage is: | 
|  |  | 
|  | f = <open the output file> | 
|  | w = MimeWriter(f) | 
|  | ...call w.addheader(key, value) 0 or more times... | 
|  |  | 
|  | followed by either: | 
|  |  | 
|  | f = w.startbody(content_type) | 
|  | ...call f.write(data) for body data... | 
|  |  | 
|  | or: | 
|  |  | 
|  | w.startmultipartbody(subtype) | 
|  | for each part: | 
|  | subwriter = w.nextpart() | 
|  | ...use the subwriter's methods to create the subpart... | 
|  | w.lastpart() | 
|  |  | 
|  | The subwriter is another MimeWriter instance, and should be | 
|  | treated in the same way as the toplevel MimeWriter.  This way, | 
|  | writing recursive body parts is easy. | 
|  |  | 
|  | Warning: don't forget to call lastpart()! | 
|  |  | 
|  | XXX There should be more state so calls made in the wrong order | 
|  | are detected. | 
|  |  | 
|  | Some special cases: | 
|  |  | 
|  | - startbody() just returns the file passed to the constructor; | 
|  | but don't use this knowledge, as it may be changed. | 
|  |  | 
|  | - startmultipartbody() actually returns a file as well; | 
|  | this can be used to write the initial 'if you can read this your | 
|  | mailer is not MIME-aware' message. | 
|  |  | 
|  | - If you call flushheaders(), the headers accumulated so far are | 
|  | written out (and forgotten); this is useful if you don't need a | 
|  | body part at all, e.g. for a subpart of type message/rfc822 | 
|  | that's (mis)used to store some header-like information. | 
|  |  | 
|  | - Passing a keyword argument 'prefix=<flag>' to addheader(), | 
|  | start*body() affects where the header is inserted; 0 means | 
|  | append at the end, 1 means insert at the start; default is | 
|  | append for addheader(), but insert for start*body(), which use | 
|  | it to determine where the Content-Type header goes. | 
|  |  | 
|  | """ | 
|  |  | 
|  | def __init__(self, fp): | 
|  | self._fp = fp | 
|  | self._headers = [] | 
|  |  | 
|  | def addheader(self, key, value, prefix=0): | 
|  | """Add a header line to the MIME message. | 
|  |  | 
|  | The key is the name of the header, where the value obviously provides | 
|  | the value of the header. The optional argument prefix determines | 
|  | where the header is inserted; 0 means append at the end, 1 means | 
|  | insert at the start. The default is to append. | 
|  |  | 
|  | """ | 
|  | lines = value.split("\n") | 
|  | while lines and not lines[-1]: del lines[-1] | 
|  | while lines and not lines[0]: del lines[0] | 
|  | for i in range(1, len(lines)): | 
|  | lines[i] = "    " + lines[i].strip() | 
|  | value = "\n".join(lines) + "\n" | 
|  | line = key + ": " + value | 
|  | if prefix: | 
|  | self._headers.insert(0, line) | 
|  | else: | 
|  | self._headers.append(line) | 
|  |  | 
|  | def flushheaders(self): | 
|  | """Writes out and forgets all headers accumulated so far. | 
|  |  | 
|  | This is useful if you don't need a body part at all; for example, | 
|  | for a subpart of type message/rfc822 that's (mis)used to store some | 
|  | header-like information. | 
|  |  | 
|  | """ | 
|  | self._fp.writelines(self._headers) | 
|  | self._headers = [] | 
|  |  | 
|  | def startbody(self, ctype, plist=[], prefix=1): | 
|  | """Returns a file-like object for writing the body of the message. | 
|  |  | 
|  | The content-type is set to the provided ctype, and the optional | 
|  | parameter, plist, provides additional parameters for the | 
|  | content-type declaration.  The optional argument prefix determines | 
|  | where the header is inserted; 0 means append at the end, 1 means | 
|  | insert at the start. The default is to insert at the start. | 
|  |  | 
|  | """ | 
|  | for name, value in plist: | 
|  | ctype = ctype + ';\n %s=\"%s\"' % (name, value) | 
|  | self.addheader("Content-Type", ctype, prefix=prefix) | 
|  | self.flushheaders() | 
|  | self._fp.write("\n") | 
|  | return self._fp | 
|  |  | 
|  | def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1): | 
|  | """Returns a file-like object for writing the body of the message. | 
|  |  | 
|  | Additionally, this method initializes the multi-part code, where the | 
|  | subtype parameter provides the multipart subtype, the boundary | 
|  | parameter may provide a user-defined boundary specification, and the | 
|  | plist parameter provides optional parameters for the subtype.  The | 
|  | optional argument, prefix, determines where the header is inserted; | 
|  | 0 means append at the end, 1 means insert at the start. The default | 
|  | is to insert at the start.  Subparts should be created using the | 
|  | nextpart() method. | 
|  |  | 
|  | """ | 
|  | self._boundary = boundary or mimetools.choose_boundary() | 
|  | return self.startbody("multipart/" + subtype, | 
|  | [("boundary", self._boundary)] + plist, | 
|  | prefix=prefix) | 
|  |  | 
|  | def nextpart(self): | 
|  | """Returns a new instance of MimeWriter which represents an | 
|  | individual part in a multipart message. | 
|  |  | 
|  | This may be used to write the part as well as used for creating | 
|  | recursively complex multipart messages. The message must first be | 
|  | initialized with the startmultipartbody() method before using the | 
|  | nextpart() method. | 
|  |  | 
|  | """ | 
|  | self._fp.write("\n--" + self._boundary + "\n") | 
|  | return self.__class__(self._fp) | 
|  |  | 
|  | def lastpart(self): | 
|  | """This is used to designate the last part of a multipart message. | 
|  |  | 
|  | It should always be used when writing multipart messages. | 
|  |  | 
|  | """ | 
|  | self._fp.write("\n--" + self._boundary + "--\n") | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | import test.test_MimeWriter |