OMGW00T: After over a decade, the MailList mixin class is gone! Well,
[mailman.git] / Mailman / docs / cook-headers.txt
blobffe2dfa5f9d8d5f49c2f285ad50d0f307abe26de
1 Cooking headers
2 ===============
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/'
22     >>> flush()
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
33     ...
34     ... A message of great import.
35     ... """, Message)
36     >>> msgdata = {}
37     >>> process(mlist, msg, msgdata)
38     >>> msgdata['original_sender']
39     'aperson@example.com'
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
45     ...
46     ... A message of great import.
47     ... """, Message)
48     >>> msgdata = {}
49     >>> process(mlist, msg, msgdata)
50     >>> msgdata['original_sender']
51     ''
54 X-BeenThere header
55 ------------------
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
59 mail loops.
61     >>> msg = message_from_string("""\
62     ... From: aperson@example.com
63     ...
64     ... A message of great import.
65     ... """, Message)
66     >>> process(mlist, msg, {})
67     >>> msg['x-beenthere']
68     '_xtest@example.com'
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
76     ...
77     ... A message of great import.
78     ... """, Message)
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
91     ...
92     ... A message of great import.
93     ... """, Message)
94     >>> process(mlist, msg, {})
95     >>> from Mailman.Version import VERSION
96     >>> msg['x-mailman-version'] == VERSION
97     True
99 ...but only if one doesn't already exist.
101     >>> msg = message_from_string("""\
102     ... From: aperson@example.com
103     ... X-Mailman-Version: 3000
104     ...
105     ... A message of great import.
106     ... """, Message)
107     >>> process(mlist, msg, {})
108     >>> from Mailman.Version import VERSION
109     >>> msg['x-mailman-version']
110     '3000'
113 Precedence header
114 -----------------
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
118 message.
120     >>> msg = message_from_string("""\
121     ... From: aperson@example.com
122     ...
123     ... A message of great import.
124     ... """, Message)
125     >>> process(mlist, msg, {})
126     >>> from Mailman.Version import VERSION
127     >>> msg['precedence']
128     'list'
130 But Mailman will only add that header if the original message doesn't already
131 have one of them.
133     >>> msg = message_from_string("""\
134     ... From: aperson@example.com
135     ... Precedence: junk
136     ...
137     ... A message of great import.
138     ... """, Message)
139     >>> process(mlist, msg, {})
140     >>> from Mailman.Version import VERSION
141     >>> msg['precedence']
142     'junk'
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:
158     ...             continue
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
169     ...
170     ... """, Message)
171     >>> process(mlist, msg, dict(_nolist=True))
172     >>> list_headers(msg)
173     ---start---
174     ---end---
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
180     >>> flush()
181     >>> msg = message_from_string("""\
182     ... From: aperson@example.com
183     ...
184     ... """, Message)
185     >>> process(mlist, msg, {})
186     >>> list_headers(msg)
187     ---start---
188     ---end---
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'
195     >>> flush()
196     >>> msg = message_from_string("""\
197     ... From: aperson@example.com
198     ...
199     ... """, Message)
200     >>> process(mlist, msg, {})
201     >>> list_headers(msg)
202     ---start---
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>
211     ---end---
213 If the mailing list has a description, then it is included in the List-Id
214 header.
216     >>> mlist.description = 'My test mailing list'
217     >>> flush()
218     >>> msg = message_from_string("""\
219     ... From: aperson@example.com
220     ...
221     ... """, Message)
222     >>> process(mlist, msg, {})
223     >>> list_headers(msg)
224     ---start---
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>
233     ---end---
235 Administrative messages crafted by Mailman will have a reduced set of headers.
237     >>> msg = message_from_string("""\
238     ... From: aperson@example.com
239     ...
240     ... """, Message)
241     >>> process(mlist, msg, dict(reduced_list_headers=True))
242     >>> list_headers(msg)
243     ---start---
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
251     ---end---
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
257     >>> flush()
258     >>> msg = message_from_string("""\
259     ... From: aperson@example.com
260     ...
261     ... """, Message)
262     >>> process(mlist, msg, {})
263     >>> list_headers(msg)
264     ---start---
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>
272     ---end---
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
279     >>> flush()
280     >>> msg = message_from_string("""\
281     ... From: aperson@example.com
282     ...
283     ... """, Message)
284     >>> process(mlist, msg, {})
285     >>> list_headers(msg)
286     ---start---
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>
294     ---end---