Post

Zimbra Distribution Lists with Ansible

Unfortunately there is no Zimbra module for Ansible but with the zmprov command it’s still possible to do some Ansible magic.

Users

A list of users for the distribution lists.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
users:
  ### BEHAVIOUR
  - name: john
    first_name: 'john'
    last_name: 'doe'
    department: 'it'

  - name: jane
    first_name: 'jane'
    last_name: 'doe'
    department: 'it'

  - name: janie
    first_name: 'janie'
    last_name: 'doe'
    department: 'hardware'

    # this user won't go into the dl
  - name: johnny
    enabled: false
    first_name: 'johnny'
    last_name: 'doe'
    department: 'hardware'

Zimbra Distribution Lists

Every department (it,hardware) gets a distribution list with the members.

There will be also a all dl where all users are going in.

The selectattr('enabled', 'undefined') will filter out disabled users.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
zimbra_dl:
  # put all users in the "all" dl
  - name: all
    description: 'all employees'
    members:
      - "{{ users | selectattr('enabled', 'undefined') | map(attribute='name') | list }}"
  # it
  - name: it
    description: 'it department'
    members:
      - "{{ users | selectattr('enabled', 'undefined') | selectattr('department', 'equalto', 'it') | map(attribute='name') | list }}"
    mail_alias:
      - 'root@example.com'
  # hardware
  - name: it
    description: 'it department'
    members:
      - "{{ users | selectattr('enabled', 'undefined') | selectattr('department', 'equalto', 'hardware') | map(attribute='name') | list }}"

Ansible task

This looks a little bit messy but not all zmprov commands are consistent with the output format and their parameters.

Tasks are doing following:

  • Get all Distribution Lists
  • Create if not present
  • Get config of the lists
  • Configure initial settings
  • Add members
  • An optional array of mail aliases
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
---
- block:
    ### DISTRIBUTION LISTS (non-dynamic)
    - name: get all distribution lists
      command: "./zmprov gadl"
      args:
        chdir: "{{ zimbra_data_dir }}/bin/"
      register: dl_result
      changed_when: false

    - name: create distribution lists
      command: "./zmprov cdl {{ item.name }}@{{ item.domain | default('example.com') }}"
      args:
        chdir: "{{ zimbra_data_dir }}/bin/"
      with_items: "{{ zimbra_dl | default([]) | flatten }}"
      when: "'{{ item.name }}@{{ item.domain | default('example.com') }}' not in dl_result.stdout_lines"
      # optional to make the output less verbose
      loop_control:
        label: "{{ item.name }}"

    - name: get distribution lists config
      command: "./zmprov gdl {{ item.name }}@{{ item.domain | default('example.com') }}"
      args:
        chdir: "{{ zimbra_data_dir }}/bin/"
      with_items: "{{ zimbra_dl | default([]) }}"
      register: dl_config_result
      changed_when: false
      loop_control:
        label: "{{ item.name }}"

    - name: configure distribution lists
      command: >
        ./zmprov mdl "{{ item.item.name }}"@"{{ item.item.domain | default('example.com') }}"
        displayName "{{ item.item.description }}"
        zimbraDistributionListSubscriptionPolicy "{{ item.item.subscription_policy | default('reject') | upper }}"
        zimbraDistributionListUnsubscriptionPolicy "{{ item.item.unsubscription_policy | default('reject') | upper }}"
      args:
        chdir: "{{ zimbra_data_dir }}/bin/"
      with_items: "{{ dl_config_result.results }}"
      when: item.item.description not in item.stdout
      loop_control:
        label: "{{ item.item.name }}"

    - name: configure distribution list members
      command: "./zmprov adlm {{ item.item.name }}@{{ item.item.domain | default('example.com') }} {{ item.item.members | flatten | join('@example.com ') ~ '@' ~ 'example.com' }}"
      args:
        chdir: "{{ zimbra_data_dir }}/bin/"
      with_items: "{{ dl_config_result.results }}"
      when: item.item.members | flatten | map('regex_replace', '$', '@example.com') | list | sort | join('\n') not in item.stdout
      loop_control:
        label: "{{ item.item.name }}"

    ### ALIAS
    - name: configue distribution lists alias
      command: "./zmprov adla {{ item.0.item.name }}@{{ item.0.item.domain | default('example.com') }} {{ item.1 }}"
      args:
        chdir: "{{ zimbra_data_dir }}/bin/"
      with_subelements:
        - "{{ dl_config_result.results }}"
        - item.mail_alias
        - flags:
          skip_missing: true
      when:
        - item.1 is defined
        - item.1 not in item.0.stdout
      loop_control:
        label: "{{ item.0.item.name }}"

  become: true
  become_user: "{{ zimbra_user }}"

Tested with:

  • Ansible 2.5.7
  • Zimbra 8.7.11
This post is licensed under CC BY 4.0 by the author.