[Mailman-Developers] Running Mailman via POP

amk at amk.ca amk at amk.ca
Fri Sep 5 08:58:30 EDT 2003


Here's a little script I just wrote for having Mailman retrieve messages to
process via POP.  This is useful in my current situation, where
reconfiguring the corporate mail server isn't an option.  Instead I plan to
set up aliases directing mail to foo, foo-subscribe, foo-bounces, etc.  into
a single 'mailman' mailbox.  This script will run from cron, getting the
messages via POP, and passing them to the right command.

Does anyone have comments on this code?  Especially any potential problems
with it...

In the next day or two I'll put this up on my web pages somewhere so it gets
Googled.

--amk

#
# Mailman via POP
#

import os, poplib, rfc822, cStringIO

# Configuration information
POP_HOST = 'pop.example.com'
POP_USER = 'mailman'
POP_PASSWORD = 'password'
MESSAGE_ID_FILE = '/tmp/message-ids'

# List of domains containing mailing list addresses.
# e.g. if this is ['x', 'y'], then foo at x and foo at y are both treated
# as an e-mail to the 'foo' mailing list.
LIST_DOMAINS = ['example.com', 'lists.example.com']

def process_message (list_name, script_name, msg_id, message):
    print list_name, script_name, msg_id
    
    # Check if list exists
    if not os.path.exists('/home/mailman/lists/%s' % list_name):
        # It must not be a list
        return
    
    # Check if this message has already been processed for this list.
    try:
        input = open(MESSAGE_ID_FILE, 'r')
    except IOError:
        pass
    else:
        for line in input:
            sent_msg_id, sent_list = line.split()
            if (msg_id == sent_msg_id and
                sent_list == list_name):
                print 'Already processed message %r -- skipping' % msg_id
                input.close()
                return
        input.close()

    # Try to open the message ID file for writing before doing anything
    # further.
    output = open(MESSAGE_ID_FILE, 'a')
        
    # XXX process message
    pipe = os.popen('/home/mailman/mail/mailman %s %s' %
                    (script_name, list_name), 'w')
    pipe.write(message)
    pipe.close()

    output.write('%s %s\n' % (msg_id, list_name))
    output.close()
    
def display_message(message, show_body=False):
    print 'From:', message.getheader('From')
    print 'Subject:', message.getheader('Subject')
    print 'To:', message.getheader('To')
    print 'Cc:', message.getheader('Cc')
    print 'Message-ID:', message.getheader('Message-ID')
    if show_body:
        message.rewindbody()
        print message.fp.read()
    
def main():
    conn = poplib.POP3(POP_HOST)
    conn.user(POP_USER)
    conn.pass_(POP_PASSWORD)
    count, size = conn.stat()
    ##print count, 'messages'

    # Read the messages and figure out which lists they belong to
    for i in range(1, count+1):
        resp, lines, octets = conn.retr(i)
        msg_text = '\n'.join(lines)
        fp = cStringIO.StringIO(msg_text)
        msg = rfc822.Message(fp)
        lists = []
        for human_name, email_addr in (msg.getaddrlist('to') +
                                       msg.getaddrlist('cc')):
            for domain in LIST_DOMAINS:				       
                if email_addr.endswith('@'+domain):
                    index = email_addr.find('@')
                    list_name = email_addr[:index].lower()
                    
                    # Remove suffixes
		    script_name = 'post'
                    for suffix in ['admin', 'bounces', 'confirm', 'join',
                               	   'leave', 'owner', 'request', 
                               	   'subscribe', 'unsubscribe']:
                    	if list_name.endswith('-'+suffix):
                            list_name = list_name.replace('-'+suffix, '')
			    script_name = suffix
                    if list_name not in lists:
                    	lists.append(list_name)

        if len(lists) == 0:
            print 'Ignoring message:'
            display_message(msg, show_body=True)
        else:
            message_id = msg.getheader('Message-ID')
            for list in lists:
                process_message(list, script_name, message_id, msg_text)

        conn.dele(i)
        
    conn.quit()


if __name__ == '__main__':
    main()
    



More information about the Mailman-Developers mailing list