PyXR

c:\python24\lib \ MimeWriter.py



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
SourceForge.net Logo