GNU Mailutils |
|
General-Purpose Mail Package |
Official GNU Software |
GNU local mail delivery agent reads a message from its standard input
and delivers it to one or more local recipients listed in the command
line. When we speak about local recipients, we mean that these
are system users that are known to the system that runs mda
.
However, the mailboxes of these users can be local as well as remote
ones. mda
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.
Mda
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,
mda
offers much more flexibility than other popular
MDAs.
mda
with Sendmail.When used with Sendmail, mda
must be invoked from the local
mailer definition in the sendmail.cf file. The flags
‘lswS’ must be set for the mailer. 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 ‘fn’ flags may be specified to allow
mda
to generate the usual ‘From ’ envelope instead
of the one supplied by sendmail
.
If you wish to use mda
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 sendmail.cf
Mlocal, P=/usr/local/sbin/mda, F=lsDFMAw5:/|@qSPfhn9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, T=DNS/RFC822/X-Unix, A=mail $u
To define local mailer in ‘mc’ source file, it will suffice to set:
define(`LOCAL_MAILER_PATH', `/usr/local/sbin/mda') define(`LOCAL_MAILER_ARGS', `mail $u')
mda
with Exim.Using mda
with Exim is quite straightforward. The
following example illustrates the definition of the appropriate transport
and director in exim.conf:
# transport mda_pipe: driver = pipe command = /usr/local/sbin/mda $local_part return_path_add delivery_date_add envelope_to_add # director mda: driver = localuser transport = mda_pipe
mda
with MeTA1.MeTA1 (http://meta1.org) communicates with the delivery agent
using LMTP. Instead of using mda
you will have to
start the LMTP daemon lmtpd
and configure MeTA1 to
communicate with it. See MeTA1-lmtpd, for details.
Mailbox quota is a limit on the size of the mailbox. When a
mailbox size reaches this limit, mda
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:
quota { exit-tempfail yes; }
in which case a temporary error will be returned.
The mailbox quota can be retrieved from the following sources:
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 mda --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 quota database in text form:
# 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
the database
configuration statement in the quota
section, e.g.:
quota { database /etc/mail/quota.db; }
User quotas can be kept in an SQL table as well. Currently (as of mailutils version 3.14) 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}'
To define this query use the sql-query
statement:
quota { sql-query "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. Mda
always uses the first tuple from the set returned by mailbox quota
query. So, you can 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 quota for the user, which will be used by
mda
. 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 { sql-query "SELECT quota " "FROM mailbox_quota " "WHERE user_name IN ('${user}','00DEFAULT') " "ORDER BY user_name DESC"; }
mda
Mda
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.14, 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:
script { language python; pattern "~/.maidag-py-filter"; }
The file name of the Sieve filter to use is specified using ‘script’ configuration statement. For example, the following configuration statement:
script { pattern "~/.maidag.sv"; }
instructs maidag
to use file .maidag.sv 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.
The file name of the Scheme mail filter is specified using ‘script’ configuration statement. For example, the following configuration statement:
script { pattern "~/.maidag.scm"; }
instructs mda
to use file .maidag.scm in the
recipient home directory as a Scheme filter.
The file name of the Python mail filter is specified using ‘script’ configuration statement. For example, the following configuration statement:
script { pattern "~/.maidag.py"; }
instructs mda
to use the file .maidag.py 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 try: if 'List-Post' in hdr and 'Received' in hdr \ and hdr['Received'].find ('fencepost.gnu.org') != -1: # check envelope's sender address m = re.search (r'([\w\-]+)-bounces\+([\w]+)=.*', msg.envelope.get_sender ()) if m: lbox = m.group (1) user = m.group (2) # open destination mailbox and append message dst = mailbox.MailboxDefault ('~/Mail/%s' % lbox) dst.open ('ac') dst.append_message (msg) dst.close () # set deleted flag so maidag will not deliver msg elsewhere msg.attribute.set_deleted () except Exception: pass
A 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.
Mda
provides a forwarding feature that is useful to
compensate the lack of it. This feature is controlled by the
forward
section in the configuration file:
forward { # Process forward file. file name; # Configure safety checks for the forward file. file-checks (list); }
The name of the forward file is given by the file
statement in the forward
section. A common usage is:
forward { file .forward; }
The forward file is always searched in the recipient home directory.
Before actually using the forward 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 are configured using the forward.file-checks
statement:
forward { file .forward; file-checks (list); }
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 ‘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); file .forward; }
The behavior of mda
is affected by the following configuration
statements:
Statement | Reference |
---|---|
debug | See debug statement. |
mailbox | See mailbox statement. |
locking | See locking statement. |
pam | See pam statement. |
sql | See sql statement. |
virtdomain | See virtdomain statement. |
radius | See radius statement. |
ldap | See ldap statement. |
auth | See auth statement. |
mailer | See mailer statement. |
If bool is true, log to standard error instead of syslog.
This section contains general delivery settings:
deliver { domain string; exit-multiple-delivery-success arg; };
Default email domain.
In case of multiple delivery, exit with code 0 if at least one delivery succeeded.
Controls the forwarding support:
forward { file name; file-checks (list); }
Defines the name of the forward file. E.g.:
forward { file .forward; }
See Forwarding, for a detailed description.
Configures safety checks to be performed on the forward file prior to using it. See Forwarding, for a detailed description.
This section configures mail quota support. See Mailbox Quotas, for a detailed description.
quota { database name; sql-query query; exit-tempfail bool; }
Sets the name of the quota database in DBM format. See DBM Quotas.
If the quotas are kept in a SQL table, this statement defines the SQL query to retrieve the quota for a given user name. See SQL Quotas.
By default, if a message cannot be delivered because the user has
exceeded its mail quota, or its delivery would cause it to be
exceeded, MDA
exits with the ‘service unavailable’
status, which causes MTA to return the 550 code. If
exit-tempfail
is set to true, it will return a temporary error
instead.
Controls scripting. See MDA Scripting.
script { language lang; pattern glob; }
Defines the language that is used for scripting. Allowed values for lang are: ‘sieve’, ‘scheme’, or ‘python’. See scripting language.
Defines the pattern for the script file name. The ‘~’ at the begiining of the pattern will be replaced with the name of the home directory of the recipient user. The ‘%u’ in pattern will be replaced with the recipient user name, and ‘%h’ with the home directory for that user.
This subsection explains how to implement mailing lists in
mda
using the ‘prog’ mailbox scheme.
Delivery to the ‘prog’ 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.
In this notation, args are command line arguments separated by white space.
In both cases, args do not include argv[0]
.
The ‘prog’ mailbox can be used to implement mailing lists.
For example, suppose that the mda
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 the 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 | +---------------------+---------------------------------------+
This document was generated on January 2, 2022 using makeinfo.
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.