4 Messages that flow through the global pipeline get their headers 'cooked',
5 which basically means that their headers go through several mostly unrelated
6 transformations. Some headers get added, others get changed. Some of these
7 changes depend on mailing list settings and others depend on how the message
8 is getting sent through the system. We'll take things one-by-one.
10 >>> from email import message_from_string
11 >>> from Mailman.Message import Message
12 >>> from Mailman.Handlers.CookHeaders import process
13 >>> from Mailman.configuration import config
14 >>> from Mailman.database import flush
15 >>> mlist = config.db.list_manager.create('_xtest@example.com')
16 >>> mlist.subject_prefix = u''
17 >>> mlist.include_list_post_header = False
18 >>> mlist.archive = True
19 >>> # XXX This will almost certainly change once we've worked out the web
20 >>> # space layout for mailing lists now.
21 >>> mlist.web_page_url = 'http://lists.example.com/'
25 Saving the original sender
26 --------------------------
28 Because the original sender headers may get deleted or changed, CookHeaders
29 will place the sender in the message metadata for safe keeping.
31 >>> msg = message_from_string("""\
32 ... From: aperson@example.com
34 ... A message of great import.
37 >>> process(mlist, msg, msgdata)
38 >>> msgdata['original_sender']
41 But if there was no original sender, then the empty string will be saved.
43 >>> msg = message_from_string("""\
44 ... Subject: No original sender
46 ... A message of great import.
49 >>> process(mlist, msg, msgdata)
50 >>> msgdata['original_sender']
57 The X-BeenThere header is what Mailman uses to recognize messages that have
58 already been processed by this mailing list. It's one small measure against
61 >>> msg = message_from_string("""\
62 ... From: aperson@example.com
64 ... A message of great import.
66 >>> process(mlist, msg, {})
67 >>> msg['x-beenthere']
70 Mailman appends X-BeenThere headers, so if there already is one in the
71 original message, the posted message will contain two such headers.
73 >>> msg = message_from_string("""\
74 ... From: aperson@example.com
75 ... X-BeenThere: another@example.com
77 ... A message of great import.
79 >>> process(mlist, msg, {})
80 >>> sorted(msg.get_all('x-beenthere'))
81 ['_xtest@example.com', 'another@example.com']
84 Mailman version header
85 ----------------------
87 Mailman will also insert an X-Mailman-Version header...
89 >>> msg = message_from_string("""\
90 ... From: aperson@example.com
92 ... A message of great import.
94 >>> process(mlist, msg, {})
95 >>> from Mailman.Version import VERSION
96 >>> msg['x-mailman-version'] == VERSION
99 ...but only if one doesn't already exist.
101 >>> msg = message_from_string("""\
102 ... From: aperson@example.com
103 ... X-Mailman-Version: 3000
105 ... A message of great import.
107 >>> process(mlist, msg, {})
108 >>> from Mailman.Version import VERSION
109 >>> msg['x-mailman-version']
116 Mailman will insert a Precedence header, which is a de-facto standard for
117 telling automatic reply software (e.g. vacation(1)) not to respond to this
120 >>> msg = message_from_string("""\
121 ... From: aperson@example.com
123 ... A message of great import.
125 >>> process(mlist, msg, {})
126 >>> from Mailman.Version import VERSION
127 >>> msg['precedence']
130 But Mailman will only add that header if the original message doesn't already
133 >>> msg = message_from_string("""\
134 ... From: aperson@example.com
137 ... A message of great import.
139 >>> process(mlist, msg, {})
140 >>> from Mailman.Version import VERSION
141 >>> msg['precedence']
145 RFC 2919 and 2369 headers
146 -------------------------
148 This is a helper function for the following section.
150 >>> def list_headers(msg):
151 ... print '---start---'
152 ... # Sort the List-* headers found in the message. We need to do
153 ... # this because CookHeaders puts them in a dictionary which does
154 ... # not have a guaranteed sort order.
155 ... for header in sorted(msg.keys()):
156 ... parts = header.lower().split('-')
157 ... if 'list' not in parts:
159 ... for value in msg.get_all(header):
160 ... print '%s: %s' % (header, value)
161 ... print '---end---'
163 These RFCs define headers for mailing list actions. A mailing list should
164 generally add these headers, but not for messages that aren't crafted for a
165 specific list (e.g. password reminders in Mailman 2.x).
167 >>> msg = message_from_string("""\
168 ... From: aperson@example.com
171 >>> process(mlist, msg, dict(_nolist=True))
172 >>> list_headers(msg)
176 Some people don't like these headers because their mail readers aren't good
177 about hiding them. A list owner can turn these headers off.
179 >>> mlist.include_rfc2369_headers = False
181 >>> msg = message_from_string("""\
182 ... From: aperson@example.com
185 >>> process(mlist, msg, {})
186 >>> list_headers(msg)
190 But normally, a list will include these headers.
192 >>> mlist.include_rfc2369_headers = True
193 >>> mlist.include_list_post_header = True
194 >>> mlist.preferred_language = 'en'
196 >>> msg = message_from_string("""\
197 ... From: aperson@example.com
200 >>> process(mlist, msg, {})
201 >>> list_headers(msg)
203 List-Archive: <http://www.example.com/pipermail/_xtest@example.com>
204 List-Help: <mailto:_xtest-request@example.com?subject=help>
205 List-Id: <_xtest.example.com>
206 List-Post: <mailto:_xtest@example.com>
207 List-Subscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
208 <mailto:_xtest-join@example.com>
209 List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
210 <mailto:_xtest-leave@example.com>
213 If the mailing list has a description, then it is included in the List-Id
216 >>> mlist.description = 'My test mailing list'
218 >>> msg = message_from_string("""\
219 ... From: aperson@example.com
222 >>> process(mlist, msg, {})
223 >>> list_headers(msg)
225 List-Archive: <http://www.example.com/pipermail/_xtest@example.com>
226 List-Help: <mailto:_xtest-request@example.com?subject=help>
227 List-Id: My test mailing list <_xtest.example.com>
228 List-Post: <mailto:_xtest@example.com>
229 List-Subscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
230 <mailto:_xtest-join@example.com>
231 List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
232 <mailto:_xtest-leave@example.com>
235 Administrative messages crafted by Mailman will have a reduced set of headers.
237 >>> msg = message_from_string("""\
238 ... From: aperson@example.com
241 >>> process(mlist, msg, dict(reduced_list_headers=True))
242 >>> list_headers(msg)
244 List-Help: <mailto:_xtest-request@example.com?subject=help>
245 List-Id: My test mailing list <_xtest.example.com>
246 List-Subscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
247 <mailto:_xtest-join@example.com>
248 List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
249 <mailto:_xtest-leave@example.com>
250 X-List-Administrivia: yes
253 With the normal set of List-* headers, it's still possible to suppress the
254 List-Post header, which is reasonable for an announce only mailing list.
256 >>> mlist.include_list_post_header = False
258 >>> msg = message_from_string("""\
259 ... From: aperson@example.com
262 >>> process(mlist, msg, {})
263 >>> list_headers(msg)
265 List-Archive: <http://www.example.com/pipermail/_xtest@example.com>
266 List-Help: <mailto:_xtest-request@example.com?subject=help>
267 List-Id: My test mailing list <_xtest.example.com>
268 List-Subscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
269 <mailto:_xtest-join@example.com>
270 List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
271 <mailto:_xtest-leave@example.com>
274 And if the list isn't being archived, it makes no sense to add the
275 List-Archive header either.
277 >>> mlist.include_list_post_header = True
278 >>> mlist.archive = False
280 >>> msg = message_from_string("""\
281 ... From: aperson@example.com
284 >>> process(mlist, msg, {})
285 >>> list_headers(msg)
287 List-Help: <mailto:_xtest-request@example.com?subject=help>
288 List-Id: My test mailing list <_xtest.example.com>
289 List-Post: <mailto:_xtest@example.com>
290 List-Subscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
291 <mailto:_xtest-join@example.com>
292 List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>,
293 <mailto:_xtest-leave@example.com>