Creating & Updating Distribution Lists in Zimbra from Active Directory

By | 12/11/2012

One of the downfalls of Zimbra is its poor integration with Active Directory, at least for the OSS version. This can be solved though with some scripting.

The basis of this script comes from “Zimbra autocreate accounts with Active Directory or LDAP” which was a good start for me but was much more complicated than I needed.

The purpose of this document is to document the method that I used to dynamically update the distribution lists from the OU membership on our Active Directory Server.

Assumptions of this Document

I am using:

  • Ubuntu Server 12.04 LTS
  • Zimbra version 8.0 OSS Version
  • Python
  • Microsoft Active on Windows 2008 Server R2
If your environment doesn’t match this then  you might not get the same results but this will hopefully point you in the right direction at least.

Modify / Create the Distribution Group and Add Members from AD

First thing is to create the script that gets a list of the users from AD and creates the necessary groups. A word of caution here is that you need to be careful of the indentation in Python. If the indentation of the lines is wrong (not what I have here) the script won’t work.

The values in RED should be changed to match your site.

$ sudo mkdir /opt/import
$ cd /opt/import
$ sudo vi groups.py
#!/usr/bin/python
import ldap,sys,os,time

# Address of LDAP Server
ldapHost = "ldap://adServer.domain.local:389"

#DN and Password of user to bind to AD with
user = "CN=UserName,CN=Users,DC=domain,DC=local"
password = "PASSWORD"

fqdn = "mailhost.domain.local" # FQDN of Zimbra Domain Configured

filter = "sn=*"

pathtozmprov="/opt/zimbra/bin/zmprov"

#--------------END VAR--------------------
groupName = str(sys.argv[1])
baseDN = str(sys.argv[2])
f = os.popen(pathtozmprov +' -l gaa ')
zmprovgaa = []
zmprovgaa = f.readlines()

try:    
  l = ldap.initialize(ldapHost) 
  l.simple_bind_s(user, password)
  result = l.search_s(baseDN, ldap.SCOPE_SUBTREE,filter)
  delete_group =  pathtozmprov + " ddl " + groupName + "@" + fqdn
  create_group =  pathtozmprov + " cdl " + groupName + "@" + fqdn
  populate_group = pathtozmprov + " adlm " + groupName + "@" + fqdn

  for (dn, vals) in result:
    try:
      mail = vals['mail'][0]
    except:
      mail = vals['sAMAccountName'][0].lower() + "@" + fqdn

    sys.stdout.flush()
    populate_group = populate_group + " " + mail

  os.system (delete_group)
  os.system (create_group)
  os.system (populate_group)

except ldap.LDAPError, error_message:
  print error_message     

l.unbind_s()
$ sudo chmod 755 groups.py

Example usage:

$ sudo su zimbra -
$ cd /opt/import
$./groups.py staff "OU=Staff,OU=Users,DC=domain,DC=local"

Specifically, this will create a Distribution List with the name of “staff” which contains all of the users in the OU listed. It’s assumed that you will already have the users created in Zimbra. The script to do this will be documented soon. If you need it now, you can email me antony@street.id.au.

Finishing Up

You could call groups.py directly from cron but it’s better to create a shell script to call it and then add the shell script to cron. This way you can easily add and edit the required OUs.

$ sudo vi batch_groups.sh
#!/bin/bash
/opt/import/groups.py staff "OU=Staff,OU=Users,DC=domain,DC=local"

Finally we’ll schedule the command to run by adding it to crontab. To complete this:

$ sudo su zimbra -
$ crontab -e

Insert the following line at the beginning of the file.

@daily /opt/import/batch_groups.sh

6 thoughts on “Creating & Updating Distribution Lists in Zimbra from Active Directory

  1. Gregg Nicholas

    This script looks good, but I’d rather find a way to import the members of an Active Directory Group into a Zimbra distribution list. Unfortunately, I don’t have the python or ldap skills to make the necessary modifications. Do you know how to do it?

    Reply
    1. Antony Post author

      Thank you for sharing the link. In our environment we have the users (students) in a very structured GPO hierarchy. I can see why that might not work in other environments. I hope it works well for you

      Reply
  2. Salva

    Hi,

    I have edited your script for take a Distribution Group and replicate it in Zimbra. This script read members of a AD distribution Gruop and recreate as a Distribution List with same members in Zimbra.

    You mas invoke it like:

    python populate_distributionlist_AD.py GROUP_NAME “cn=GROUP_NAME,ou=Grupos,ou=Folder1,dc=domain,dc=com”

    Where GROUP_NAME is a group in your AD:

    #!/usr/bin/python
    import ldap,sys,os,time

    # Address of LDAP Server
    ldapHost = “ldap://YOUR_SERVER:389”

    #DN and Password of user to bind to AD with
    user = “CN=Administrador,CN=Users,DC=domain,DC=com”
    password = “XXXXXXX”

    fqdn = “domain.com” # FQDN of Zimbra Domain Configured

    filter = “sn=*”

    pathtozmprov=”/opt/zimbra/bin/zmprov”

    #————–END VAR——————–
    groupName = str(sys.argv[1])
    baseDN = str(sys.argv[2])
    f = os.popen(pathtozmprov +’ -l gaa ‘)
    zmprovgaa = []
    zmprovgaa = f.readlines()

    try:
    l = ldap.initialize(ldapHost)
    l.simple_bind_s(user, password)
    result = l.search_s(baseDN, ldap.SCOPE_SUBTREE,”cn=*”)
    delete_group = pathtozmprov + ” ddl ” + groupName + “@” + fqdn
    create_group = pathtozmprov + ” cdl ” + groupName + “@” + fqdn
    populate_group = pathtozmprov + ” adlm ” + groupName + “@” + fqdn

    for resultado in result:
    result_dn = resultado[0]
    result_attrs = resultado[1]
    for member in result_attrs[“member”]:
    result2 = l.search_s(member, ldap.SCOPE_SUBTREE,”cn=*”,[‘mail’])
    populate_group = populate_group + ” ” + str(result2).split(‘:’,2)[1][3:-5]

    sys.stdout.flush()

    os.system (delete_group)
    print(delete_group)
    os.system (create_group)
    print(create_group)
    os.system (populate_group)
    print(populate_group)

    except ldap.LDAPError, error_message:
    print error_message

    l.unbind_s()

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.