GNU Mailutils Manual (split by section):   Section:   Chapter:FastBack: Programs   Up: Programs   FastForward: Libraries   Contents: Table of ContentsIndex: Function Index

3.11 maidag

Editor’s note:

The information in this node may be obsolete or otherwise inaccurate. This message will disappear, once this node revised.

The name ‘maidag’ stands for Mail delivery agent. It is a general-purpose MDA offering a rich set of features. It can operate both in traditional mode, reading the message from its standard input, and in LMTP mode. Maidag is able to deliver mail to any mailbox format, supported by GNU Mailutils. These formats, among others, include ‘smtp://’, ‘prog://’ and ‘sendmail://’ which are equivalent to forwarding a message over SMTP to a remote node. Thus, maidag supersedes both mail.local and mail.remote utilities from GNU Mailutils versions prior to 2.0.

Maidag is also able to process incoming messages using Sieve, Scheme or Python scripts and, based on results of this processing, to take a decision on whether to actually deliver and where to deliver them. Due to its extensive scripting facilities, maidag offers much more flexibility than other popular MDAs, such as procmail.

3.11.1 Using maidag with Sendmail.

When used as a MDA with Sendmail, maidag must be invoked from the local mailer definition in the file. It must have the following flags set: ‘lswS’. These mean: the mailer is local, quote characters should be stripped off the address before invoking the mailer, the user must have a valid account on this machine and the userid should not be reset before calling the mailer. Additionally, the flags ‘fn’ may be specified to allow maidag to generate the usual ‘From ’ envelope instead of the one supplied by sendmail.

If you wish to use maidag with non-local authentication, such as SQL or LDAP, you also need to remove the ‘w’ flag, since in that case the user is not required to have a valid account on the machine that runs sendmail.

Here is an example of mailer definition in

Mlocal, P=/usr/local/sbin/maidag,
        S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
        A=mail $u

To define local mailer in ‘mc’ source file, it will suffice to set:

define(`LOCAL_MAILER_PATH', `/usr/local/sbin/maidag')
define(`LOCAL_MAILER_ARGS', `mail $u')

3.11.2 Using maidag with Exim.

Using maidag with Exim is quite straightforward. The following example illustrates the definition of the appropriate transport and director in exim.conf:

# transport
  driver = pipe
  command = /usr/local/sbin/maidag $local_part
# director
  driver = localuser
  transport = maidag_pipe

3.11.3 Using maidag with MeTA1.

MeTA1 ( communicates with the delivery agent using LMTP.

LMTP mode is enabled in maidag by the ‘lmtp yes’ statement. The socket to listen on must be specified using server statement (see Server Settings). For the purposes of this section, let’s suppose maidag will listen on a UNIX socket /var/spool/meta1/lmtpsock. Then, the following (minimal) maidag configuration will do the job:

# Start in LMTP mode.
lmtp yes;
# Run as daemon.
mode daemon;
# Switch to this group after startup.
group meta1c;
# Configure server:
server unix:///var/spool/meta1/lmtpsock {
  transcript no;

To configure MeTA1 to use this socket, add the following statement to the ‘smtpc’ section in /etc/meta1/meta1.conf:


3.11.4 Mailbox Quotas

Mailbox quota is a limit on the size of the mailbox. When a mailbox size reaches this limit, maidag stops accepting messages for this recipient and returns an error condition to the sender. The error code is accompanied by the following error message:

user: mailbox quota exceeded for this recipient

Furthermore, if accepting the incoming message would make the mailbox size exceed the quota, such a message will be rejected as well. In this case, the error message is:

user: message would exceed maximum mailbox size for this recipient

In both cases, the default return code will be ‘service unavailable’ (corresponding to the SMTP return code ‘550’), unless the following statement is present in the maidag configuration file:

exit-quota-tempfail yes;

in which case a temporary error will be returned.

The mailbox quota can be retrieved from the following sources:

  1. Authentication method.
  2. DBM file.
  3. SQL database. Keeping Quotas in DBM File

To use DBM quota database, GNU Mailutils must be compiled with one of the following command line options: --with-gdbm, --with-berkeley-db, --with-ndbm, --with-tokyocabinet, or --with-kyotocabinet. Examine the output of maidag --show-config-options, if not sure.

The quota database should have the following structure:


Key represents the user name. Special key ‘DEFAULT’ means default quota value, i.e. the one to be used if the user is not explicitly listed in the database.


Mailbox quota for this user. If it is a number, it represents the maximum mailbox size in bytes. A number may optionally be followed by ‘kb’ or ‘mb’, meaning kilobytes and megabytes, respectively.

A special value ‘NONE’ means no mailbox size limit for this user.

Here is an example of a valid quota database

# Default quota value:
DEFAULT         5mb

# Following users have unlimited mailbox size
root            NONE
smith           NONE

# Rest of users
plog            26214400
karin           10mB

To use the DBM quota database, specify its absolute name using quota-db configuration statement, e.g.:

quota-db /etc/mail/quota.db; Keeping Quotas in SQL Database

Configuration statement quota-query allows to specify a special query to retrieve the quota from the database. Currently (as of mailutils version 3.5) it is assumed that this table can be accessed using the credentials set in ‘sql’ configuration statement (see SQL Statement).

For example, suppose you have the following quota table:

create table mailbox_quota (
  user_name varchar(32) binary not null,
  quota int,
  unique (user_name)

To retrieve user quota the following query can be used:

SELECT quota FROM mailbox_quota WHERE user_name='${user}'

There are no special provisions for specifying group quotas, similar to ‘DEFAULT’ in DBM databases. This is because group quotas can easily be implemented using SQL language. Maidag always uses the first tuple from the set returned by mailbox quota query. So, you may add a special entry to the mailbox_quota table that would keep the group quota. In the discussion below we assume that the user_name column for this entry is lexicographically less than any other user name in the table. Let’s suppose the group quota name is ‘00DEFAULT’. Then the following query:

SELECT quota
FROM mailbox_quota
WHERE user_name IN ('${user}','00DEFAULT')
ORDER BY user_name DESC

will return two tuples if the user is found in mailbox_quota. Due to ORDER statement, the first tuple will contain the quota for the user, which will be used by maidag. On the other hand, if the requested user name is not present in the table, the above query will return a single tuple containing the group quota.

The following configuration statement instructs maidag to use this query for retrieving the user quota:

quota-query "SELECT quota "
            "FROM mailbox_quota "
            "WHERE user_name IN ('${user}','00DEFAULT') "
            "ORDER BY user_name DESC";

3.11.5 Maidag Scripting

Maidag can use global or per-user mail filters to decide whether to deliver the message, and where to deliver it. As of Mailutils version 3.5, such mail filters may be written in the following languages:

Mail filters to use are specified using ‘script’ configuration statement. The following meta-symbols can be used in its argument:


Expands to the recipient home directory.


Expands to the recipient user name.

By default, the filename extension decides which scripting language will be used. User can alter the choice using ‘language’ configuration statement. For example:

language "python"
script "~/.maidag-py-filter" Sieve Maidag Filters

The file name of the Sieve filter to use is specified using ‘script’ configuration statement. For example, the following configuration statement:

script "~/"

instructs maidag to use file in the recipient home directory as a Sieve filter.

Normal message delivery is attempted if execution of the Sieve code ended with keep action (either implicit or explicit).

Other Sieve actions are executed as described in Actions. For example, to deliver message to another mailbox, use the fileinto action.

Any modifications to headers or body of the message performed by the Sieve code will be visible in the delivered message. Scheme Maidag Filters

The file name of the Scheme mail filter is specified using ‘script’ configuration statement. For example, the following configuration statement:

script "~/.maidag.scm"

instructs ‘maidag’ to use file ‘.maidag.scm’ in the recipient home directory as a Scheme filter. Python Maidag Filters

The file name of the Python mail filter is specified using ‘script’ configuration statement. For example, the following configuration statement:

script "~/"

instructs ‘maidag’ to use file ‘’ in the recipient home directory as a Python filter.

A simple example of a mail filter written in Python:

from mailutils import *
import maidag
import re

msg = message.Message (maidag.message)
hdr = msg.header

    if 'List-Post' in hdr and 'Received' in hdr \
       and hdr['Received'].find ('') != -1:

        # check envelope's sender address
        m = (r'([\w\-]+)-bounces\+([\w]+)=.*',
                       msg.envelope.get_sender ())
        if m:
            lbox = (1)
            user = (2)
            # open destination mailbox and append message
            dst = mailbox.MailboxDefault ('~/Mail/%s' % lbox)
            dst.append_message (msg)
            dst.close ()
            # set deleted flag so maidag will not deliver msg elsewhere
            msg.attribute.set_deleted ()
except Exception:

3.11.6 Forwarding

Forward file is a special file in the user’s home directory that contains the email address of the mailbox where the user wants to forward his mail. Normally, forward files are processed by MTA. However, there are some MTA that lack this feature. One of them is MeTA1.

Maidag provides a forwarding feature that is useful to compensate the lack of it.

Name of the forward file is given using forward-file configuration statement. A common usage is:

forward-file .forward;

The forward file is always searched in the recipient home directory.

Before actually using the file, a number of safety checks are performed on it. If the file fails to pass one of these checks, no forwarding is performed and the message is delivered as usual. These checks can be configured using forward-file-checks statement. Its argument is a list of the following keywords:


The file must not be group writable.


The file must not be world writable.


The file cannot be a symlink in a writable directory.


The file cannot reside in a group writable directory.


The file cannot reside in a world writable directory.


All of the above checks.

The default is ‘forward-file-checks all’.

Each of these keywords may be prefixed by ‘no’ to disable this particular check. For example:

forward-file-checks (nodir_iwoth, nodir_iwgrp);

3.11.7 Delivering Messages to a URL.

When invoked with the --url command line option, maidag treats its arguments as a list of mailbox URLs and attempts to deliver the message to each of them.

For example:

$ maidag --url maildir:///home/smith/Mail

3.11.8 Remote Mailbox Delivery

Maidag can be used to deliver mail to remote mailboxes, such as ‘imap’ or ‘smtp’. If the mailbox URL is ‘smtp’ or ‘sendmail’, the message is actually forwarded over SMTP to the remote node, so maidag acts as a message transfer agent. For example:

$ maidag --url smtp://

This command line will send the message to the machine ‘’ using port ‘24’ (private mail system).

The ‘prog’ mailbox may be of special use. Delivering to this mailbox results in invoking the specified command with the given arguments and passing the message to its standard input. There are two ways to specify a ‘prog’ mailbox:


Here, program is the absolute pathname of the program binary, and args are its arguments, separated by ‘&’ signs.

|program args

In this notation, args are command line arguments separated by white space.

In both cases, args do not include argv[0].

The ‘prog’ mailbox may be used, in particular, to implement mailing lists with MeTA1.

For example, suppose that the maidag configuration contains:

auth {
  authorization sql:system;
  authentication generic:system;

sql {
  interface mysql;
  db mail;
  getpwnam "SELECT user as name, mailbox, "
           "'x' as passwd, 500 as uid, 2 as gid, "
           "'/nonexistent' as dir, '/sbin/nologin' as shell "
           "FROM userdb "
           "WHERE user='${user}'";

Then, the following entries in the ‘userdb’ table implement mailman@yourdomain mailing list:

mysql> select * from userdb;
| user                | mailbox                               |
| mailman             | |/usr/bin/mailman post mailman        |
| mailman-admin       | |/usr/bin/mailman admin mailman       |
| mailman-bounces     | |/usr/bin/mailman bounces mailman     |
| mailman-confirm     | |/usr/bin/mailman confirm mailman     |
| mailman-join        | |/usr/bin/mailman join mailman        |
| mailman-leave       | |/usr/bin/mailman leave mailman       |
| mailman-owner       | |/usr/bin/mailman owner mailman       |
| mailman-request     | |/usr/bin/mailman request mailman     |
| mailman-subscribe   | |/usr/bin/mailman subscribe mailman   |
| mailman-unsubscribe | |/usr/bin/mailman unsubscribe mailman |

3.11.9 Maidag Configuration File Summary

The behavior of maidag is affected by the following configuration statements:

debugSee debug statement.
mailboxSee mailbox statement.
lockingSee locking statement.
pamSee pam statement.
sqlSee sql statement.
virtdomainSee virtdomain statement.
radiusSee radius statement.
ldapSee ldap statement.
authSee auth statement.
mailerSee mailer statement.
serverSee Server Settings. Used only in LMTP mode.
aclSee acl statement.
tcp-wrappersSee tcp-wrappers statement.
Maidag Config: ex-multiple-delivery-success bool

In case of multiple delivery, exit with code 0 if at least one delivery has succeeded.

Maidag Config: ex-quota-tempfail bool

Indicate temporary failure if the recipient is over his mail quota. By default, permanent failure is returned. See Mailbox Quotas.

Maidag Config: quota-db file

Set the name of DBM quota database file. See DBM Quotas.

Maidag Config: sieve-filter pattern

Set file name or name pattern of the Sieve filter file. See Sieve Maidag Filters.

Maidag Config: message-id-header name

When logging Sieve actions, identify messages by the value of this header.

Maidag Config: guile-filter pattern

File name or name pattern for Guile filter file. See Scheme Maidag Filters.

Maidag Config: debug flags

Set additional debugging flags. Valid flags are:


Print guimb stack traces.


Enable sieve trace (MU_SIEVE_DEBUG_TRACE).


Enable sieve instructions trace (MU_SIEVE_DEBUG_INSTR).


Log executed Sieve actions.

Maidag Config: stderr bool

Log to stderr instead of syslog.

Maidag Config: forward-file file

Process forward file file. See Forwarding.

Maidag Config: forward-file-checks list

Configure safety checks for the forward file. See forward-file-checks.

Maidag Config: lmtp bool

Run in LMTP mode.

Maidag Config: group list

In LMTP mode, retain supplementary groups from list.

Maidag Config: listen url

In LMTP mode, listen on url. Valid URLs are: ‘tcp://host:port’ (note that port is mandatory), ‘file://socket-file-name’ or ‘socket://socket-file-name’.

Maidag Config: reuse-address bool

Reuse existing address (LMTP mode). Default is ‘yes’.

GNU Mailutils Manual (split by section):   Section:   Chapter:FastBack: Programs   Up: maidag   FastForward: Libraries   Contents: Table of ContentsIndex: Function Index