def process(self, mlist, msg, msgdata): """See `IHandler`.""" # Remove headers that could contain passwords. del msg['approved'] del msg['approve'] del msg['x-approved'] del msg['x-approve'] del msg['urgent'] # We remove other headers from anonymous lists. if mlist.anonymous_list: log.info('post to %s from %s anonymized', mlist.fqdn_listname, msg.get('from')) del msg['from'] del msg['reply-to'] del msg['sender'] # Hotmail sets this one del msg['x-originating-email'] i18ndesc = str(uheader(mlist, mlist.description, 'From')) msg['From'] = formataddr((i18ndesc, mlist.posting_address)) msg['Reply-To'] = mlist.posting_address # Some headers can be used to fish for membership. del msg['return-receipt-to'] del msg['disposition-notification-to'] del msg['x-confirm-reading-to'] # Pegasus mail uses this one... sigh. del msg['x-pmrqc'] # Don't let this header be spoofed. See RFC 5064. del msg['archived-at']
def test_uheader_multiline(self): # Multiline headers should be truncated (GL#273). mark = LogFileMark('mailman.error') header = cook_headers.uheader(self._mlist, 'A multiline\ndescription', 'X-Header') self.assertEqual(header.encode(), 'A multiline [...]') log_messages = mark.read() self.assertIn('Header X-Header contains a newline, truncating it', log_messages)
def process(mlist, msg, msgdata): """Add the RFC 2369 List-* and related headers.""" # Some people really hate the List-* headers. It seems that the free # version of Eudora (possibly on for some platforms) does not hide these # headers by default, pissing off their users. Too bad. Fix the MUAs. if not mlist.include_rfc2369_headers: return list_id = '{0.list_name}.{0.mail_host}'.format(mlist) if mlist.description: # Don't wrap the header since here we just want to get it properly RFC # 2047 encoded. i18ndesc = uheader(mlist, mlist.description, 'List-Id', maxlinelen=998) listid_h = formataddr((str(i18ndesc), list_id)) else: # Without a description, we need to ensure the MUST brackets. listid_h = '<{}>'.format(list_id) # No other agent should add a List-ID header except Mailman. del msg['list-id'] msg['List-Id'] = listid_h # For internally crafted messages, we also add a (nonstandard), # "X-List-Administrivia: yes" header. For all others (i.e. those coming # from list posts), we add a bunch of other RFC 2369 headers. requestaddr = mlist.request_address headers = [] # XXX reduced_list_headers used to suppress List-Help, List-Subject, and # List-Unsubscribe from UserNotification. That doesn't seem to make sense # any more, so always add those three headers (others will still be # suppressed). headers.extend(( ('List-Help', '<mailto:{}?subject=help>'.format(requestaddr)), ('List-Unsubscribe', '<mailto:{}>'.format(mlist.leave_address)), ('List-Subscribe', '<mailto:{}>'.format(mlist.join_address)), )) if not msgdata.get('reduced_list_headers'): # List-Post: is controlled by a separate attribute, which is somewhat # misnamed. RFC 2369 requires a value of NO if posting is not # allowed, i.e. for an announce-only list. list_post = ('<mailto:{}>'.format(mlist.posting_address) if mlist.allow_list_posts else 'NO') headers.append(('List-Post', list_post)) # Add RFC 2369 and 5064 archiving headers, if archiving is enabled. if mlist.archive_policy is not ArchivePolicy.never: archiver_set = IListArchiverSet(mlist) for archiver in archiver_set.archivers: if not archiver.is_enabled: continue # Watch out for exceptions in the archiver plugin. try: archiver_url = archiver.system_archiver.list_url(mlist) except Exception: log.exception('Exception in "{}" archiver'.format( archiver.system_archiver.name)) archiver_url = None if archiver_url is not None: headers.append(('List-Archive', '<{}>'.format(archiver_url))) try: permalink = archiver.system_archiver.permalink(mlist, msg) except Exception: log.exception('Exception in "{}" archiver'.format( archiver.system_archiver.name)) permalink = None if permalink is not None: headers.append(('Archived-At', '<{}>'.format(permalink))) # XXX RFC 2369 also defines a List-Owner header which we are not currently # supporting, but should. # # Some headers will appear more than once in the new set, e.g. the # List-Archive and Archived-At headers. We want to delete any RFC 2369 # headers from the original message, but make sure to preserve all of the # new headers we're adding. Go through the list of new headers twice, # first removing any old ones, then adding all the new ones. for h, v in headers: del msg[h] for h, v in sorted(headers): # Wrap these lines if they are too long. 78 character width probably # shouldn't be hardcoded, but is at least text-MUA friendly. The # adding of 2 is for the colon-space separator. if len(h) + 2 + len(v) > 78: v = CONTINUATION.join(v.split(', ')) msg[h] = v
def process(mlist, msg, msgdata): """Add the RFC 2369 List-* and related headers.""" # Some people really hate the List-* headers. It seems that the free # version of Eudora (possibly on for some platforms) does not hide these # headers by default, pissing off their users. Too bad. Fix the MUAs. if not mlist.include_rfc2369_headers: return list_id = '{0.list_name}.{0.mail_host}'.format(mlist) if mlist.description: # Don't wrap the header since here we just want to get it properly RFC # 2047 encoded. i18ndesc = uheader(mlist, mlist.description, 'List-Id', maxlinelen=998) listid_h = formataddr((str(i18ndesc), list_id)) else: # Without a description, we need to ensure the MUST brackets. listid_h = '<{}>'.format(list_id) # No other agent should add a List-ID header except Mailman. del msg['list-id'] msg['List-Id'] = listid_h # For internally crafted messages, we also add a (nonstandard), # "X-List-Administrivia: yes" header. For all others (i.e. those coming # from list posts), we add a bunch of other RFC 2369 headers. requestaddr = mlist.request_address subfieldfmt = '<{}>, <mailto:{}>' listinfo = mlist.script_url('listinfo') headers = [] # XXX reduced_list_headers used to suppress List-Help, List-Subject, and # List-Unsubscribe from UserNotification. That doesn't seem to make sense # any more, so always add those three headers (others will still be # suppressed). headers.extend(( ('List-Help', '<mailto:{}?subject=help>'.format(requestaddr)), ('List-Unsubscribe', subfieldfmt.format(listinfo, mlist.leave_address)), ('List-Subscribe', subfieldfmt.format(listinfo, mlist.join_address)), )) if not msgdata.get('reduced_list_headers'): # List-Post: is controlled by a separate attribute, which is somewhat # misnamed. RFC 2369 requires a value of NO if posting is not # allowed, i.e. for an announce-only list. list_post = ('<mailto:{}>'.format(mlist.posting_address) if mlist.allow_list_posts else 'NO') headers.append(('List-Post', list_post)) # Add RFC 2369 and 5064 archiving headers, if archiving is enabled. if mlist.archive_policy is not ArchivePolicy.never: archiver_set = IListArchiverSet(mlist) for archiver in archiver_set.archivers: if not archiver.is_enabled: continue # Watch out for exceptions in the archiver plugin. try: archiver_url = archiver.system_archiver.list_url(mlist) except Exception: log.exception('Exception in "{}" archiver'.format( archiver.system_archiver.name)) archiver_url = None if archiver_url is not None: headers.append(('List-Archive', '<{}>'.format(archiver_url))) try: permalink = archiver.system_archiver.permalink(mlist, msg) except Exception: log.exception('Exception in "{}" archiver'.format( archiver.system_archiver.name)) permalink = None if permalink is not None: headers.append(('Archived-At', '<{}>'.format(permalink))) # XXX RFC 2369 also defines a List-Owner header which we are not currently # supporting, but should. # # Some headers will appear more than once in the new set, e.g. the # List-Archive and Archived-At headers. We want to delete any RFC 2369 # headers from the original message, but make sure to preserve all of the # new headers we're adding. Go through the list of new headers twice, # first removing any old ones, then adding all the new ones. for h, v in headers: del msg[h] for h, v in sorted(headers): # Wrap these lines if they are too long. 78 character width probably # shouldn't be hardcoded, but is at least text-MUA friendly. The # adding of 2 is for the colon-space separator. if len(h) + 2 + len(v) > 78: v = CONTINUATION.join(v.split(', ')) msg[h] = v
def process(mlist, msg, msgdata): """Add the RFC 2369 List-* and related headers.""" # Some people really hate the List-* headers. It seems that the free # version of Eudora (possibly on for some platforms) does not hide these # headers by default, pissing off their users. Too bad. Fix the MUAs. if not mlist.include_rfc2369_headers: return list_id = '{0.list_name}.{0.mail_host}'.format(mlist) if mlist.description: # Don't wrap the header since here we just want to get it properly RFC # 2047 encoded. i18ndesc = uheader(mlist, mlist.description, 'List-Id', maxlinelen=998) listid_h = formataddr((str(i18ndesc), list_id)) else: # Without a description, we need to ensure the MUST brackets. listid_h = '<{0}>'.format(list_id) # No other agent should add a List-ID header except Mailman. del msg['list-id'] msg['List-Id'] = listid_h # For internally crafted messages, we also add a (nonstandard), # "X-List-Administrivia: yes" header. For all others (i.e. those coming # from list posts), we add a bunch of other RFC 2369 headers. requestaddr = mlist.request_address subfieldfmt = '<{0}>, <mailto:{1}>' listinfo = mlist.script_url('listinfo') headers = {} # XXX reduced_list_headers used to suppress List-Help, List-Subject, and # List-Unsubscribe from UserNotification. That doesn't seem to make sense # any more, so always add those three headers (others will still be # suppressed). headers.update({ 'List-Help' : '<mailto:{0}?subject=help>'.format(requestaddr), 'List-Unsubscribe': subfieldfmt.format(listinfo, mlist.leave_address), 'List-Subscribe' : subfieldfmt.format(listinfo, mlist.join_address), }) if not msgdata.get('reduced_list_headers'): # List-Post: is controlled by a separate attribute, which is somewhat # misnamed. RFC 2369 requires a value of NO if posting is not # allowed, i.e. for an announce-only list. list_post = ('<mailto:{0}>'.format(mlist.posting_address) if mlist.allow_list_posts else 'NO') headers['List-Post'] = list_post # Add RFC 2369 and 5064 archiving headers, if archiving is enabled. if mlist.archive_policy is not ArchivePolicy.never: for archiver in config.archivers: headers['List-Archive'] = '<{0}>'.format( archiver.list_url(mlist)) permalink = archiver.permalink(mlist, msg) if permalink is not None: headers['Archived-At'] = permalink # XXX RFC 2369 also defines a List-Owner header which we are not currently # supporting, but should. for h, v in headers.items(): # First we delete any pre-existing headers because the RFC permits # only one copy of each, and we want to be sure it's ours. del msg[h] # Wrap these lines if they are too long. 78 character width probably # shouldn't be hardcoded, but is at least text-MUA friendly. The # adding of 2 is for the colon-space separator. if len(h) + 2 + len(v) > 78: v = CONTINUATION.join(v.split(', ')) msg[h] = v