summaryrefslogtreecommitdiff
path: root/doc/texinfo/programs/mda.texi
blob: 6bc007b59b61859cbd459c4f143065abd8e09131 (plain)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
@c This is part of the GNU Mailutils manual.
@c Copyright (C) 1999-2020 Free Software Foundation, Inc.
@c See file mailutils.texi for copying conditions.
@comment *******************************************************************
@pindex mda
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 @i{local} recipients, we mean that these
are system users that are known to the system that runs @command{mda}.
However, the mailboxes of these users can be local as well as remote
ones.  @command{mda} is able to deliver mail to any mailbox format,
supported by GNU Mailutils.  These formats, among others, include
@samp{smtp://}, @samp{prog://} and @samp{sendmail://} which are
equivalent to forwarding a message over @acronym{SMTP} to a remote
node.

@command{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,
@command{mda} offers much more flexibility than other popular
@acronym{MDA}s.

@menu
* Sendmail-mda::         Using @command{mda} with Sendmail.
* Exim-mda::             Using @command{mda} with Exim.
* MeTA1-mda::            Using @command{mda} with MeTA1.
* Mailbox Quotas::
* MDA Scripting::
* Forwarding::
* Conf-mda::             @command{mda} Configuration File Summary.
* Mailing lists::        How to implement Mailing Lists with @command{mda}.
@end menu

@node Sendmail-mda
@subsection Using @command{mda} with Sendmail.
@cindex Sendmail
When used with Sendmail, @command{mda} must be invoked from the local
mailer definition in the @file{sendmail.cf} file.  The flags
@samp{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 @samp{fn} flags may be specified to allow 
@command{mda} to generate the usual @samp{From } envelope instead
of the one supplied by @command{sendmail}. 

If you wish to use @command{mda} with non-local authentication,
such as @acronym{SQL} or @acronym{LDAP}, you also need to remove the
@samp{w} flag, since in that case the user is not required to have a
valid account on the machine that runs @command{sendmail}.

Here is an example of mailer definition in @file{sendmail.cf}

@example 
Mlocal, P=/usr/local/sbin/mda,
        F=lsDFMAw5:/|@@qSPfhn9,
        S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
        T=DNS/RFC822/X-Unix,
        A=mail $u
@end example

To define local mailer in @samp{mc} source file, it will suffice to
set:

@example
define(`LOCAL_MAILER_PATH', `/usr/local/sbin/mda')
define(`LOCAL_MAILER_ARGS', `mail $u')
@end example

@node Exim-mda
@subsection Using @command{mda} with Exim.
@cindex Exim

Using @command{mda} with Exim is quite straightforward.  The
following example illustrates the definition of the appropriate transport
and director in @file{exim.conf}:

@example
# 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
@end example

@node MeTA1-mda
@subsection Using @command{mda} with MeTA1.
@cindex MeTA1
MeTA1 (@uref{http://meta1.org}) communicates with the delivery agent
using @acronym{LMTP}.  Instead of using @command{mda} you will have to
start the @acronym{LMTP} daemon @command{lmtpd} and configure MeTA1 to
communicate with it.  @xref{MeTA1-lmtpd}, for details.

@node Mailbox Quotas
@subsection Mailbox Quotas

@dfn{Mailbox quota} is a limit on the size of the mailbox.  When a
mailbox size reaches this limit, @command{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:

@example
@var{user}: mailbox quota exceeded for this recipient
@end example

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:

@example
@var{user}: message would exceed maximum mailbox size for this recipient
@end example

In both cases, the default return code will be @samp{service
unavailable} (corresponding to the @acronym{SMTP} return code
@samp{550}), unless the following statement is present in the
@command{maidag} configuration file:

@example
quota @{
  exit-tempfail yes;
@}
@end example

@noindent
in which case a temporary error will be returned.

The mailbox quota can be retrieved from the following sources:

@enumerate 1
@item Authentication method.
@item @acronym{DBM} file.
@item @acronym{SQL} database.
@end enumerate

@menu
* DBM Quotas::          Keeping Quotas in DBM File.
* SQL Quotas::          Keeping Quotas in SQL Database.
@end menu

@node DBM Quotas
@subsubsection Keeping Quotas in DBM File

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

The quota database should have the following structure:

@table @asis
@item Key
Key represents the user name.  Special key @samp{DEFAULT} means default
quota value, i.e. the one to be used if the user is not explicitly
listed in the database.

@item Value
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
@samp{kb} or @samp{mb}, meaning kilobytes and megabytes, respectively.

A special value @samp{NONE} means no mailbox size limit for this user.
@end table

Here is an example of a quota database in text form:

@example
# Default quota value:
DEFAULT         5mb

# Following users have unlimited mailbox size
root            NONE
smith           NONE

# Rest of users
plog            26214400
karin           10mB
@end example

To use the @acronym{DBM} quota database, specify its absolute name using
the @code{database} configuration statement in the @code{quota}
section, e.g.:

@example
quota @{
  database /etc/mail/quota.db;
@}  
@end example

@node SQL Quotas
@subsubsection Keeping Quotas in SQL Database

User quotas can be kept in an SQL table as well.  Currently (as of mailutils
version @value{VERSION}) it is assumed that this table can be accessed
using the credentials set in @samp{sql} configuration statement
(@pxref{SQL Statement}).

For example, suppose you have the following quota table:

@example
create table mailbox_quota (
  user_name varchar(32) binary not null,
  quota int,
  unique (user_name)
);
@end example

@noindent

To retrieve user quota the following query can be used:

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

To define this query use the @code{sql-query} statement:

@example
quota @{
  sql-query "SELECT quota "
            "FROM mailbox_quota "
            "WHERE user_name='$@{user@}'";
@}
@end example

There are no special provisions for specifying group quotas, similar to
@samp{DEFAULT} in @acronym{DBM} databases.  This is because group quotas can
easily be implemented using @acronym{SQL} language.  @command{Mda}
always uses the first tuple from the set returned by mailbox quota
query.  So, you can add a special entry to the @code{mailbox_quota}
table that would keep the group quota.  In the discussion below we assume
that the @code{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 @samp{00DEFAULT}.  Then the following query:

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

@noindent
will return two tuples if the user is found in
@code{mailbox_quota}.  Due to @code{ORDER} statement, the first tuple
will contain quota for the user, which will be used by
@command{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 @command{maidag} to
use this query for retrieving the user quota:

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

@node MDA Scripting
@subsection Scripting in @command{mda}
@command{Mda} can use global or per-user @dfn{mail filters} to
decide whether to deliver the message, and where to deliver it.  As of
Mailutils version @value{VERSION}, such mail filters may be written in
the following languages:

@itemize @bullet
@item Sieve
@xref{Sieve Language}.

@item Scheme
@item Python
@end itemize

Mail filters to use are specified using @samp{script} configuration
statement.  The following meta-symbols can be used in its argument:

@table @asis
@item ~
@itemx %h
Expands to the recipient home directory.

@item %u
Expands to the recipient user name.
@end table

@anchor{scripting language}
By default, the filename extension decides which scripting language will
be used.  User can alter the choice using @samp{language} configuration
statement.  For example:

@example
script @{
  language python;
  pattern "~/.maidag-py-filter";
@}  
@end example

@menu
* Sieve MDA Filters::
* Scheme MDA Filters::
* Python MDA Filters::
@end menu

@node Sieve MDA Filters
@subsubsection Sieve MDA Filters
@kwindex script
The file name of the Sieve filter to use is specified using
@samp{script} configuration statement.  For example, the following
configuration statement:

@example
script @{
  pattern "~/.maidag.sv";
@}  
@end example

@noindent
instructs @command{maidag} to use file @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 @code{keep} action (either implicit or explicit).

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

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

@node Scheme MDA Filters
@subsubsection Scheme MDA Filters
@kwindex script
The file name of the Scheme mail filter is specified using
@samp{script} configuration statement.  For example, the following
configuration statement:

@example
script @{
  pattern "~/.maidag.scm";
@}  
@end example

@noindent
instructs @command{mda} to use file @file{.maidag.scm} in the
recipient home directory as a Scheme filter.

@node Python MDA Filters
@subsubsection Python MDA Filters
@kwindex script

The file name of the Python mail filter is specified using
@samp{script} configuration statement.  For example, the following
configuration statement:

@example
script @{
  pattern "~/.maidag.py";
@}  
@end example

@noindent
instructs @command{mda} to use the file @file{.maidag.py} in the
recipient home directory as a Python filter.

@noindent
A simple example of a mail filter written in Python:

@example
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
@end example

@node Forwarding
@subsection Forwarding
@cindex forward
A @dfn{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
@acronym{MTA}.  However, there are some @acronym{MTA} that lack this
feature.  One of them is MeTA1.

@command{Mda} provides a forwarding feature that is useful to
compensate the lack of it.  This feature is controlled by the
@code{forward} section in the configuration file:

@example
forward @{
  # Process forward file.
  file @var{name};
  # Configure safety checks for the forward file.
  file-checks (@var{list});
@}
@end example

@kwindex file, forward
The name of the forward file is given by the @code{file}
statement in the @code{forward} section.  A common usage is:

@example
forward @{
  file .forward;
@}  
@end example

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 @code{forward.file-checks} statement:

@example
forward @{
  file .forward;
  file-checks (@var{list});
@}  
@end example

Its argument is a list of the following keywords:

@table @asis
@item groupwritablefile
@itemx file_iwgrp
The file must not be group writable.

@item worldwritablefile
@itemx file_iwoth
The file must not be world writable.

@item linkedfileinwritabledir
@itemx link
The file cannot be a symlink in a writable directory.

@item fileingroupwritabledir
@itemx dir_iwgrp
The file cannot reside in a group writable directory.

@item fileinworldwritabledir
@itemx dir_iwoth
The file cannot reside in a world writable directory.

@item all
All of the above checks.
@end table

The default is @samp{file-checks all}.

Each of these keywords may be prefixed by @samp{no} to disable this
particular check.  For example:

@example
forward @{
  file-checks (nodir_iwoth, nodir_iwgrp);
  file .forward;
@}  
@end example

@node Conf-mda
@subsection MDA Configuration File Summary

The behavior of @command{mda} is affected by the following configuration
statements:

@multitable @columnfractions 0.3 0.6
@headitem Statement @tab Reference
@item debug         @tab @xref{debug statement}.
@item mailbox       @tab @xref{mailbox statement}.
@item locking       @tab @xref{locking statement}.
@item pam           @tab @xref{pam statement}.
@item sql           @tab @xref{sql statement}.
@item virtdomain    @tab @xref{virtdomain statement}.
@item radius        @tab @xref{radius statement}.
@item ldap          @tab @xref{ldap statement}.
@item auth          @tab @xref{auth statement}.
@item mailer        @tab @xref{mailer statement}.
@end multitable

@deffn {MDA Config} stderr @var{bool}
If @var{bool} is true, log to standard error instead of syslog.
@end deffn

@deffn {MDA Config} deliver @{ ... @}
This section contains general delivery settings:

@example
deliver @{
  domain @var{string};
  exit-multiple-delivery-success @var{arg};
@};
@end example
@end deffn

@deffn {deliver} domain @var{name}
Default email domain.
@end deffn

@deffn {deliver} exit-multiple-delivery-success @var{arg};
In case of multiple delivery, exit with code 0 if at least
one delivery succeeded.
@end deffn


@deffn {MDA Config} forward @{ ... @}
Controls the forwarding support:

@example
forward @{
  file @var{name};
  file-checks (@var{list});
@}
@end example
@end deffn

@deffn {forward} file @var{name}
Defines the name of the forward file.  E.g.:

@example
forward @{
  file .forward;
@}  
@end example

@xref{Forwarding}, for a detailed description.
@end deffn

@deffn {forward} file-checks (@var{list})
Configures safety checks to be performed on the forward file prior to
using it.  @xref{Forwarding}, for a detailed description.
@end deffn

@deffn {MDA Config} quota @{ ... @}
This section configures mail quota support.  @xref{Mailbox Quotas},
for a detailed description.

@example
quota @{
  database @var{name};
  sql-query @var{query};
  exit-tempfail @var{bool};
@}
@end example
@end deffn

@deffn {quota} database @var{name}
Sets the name of the quota database in DBM format.  @xref{DBM Quotas}.
@end deffn

@deffn {quota} sql-query @var{query}
If the quotas are kept in a SQL table, this statement defines the SQL
query to retrieve the quota for a given user name.  @xref{SQL Quotas}.
@end deffn

@deffn {quota} exit-tempfail @var{bool}
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, @command{MDA} exits with the @samp{service unavailable}
status, which causes MTA to return the 550 code.  If
@code{exit-tempfail} is set to true, it will return a temporary error
instead.
@end deffn

@deffn {MDA Config} script @{ ... @}
Controls scripting.  @xref{MDA Scripting}.

@example
script @{
  language @var{lang};
  pattern @var{glob};
@}
@end example
@end deffn

@deffn {script} language @var{lang}
Defines the language that is used for scripting.  Allowed values for
@var{lang} are: @samp{sieve}, @samp{scheme}, or @samp{python}.
@xref{scripting language}.
@end deffn

@deffn {script} pattern @var{pat}
Defines the pattern for the script file name.  The @samp{~} at the
begiining of the pattern will be replaced with the name of the home
directory of the recipient user.  The @samp{%u} in pattern will be
replaced with the recipient user name, and @samp{%h} with the home
directory for that user.
@end deffn

@node Mailing lists
@subsection Mailing list implementation

This subsection explains how to implement mailing lists in
@command{mda} using the @samp{prog} mailbox scheme.

Delivery to the @samp{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 @samp{prog} mailbox:

@table @asis
@item prog://@var{program}?@var{args}
Here, @var{program} is the absolute pathname of the program binary,
and @var{args} are its arguments, separated by @samp{&} signs.

@item |@var{program} @var{args}
In this notation, @var{args} are command line arguments separated by
white space.
@end table

In both cases, @var{args} do not include @code{argv[0]}.

The @samp{prog} mailbox can be used to implement mailing lists.

For example, suppose that the @command{mda} configuration contains:

@example
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@}'";
@}
@end example

Then, the following entries in the @samp{userdb} table implement the
@email{mailman@@yourdomain} mailing list:

@example
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 |
+---------------------+---------------------------------------+
@end example







Return to:

Send suggestions and report system problems to the System administrator.