Mailu command line

Managing domains, users and aliases can be done from CLI using the commands:

  • alias

  • alias-delete

  • domain

  • password

  • user

  • user-import

  • user-delete

  • config-update

  • config-export

  • config-import


docker compose exec admin flask mailu alias foo ","


docker compose exec admin flask mailu alias-delete


docker compose exec admin flask mailu domain


docker compose exec admin flask mailu password myuser 'password123'


docker compose exec admin flask mailu user myuser 'password123'


primary difference with simple user command is that password is being imported as a hash - very useful when migrating users from other systems where only hash is known.

docker compose run --rm admin flask mailu user-import myuser '$6$51ebe0cb9f1dab48effa2a0ad8660cb489b445936b9ffd812a0b8f46bca66dd549fea530ce' 'SHA512-CRYPT'


Although the action is called “user-delete” the user is only deactivated by default. This is due to the fact mailu does not remove user-data (emails and webmail contacts) when a user is deleted. Add the flag -r to really delete the user after you have deleted user-data manually.

docker compose exec admin flask mailu user-delete


The sole purpose of this command is for importing users/aliases in bulk and synchronizing DB entries with external YAML template:

cat mail-config.yml | docker compose exec -T admin flask mailu config-update --delete-objects

where mail-config.yml looks like:

  - localpart: foo
    password_hash: klkjhumnzxcjkajahsdqweqqwr

  - localpart: alias1
    destination: ","

without --delete-object option config-update will only add/update new values but will not remove any entries missing in provided YAML input.


following are additional parameters that could be defined for users:

  • comment

  • quota_bytes

  • global_admin

  • enable_imap

  • enable_pop

  • forward_enabled

  • forward_destination

  • reply_enabled

  • reply_subject

  • reply_body

  • displayed_name

  • spam_enabled

  • spam_mark_as_read

  • spam_threshold


additional fields:

  • wildcard


The purpose of this command is to export the complete configuration in YAML or JSON format.

 $ docker compose exec -T admin flask mailu config-export --help

Usage: flask mailu config-export [OPTIONS] [FILTER]...

  Export configuration as YAML or JSON to stdout or file

  -f, --full                  Include attributes with default value.
  -s, --secrets               Include secret attributes (dkim-key, passwords).
  -d, --dns                   Include dns records.
  -c, --color                 Force colorized output.
  -o, --output-file FILENAME  Save configuration to file.
  -j, --json                  Export configuration in json format.
  -?, -h, --help              Show this message and exit.

Only non-default attributes are exported. If you want to export all attributes use --full. If you want to export plain-text secrets (dkim-keys, passwords) you have to add the --secrets option. To include dns records (mx, spf, dkim and dmarc) add the --dns option.

By default all configuration objects are exported (domain, user, alias, relay). You can specify filters to export only some objects or attributes (try: user or Attributes explicitly specified in filters are automatically exported: there is no need to add --secrets or --full.

$ docker compose exec admin flask mailu config-export --output-file mail-config.yml

$ docker compose exec -T admin flask mailu config-export domain.dns_mx domain.dns_spf

$ docker compose exec -T admin flask mailu config-export user.spam_threshold


This command imports configuration data from an external YAML or JSON source.

 $ docker compose exec -T admin flask mailu config-import --help

Usage: flask mailu config-import [OPTIONS] [FILENAME|-]

  Import configuration as YAML or JSON from stdin or file

  -v, --verbose   Increase verbosity.
  -s, --secrets   Show secret attributes in messages.
  -q, --quiet     Quiet mode - only show errors.
  -c, --color     Force colorized output.
  -u, --update    Update mode - merge input with existing config.
  -n, --dry-run   Perform a trial run with no changes made.
  -?, -h, --help  Show this message and exit.

To pass stdin correctly you have to use the -T option:

docker compose exec -T admin flask mailu config-import -nv < mail-config.yml

mail-config.yml contains the configuration and looks like this:

  - name:

  - email:
    password_hash: '$2b$12$...'
    hash_scheme: MD5-CRYPT

  - email:

  - name:
    comment: test

config-import shows the number of created/modified/deleted objects after import. To suppress all messages except error messages use --quiet. By adding the --verbose switch the import gets more detailed and shows exactly what attributes changed. In all log messages plain-text secrets (dkim-keys, passwords) are hidden by default. Use --secrets to log secrets. If you want to test what would be done when importing without committing any changes, use --dry-run.

By default config-import replaces the whole configuration. --update allows to modify the existing configuration instead. New elements will be added and existing elements will be modified. It is possible to delete a single element or prune all elements from lists and associative arrays using a special notation:

Delete what?



specific array object

- -key: id

- -name:

specific list item

- -id


all remaining array objects

- -key: null

- -email: null

all remaining list items

- -prune-

- -prune-

The -key: null notation can also be used to reset an attribute to its default. To reset spam_threshold to it’s default 80 use -spam_threshold: null.

A new dkim key can be generated when adding or modifying a domain, by using the special value dkim_key: -generate-.

This is a complete YAML template with all additional parameters that can be defined:

  - name:
      - alternative.tld
    comment: ''
    dkim_key: ''
    max_aliases: -1
    max_quota_bytes: 0
    max_users: -1
    signup_enabled: false

  - email:
    comment: ''
    displayed_name: 'Postmaster'
    enable_imap: true
    enable_pop: false
    enabled: true
      - id: 1
        comment: 'test fetch'
        error: null
        keep: true
        last_check: '2020-12-29T17:09:48.200179'
        password: 'secret'
        hash_password: true
        port: 993
        protocol: imap
        tls: true
        username: fetch-user
    forward_enabled: true
    forward_keep: true
    global_admin: true
    password: '$2b$12$...'
    hash_password: true
    quota_bytes: 1000000000
    reply_body: ''
    reply_enabled: false
    reply_enddate: '2999-12-31'
    reply_startdate: '1900-01-01'
    reply_subject: ''
    spam_enabled: true
    spam_mark_as_read: true
    spam_threshold: 80
      - id: 1
        comment: email-client
        password: '$5$rounds=1$...'

  - email:
    comment: ''
    wildcard: false

  - name:
    comment: ''