]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """Generic MIME writer.\r |
2 | \r | |
3 | This module defines the class MimeWriter. The MimeWriter class implements\r | |
4 | a basic formatter for creating MIME multi-part files. It doesn't seek around\r | |
5 | the output file nor does it use large amounts of buffer space. You must write\r | |
6 | the parts out in the order that they should occur in the final file.\r | |
7 | MimeWriter does buffer the headers you add, allowing you to rearrange their\r | |
8 | order.\r | |
9 | \r | |
10 | """\r | |
11 | \r | |
12 | \r | |
13 | import mimetools\r | |
14 | \r | |
15 | __all__ = ["MimeWriter"]\r | |
16 | \r | |
17 | import warnings\r | |
18 | \r | |
19 | warnings.warn("the MimeWriter module is deprecated; use the email package instead",\r | |
20 | DeprecationWarning, 2)\r | |
21 | \r | |
22 | class MimeWriter:\r | |
23 | \r | |
24 | """Generic MIME writer.\r | |
25 | \r | |
26 | Methods:\r | |
27 | \r | |
28 | __init__()\r | |
29 | addheader()\r | |
30 | flushheaders()\r | |
31 | startbody()\r | |
32 | startmultipartbody()\r | |
33 | nextpart()\r | |
34 | lastpart()\r | |
35 | \r | |
36 | A MIME writer is much more primitive than a MIME parser. It\r | |
37 | doesn't seek around on the output file, and it doesn't use large\r | |
38 | amounts of buffer space, so you have to write the parts in the\r | |
39 | order they should occur on the output file. It does buffer the\r | |
40 | headers you add, allowing you to rearrange their order.\r | |
41 | \r | |
42 | General usage is:\r | |
43 | \r | |
44 | f = <open the output file>\r | |
45 | w = MimeWriter(f)\r | |
46 | ...call w.addheader(key, value) 0 or more times...\r | |
47 | \r | |
48 | followed by either:\r | |
49 | \r | |
50 | f = w.startbody(content_type)\r | |
51 | ...call f.write(data) for body data...\r | |
52 | \r | |
53 | or:\r | |
54 | \r | |
55 | w.startmultipartbody(subtype)\r | |
56 | for each part:\r | |
57 | subwriter = w.nextpart()\r | |
58 | ...use the subwriter's methods to create the subpart...\r | |
59 | w.lastpart()\r | |
60 | \r | |
61 | The subwriter is another MimeWriter instance, and should be\r | |
62 | treated in the same way as the toplevel MimeWriter. This way,\r | |
63 | writing recursive body parts is easy.\r | |
64 | \r | |
65 | Warning: don't forget to call lastpart()!\r | |
66 | \r | |
67 | XXX There should be more state so calls made in the wrong order\r | |
68 | are detected.\r | |
69 | \r | |
70 | Some special cases:\r | |
71 | \r | |
72 | - startbody() just returns the file passed to the constructor;\r | |
73 | but don't use this knowledge, as it may be changed.\r | |
74 | \r | |
75 | - startmultipartbody() actually returns a file as well;\r | |
76 | this can be used to write the initial 'if you can read this your\r | |
77 | mailer is not MIME-aware' message.\r | |
78 | \r | |
79 | - If you call flushheaders(), the headers accumulated so far are\r | |
80 | written out (and forgotten); this is useful if you don't need a\r | |
81 | body part at all, e.g. for a subpart of type message/rfc822\r | |
82 | that's (mis)used to store some header-like information.\r | |
83 | \r | |
84 | - Passing a keyword argument 'prefix=<flag>' to addheader(),\r | |
85 | start*body() affects where the header is inserted; 0 means\r | |
86 | append at the end, 1 means insert at the start; default is\r | |
87 | append for addheader(), but insert for start*body(), which use\r | |
88 | it to determine where the Content-Type header goes.\r | |
89 | \r | |
90 | """\r | |
91 | \r | |
92 | def __init__(self, fp):\r | |
93 | self._fp = fp\r | |
94 | self._headers = []\r | |
95 | \r | |
96 | def addheader(self, key, value, prefix=0):\r | |
97 | """Add a header line to the MIME message.\r | |
98 | \r | |
99 | The key is the name of the header, where the value obviously provides\r | |
100 | the value of the header. The optional argument prefix determines\r | |
101 | where the header is inserted; 0 means append at the end, 1 means\r | |
102 | insert at the start. The default is to append.\r | |
103 | \r | |
104 | """\r | |
105 | lines = value.split("\n")\r | |
106 | while lines and not lines[-1]: del lines[-1]\r | |
107 | while lines and not lines[0]: del lines[0]\r | |
108 | for i in range(1, len(lines)):\r | |
109 | lines[i] = " " + lines[i].strip()\r | |
110 | value = "\n".join(lines) + "\n"\r | |
111 | line = key + ": " + value\r | |
112 | if prefix:\r | |
113 | self._headers.insert(0, line)\r | |
114 | else:\r | |
115 | self._headers.append(line)\r | |
116 | \r | |
117 | def flushheaders(self):\r | |
118 | """Writes out and forgets all headers accumulated so far.\r | |
119 | \r | |
120 | This is useful if you don't need a body part at all; for example,\r | |
121 | for a subpart of type message/rfc822 that's (mis)used to store some\r | |
122 | header-like information.\r | |
123 | \r | |
124 | """\r | |
125 | self._fp.writelines(self._headers)\r | |
126 | self._headers = []\r | |
127 | \r | |
128 | def startbody(self, ctype, plist=[], prefix=1):\r | |
129 | """Returns a file-like object for writing the body of the message.\r | |
130 | \r | |
131 | The content-type is set to the provided ctype, and the optional\r | |
132 | parameter, plist, provides additional parameters for the\r | |
133 | content-type declaration. The optional argument prefix determines\r | |
134 | where the header is inserted; 0 means append at the end, 1 means\r | |
135 | insert at the start. The default is to insert at the start.\r | |
136 | \r | |
137 | """\r | |
138 | for name, value in plist:\r | |
139 | ctype = ctype + ';\n %s=\"%s\"' % (name, value)\r | |
140 | self.addheader("Content-Type", ctype, prefix=prefix)\r | |
141 | self.flushheaders()\r | |
142 | self._fp.write("\n")\r | |
143 | return self._fp\r | |
144 | \r | |
145 | def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1):\r | |
146 | """Returns a file-like object for writing the body of the message.\r | |
147 | \r | |
148 | Additionally, this method initializes the multi-part code, where the\r | |
149 | subtype parameter provides the multipart subtype, the boundary\r | |
150 | parameter may provide a user-defined boundary specification, and the\r | |
151 | plist parameter provides optional parameters for the subtype. The\r | |
152 | optional argument, prefix, determines where the header is inserted;\r | |
153 | 0 means append at the end, 1 means insert at the start. The default\r | |
154 | is to insert at the start. Subparts should be created using the\r | |
155 | nextpart() method.\r | |
156 | \r | |
157 | """\r | |
158 | self._boundary = boundary or mimetools.choose_boundary()\r | |
159 | return self.startbody("multipart/" + subtype,\r | |
160 | [("boundary", self._boundary)] + plist,\r | |
161 | prefix=prefix)\r | |
162 | \r | |
163 | def nextpart(self):\r | |
164 | """Returns a new instance of MimeWriter which represents an\r | |
165 | individual part in a multipart message.\r | |
166 | \r | |
167 | This may be used to write the part as well as used for creating\r | |
168 | recursively complex multipart messages. The message must first be\r | |
169 | initialized with the startmultipartbody() method before using the\r | |
170 | nextpart() method.\r | |
171 | \r | |
172 | """\r | |
173 | self._fp.write("\n--" + self._boundary + "\n")\r | |
174 | return self.__class__(self._fp)\r | |
175 | \r | |
176 | def lastpart(self):\r | |
177 | """This is used to designate the last part of a multipart message.\r | |
178 | \r | |
179 | It should always be used when writing multipart messages.\r | |
180 | \r | |
181 | """\r | |
182 | self._fp.write("\n--" + self._boundary + "--\n")\r | |
183 | \r | |
184 | \r | |
185 | if __name__ == '__main__':\r | |
186 | import test.test_MimeWriter\r |