A MemberAdaptor for LDAP-based membership

Bug #558106 reported by fubarobfusco
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Mailman

Bug Description

This is a module, LDAPMemberships, which extends MemberAdaptor to support membership lists based on a search in an enterprise LDAP directory. With this module, you can make mailing lists which, rather than having a list of member addresses stored in the list, query your LDAP server for member addresses whenever necessary.

For instance, if you wish to have a mailing list of all the Vice Presidents in your company, you can express this as an LDAP search: "(title=Vice President*)" and create a mailing list which performs this search and delivers mail to the resulting user accounts when a message is sent to it. This way, rather than manually adding new Vice Presidents to the mailing list, you can simply have Human Resources update the LDAP records, and the change will immediately take effect for the mailing list.

Mailman lists with LDAP-based membership can still have moderators, list policies, and the other usual features of Mailman lists. There are a few missing features; notably:

1. There is no bounce processing.
2. There are no per-user preferences.
3. The Web interface still allows you to try setting user preferences, but if you do you will get a stack thrown at you. (Only the "readable" interface of MemberAdaptor is implemented.)
4. The LDAP settings of a list (e.g. LDAP server and search string) are only administrable by editing its "extend.py" file, not over the Web.
5. There is no digest mode.

To use this module, you must have the "ldap" Python module installed (aka "python-ldap"). Then just put LDAPMemberships.py in the "Mailman" directory (~mailman/Mailman), create a new list, and write an "extend.py" file in the list directory like so:

from Mailman.LDAPMemberships import LDAPMemberships

def extend(list):
    ldap = LDAPMemberships(list)
    ldap.ldapsearch = "(title=Vice President*)" # members search string
    ldap.ldapserver = "ldap.example.net" # your enterprise LDAP server
    ldap.ldapbasedn = "dc=Example dc=net" # your LDAP base DN
    ldap.ldapbinddn = '' # a bind DN which can read people's 'mail' field
    ldap.ldappasswd = '' # the password for the bind DN
    list._memberadaptor = ldap

This module has been tested at my site and is in production on a Mailman 2.1.2 installation.

Revision history for this message
fubarobfusco (fubarobfusco) wrote :

Logged In: YES

Er. SF ate the indentation on my "extend.py" example in the patch description. All of the lines after "def extend(list):" are meant to be indented once.

Revision history for this message
fubarobfusco (fubarobfusco) wrote :

Logged In: YES

I've uploaded a new version (0.2) of LDAPMemberships.py. This one is some ungodly number of times faster, as it does not do redundant LDAP queries in a single load.

Revision history for this message
fubarobfusco (fubarobfusco) wrote :

Logged In: YES

Yet another new version (0.3) of LDAPMemberships.py. This
one fixes some ambiguities with LDAP record handling,
particularly for users with multiple "cn" values, and those
who send mail as their "mailalternateaddress" field address
rather than their "mail" field.

If anyone is actually using this, please email me and let me
know :)

Revision history for this message
cdrum (cdrum) wrote :

Logged In: YES

why use this when you can just use Sendmail's LDAP -> Alias
functions? No need for a mailing list program like mailman..

Revision history for this message
fubarobfusco (fubarobfusco) wrote :

Logged In: YES

Well, Mailman does a lot more than just keep track of who's subscribed --
for instance, restricted posters, list moderation, archiving.
LDAPMemberships is not meant to be useful for Internet mailing lists with
people signing up for them, but rather for institutional or enterprise lists.
These have a lot of the same requirements (moderation etc.) as Internet
lists, but don't need subscription/unsubscription -- since employees are
usually required to be on them.

My workplace is using this (well, actually a later version than the one I've
uploaded here) as a replacement for an LDAP mailing-list feature in
Netscape SuiteSpot now that we have migrated away from that system.
We -also- use LDAP-based aliases (in Postfix, not Sendmail, actually) --
but for some things we need the moderation and other facilities that
Mailman has.

For instance, we have an announcements list that goes to all regular
employees. A simple alias would allow anyone to send stuff to it, and
certain senior scientists would love to send big PDFs to everyone. A
Mailman list with LDAPMemberships can have sender restrictions so that
only our IT Director and our mail systems admin can approve posts to it.
Archiving is also quite useful for announcements lists.

Revision history for this message
the_olo (the-olo-users) wrote :

Logged In: YES

I suggest this patch to allow senders use any source address
they might have set in LDAP (the 'mail' attribute can have
multiple values!)

--- LDAPMemberships.py.orig 2004-04-01
12:31:54.000000000 +0200
+++ LDAPMemberships.py 2004-04-05 15:40:03.000000000 +0200
@@ -115,7 +115,9 @@
                                        # mail is unique
                                        mail =

self.__member_map[mail] = mail
+ # mail can have
multiple values
+ for secondarymail in
self.__member_map[secondarymail.strip()] = mail
                                                malts =
                                                for malt in

Revision history for this message
mawhin (mawhin) wrote :

Logged In: YES

I've hacked your work about to get it to handle lists based
on group membership instead.

You may find it worthwhile.


This version's nasty, but you'll get the idea. Wanna roll it
into yours?


Revision history for this message
fubarobfusco (fubarobfusco) wrote :

The file LDAPMemberships.py was added: LDAPMemberships.py version 0.4

Revision history for this message
fubarobfusco (fubarobfusco) wrote :

Logged In: YES

I've just uploaded version 0.4 of LDAPMemberships.py. This
includes the patch by the_olo to support multiple values in
'mail', and also fixes a bug reported by Mark Sapiro
involving importing defaults from the wrong module.

Revision history for this message
viktu (viktu) wrote :

Logged In: YES

Hi all, I'm having troubles with this memberadaptor, which I
can't resolve as I have no idea of python :(

The fact is that sometimes it works, sometimes not. If the
query returns few values (this is 50,60) it works fine, but
when I have to select a huge amount of addresses (say 3000)
it gives up giving errors such "Can't contact LDAP server".
Then it puts the message in the shunt folder, and sometimes
unshunting several times it sends the email, and sometimes
you lose it forever and can't find where it went.

Any ideas? Anyone having the same problem?

Thanks a lot!

Revision history for this message
Mark Sapiro (msapiro) wrote :

This version (0.5) of LDAPMemberships.py supports mixed case email addresses and properly returns None from the getMemberName method if the member has no 'cn' value in the LDAP database.

Revision history for this message
Mark Sapiro (msapiro) wrote :

This update (0.6) from Chris Nulk adds additional fields from LDAP
            givenname - givenname/firstname typically,
            preferredname - preferred name instead of givenname,
            sn - surname/lastname,
            fullname - usually first/given name and last/sur name combined,
to be consulted in defining the member's real name.

Revision history for this message
Mark Sapiro (msapiro) wrote :

This version includes a contribution by Seth Bromberger to support LDAP groups.

It also fixes a problem with version 0.6 that would throw an exception if variables having to do with real name options were not set in mm_cfg.py. They are now given reasonable defaults if not set.

Revision history for this message
Mark Sapiro (msapiro) wrote :

Version 0.63 contains changes by Seth Bromberger to support digest members.

Revision history for this message
fs-physik-bielefeld (ubuntu-fachschaft) wrote :

First of all, thanks for your work, it really helped me out. I also hacked a little modification, to support cacertfile and reqcert (for ldaps:// connections). If you like it, take it.

Revision history for this message
fs-physik-bielefeld (ubuntu-fachschaft) wrote :

So I used that adapter, but I had the problem that the mail server was more important to be accessible without interruption that the ldap server. So I tried replicating the ldap server to the mail server, but since I did not want the password hashes on the mail server, I tried a partial replication which somehow did not always work. Although the ldap-server for the adapter was ldapi:///, it sometimes said 'connection refused' and shunted my mails.

I finally changed LdapMemberships.py to FileMemberships.py, which is minimal and just reads the list entries from files that are created with python's pickle module. The files, on the other hand, are populated by a cron job which contacts the original LDAP-Server. The disadvantage is that changes to the LDAP entries get realized with a delay of one hour at most, but the advantage is that if there is some problem with the LDAP server, the files are just left as they are and the mails get delivered. For my case this is more important.

For the implementation of FileMemberships, I was guided by this module, so thanks for that. If someone else is interested, my version is attached.

Revision history for this message
Mark Sapiro (msapiro) wrote :

The LDAP_Memberships.py, version 0.63 which was attached to Comment #14 has been deleted. It is replaced with this one which corrects a serious typo in the prior version.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers