aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-05-05 19:59:22 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-05-05 19:59:22 +0000
commit5d929766e74bf61a5ee324b1ab616d34db2fbee4 (patch)
tree012886df7b8c917cc8b97219647c8b8ff03cb3f4
parent0aa7e4583600de267f6a23b1a9f32f92cab19aae (diff)
downloadmailfromd-5d929766e74bf61a5ee324b1ab616d34db2fbee4.tar.gz
mailfromd-5d929766e74bf61a5ee324b1ab616d34db2fbee4.tar.bz2
Update
git-svn-id: file:///svnroot/mailfromd/trunk@1412 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r--doc/mailfromd.texi1050
-rw-r--r--doc/mtasim.texi4
2 files changed, 544 insertions, 510 deletions
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index bf2fbb64..3a8bf74a 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -275,7 +275,7 @@ that the original implementation was a simple filter implementing the
@dfn{sender address verification} technique. Since then the program
has changed dramatically, and now it is actually a language translator
and run-time evaluator providing a set of built-in and library
-functions for filtering mail.
+functions for filtering electronic mail.
The first part of this manual is an overview, describing the features
@command{mailfromd} offers in general.
@@ -309,12 +309,12 @@ said about a specific topic.
@command{mailfromd} does not implement any default filtering
policies. Instead, it depends entirely on a @dfn{filter script},
supplied to it by the administrator. The script, written in a
-specialized and simple to use language (@pxref{MFL}), is
-supposed to perform some set of tests and to decide
+specialized and simple to use language, called @acronym{MFL}
+(@pxref{MFL}), is supposed to run a set of tests and to decide
whether the message should be accepted by the @acronym{MTA} or not.
To perform the tests, the script can examine the values of
@command{Sendmail} macros, use an extensive set of built-in
-and library functions and define and invoke user-defined functions.
+and library functions, and invoke user-defined functions.
@node SAV
@section Sender Address Verification.
@@ -323,7 +323,7 @@ and library functions and define and invoke user-defined functions.
@cindex callout, described
@dfn{Sender address verification} is the basic mail verification
technique, implemented by @command{mailfromd}. It consists in probing
-each MX server for the given address, until one of them gives a
+each @acronym{MX} server for the given address, until one of them gives a
definite (positive or negative) reply. Using this technique you can
block a sender address if it is not deliverable, thereby cutting off a
large amount of spam. It can also be useful to block mail for
@@ -345,7 +345,7 @@ your @acronym{MTA} and issues @code{MAIL FROM: <jsmith@@somedomain.net>}
command. However, your @acronym{MTA} does not have to take its word for it, so
it uses @command{mailfromd} to verify the sender address
validity. @command{Mailfromd} strips the domain name from the address
-(@samp{somedomain.net}) and queries @acronym{DNS} about MX records for that
+(@samp{somedomain.net}) and queries @acronym{DNS} about @samp{MX} records for that
domain. Suppose, it receives the following list
@multitable @columnfractions 0.2 0.7
@@ -353,12 +353,12 @@ domain. Suppose, it receives the following list
@item 20 @tab relay2.somedomain.net
@end multitable
- It then connects to first MX server, using @acronym{SMTP}
+ It then connects to first @acronym{MX} server, using @acronym{SMTP}
protocol, as if it were going to send a message to
@samp{<jsmith@@somedomain.net>}. This is called sending a
@dfn{probe message}. If the server accepts the recipient address, the
@command{mailfromd} accepts the incoming mail. Otherwise, if the
-server rejects the address, the mail is rejected as well. If the MX
+server rejects the address, the mail is rejected as well. If the @acronym{MX}
server cannot be connected, @command{mailfromd} selects next server
from the list and continues this process until it finds the
answer or the list of servers is exhausted.
@@ -386,12 +386,12 @@ always discarded.
@dfn{standard} method throughout this document. @command{Mailfromd}
also implements a method we call @dfn{strict}. When using strict
method, @command{mailfromd} first resolves @acronym{IP} address of sender
-machine to a fully qualified domain name. Then it obtains MX records
+machine to a fully qualified domain name. Then it obtains @samp{MX} records
for this machine, and then proceeds with probing as described above.
- So, the difference between the two methods is in the set of MX
-records that are being probed: standard method queries MXs based on
-the sender email domain, strict method works with MXs for the sender
+ So, the difference between the two methods is in the set of @samp{MX}
+records that are being probed: standard method queries @samp{MX}s based on
+the sender email domain, strict method works with @samp{MX}s for the sender
@acronym{IP} address.
Strict method allows to cut off much larger amount of spam,
@@ -402,16 +402,16 @@ other domain, say @samp{otherdomain.com}. Standard method is not able
to cope with such cases, whereas strict one is.
An alert reader will ask: what happens if @command{mailfromd} is
-not able to get a definite answer from any of MX servers? Actually,
+not able to get a definite answer from any of @acronym{MX} servers? Actually,
it depends entirely on how you will instruct it to act in this case,
but the general practice is to return temporary failure, which will
-urge the remote party to retry sending his/her message later.
+urge the remote party to retry sending their message later.
@cindex caching @acronym{DNS} requests
After receiving a definite answer, @command{mailfromd} will
cache it in its database, so that next time your @acronym{MTA} receives a
message from that address (or from the sender @acronym{IP}/email address pair,
-for strict method), it will not waste its time trying to reach MX
+for strict method), it will not waste its time trying to reach @acronym{MX}
servers again. The records remain in the cache database for a certain
time, after which they are discarded.
@@ -535,7 +535,7 @@ any column means there is no support for this database in
@item GDBM @tab N/A @tab @option{--with-gdbm}
@end multitable
- The @option{--with-berkeley-db} needs a special note. By default it
+ The @option{--with-berkeley-db} option needs a special note. By default it
will try to determine the version of Berkeley DB installed on your
machine. If, however, this autodetection fails, you can explicitly
specify the version or the library name to use as the argument to
@@ -585,9 +585,9 @@ The user name can also be changed at run-time (@pxref{--user}).
@cindex @option{--prefix}, @command{configure} option
@item Decide where to install @command{mailfromd} and where its
-configuration and data files will be located.
+filter script and data files will be located.
- As usual, default value for installation prefix is
+ As usual, the default value for the installation prefix is
@file{/usr/local}. If it does not suit you, specify another location
using @option{--prefix} option, e.g.: @samp{--prefix=/usr}.
@@ -614,9 +614,9 @@ configuring the whole system.
@anchor{statedir}
@cindex local state directory
@cindex DEFAULT_STATE_DIR, @command{configure} variable
- Another important point is the location of @dfn{local state
+ Another important point is location of @dfn{local state
directory}, i.e. a directory where @command{mailfromd} will keep its
-data files (communication socket, pidfile and cache database). By
+data files (communication socket, pidfile and database files). By
default, its full name is @file{@var{localstatedir}/mailfromd}. You
can change it by setting @code{DEFAULT_STATE_DIR} configuration
variable. This value can be changed at run-time using @code{#pragma
@@ -627,10 +627,14 @@ option state-directory} statement
@cindex default communication socket
@cindex default communication port
@cindex DEFAULT_SOCKET, @command{configure} variable
- This is the socket used to communicate with @command{sendmail}.
-Its default value is
-@file{unix:@var{localstatedir}/mailfromd/mailfrom}. To alter this, use
-@code{DEFAULT_SOCKET} environment variable, e.g.:
+ This is the socket used to communicate with @command{sendmail}, in
+the usual @command{Milter} port notation (@pxref{milter port specification}).
+If the socket name does not begin with a protocol or directory
+separator, it is assumed to be a @acronym{UNIX} socket, located in the
+local state directory. The default value is @file{mailfrom}, which is
+equivalent to @file{unix:@var{localstatedir}/mailfromd/mailfrom}.
+
+ To alter this, use @code{DEFAULT_SOCKET} environment variable, e.g.:
@smallexample
./configure DEFAULT_SOCKET=inet:999@@localhost
@@ -656,7 +660,7 @@ variable.
There are also two variables that allow to control particular
expiration intervals: @code{DEFAULT_DNS_NEGATIVE_EXPIRE_INTERVAL} sets
expiration time for cached negative @acronym{DNS} answers (@pxref{DNS Cache
-Management} (default 3600 seconds) and
+Management}) (default 3600 seconds) and
@code{DEFAULT_EXPIRE_RATES_INTERVAL} sets default expiration time for
mail rate database (@pxref{rate}).
@@ -721,8 +725,7 @@ DBM version............................... Berkeley DB v. 3
Default user.............................. mail
State directory...........................
$(localstatedir)/$(PACKAGE)
-Socket....................................
- unix:/$(DEFAULT_STATE_DIR)/mailfrom
+Socket.................................... mailfrom
Expiration interval....................... 86400
Negative DNS answer expiration interval... 3600
Rates expire interval..................... 300
@@ -887,8 +890,8 @@ make sure the variable is declared as global. For example, this code:
@smallexample
prog helo
do
- # @r{Save the host name for further use}
- set helohost $s
+ # @r{Save the host name for further use}
+ set helohost $s
done
@end smallexample
@end float
@@ -903,8 +906,8 @@ set helohost ""
prog helo
do
- # @r{Save the host name for further use}
- set helohost $s
+ # @r{Save the host name for further use}
+ set helohost $s
done
@end smallexample
@end float
@@ -1000,7 +1003,7 @@ simplest ones and proceeding up to more advanced forms. It omits
most complicated details, concentrating mainly on the
common practical tasks.
- If you are familiar to @command{mailfromd} you can skip this
+ If you are familiar to @command{mailfromd}, you can skip this
chapter and go directly to the next one, that contains detailed
discussion of the configuration language and @command{mailfromd}
interaction with the Mail Transport Agent.
@@ -1031,7 +1034,7 @@ interaction with the Mail Transport Agent.
@cindex @acronym{MTA}
@cindex Mail Transfer Agent (@acronym{MTA})
- The @command{mailfromd} runs as a standalone @dfn{daemon}
+ The @command{mailfromd} utility runs as a standalone @dfn{daemon}
program and listens on a predefined communication channel for requests
from the @dfn{Mail Transfer Agent} (@acronym{MTA}, for short). When
processing each message, the @acronym{MTA} installs communication with
@@ -1041,7 +1044,8 @@ information to @command{mailfromd}, and waits for it to reply. The
@command{mailfromd} filter receives the message data through
@dfn{Sendmail macros} and runs a @dfn{handler program}
defined for the given state. The result of this run is a @dfn{response
-code}, that it returns to the @acronym{MTA}:
+code}, that it returns to the @acronym{MTA}. The following response
+codes are defined:
@table @code
@item continue
@@ -1056,9 +1060,9 @@ further consulting @command{mailfromd} filter.
@item reject
@cindex reject action, introduced
-Reject this message. The message processing stops at this stage, the
-sender receives the reject reply. No further @command{mailfromd}
-handlers are called for this message.
+Reject this message. The message processing stops at this stage, and the
+sender receives the reject reply (@samp{5@var{xx}} reply code). No
+further @command{mailfromd} handlers are called for this message.
@item discard
@cindex discard action, introduced
@@ -1070,8 +1074,9 @@ but will discard it after receiving. No further interaction with
@item tempfail
@cindex tempfail action, introduced
Temporarily reject the message. The message processing stops at this
-stage, the sender receives the tempfail reply. No further @command{mailfromd}
-handlers are called for this message.
+stage, and the sender receives the @samp{temporary failure} reply
+(@samp{4@var{xx}} reply code). No further @command{mailfromd}
+handlers are called for this message.
@end table
@cindex filter script, described
@@ -1097,7 +1102,7 @@ be supplied its own handling procedure. A missing procedure implies
@cindex begin, special handler
@cindex end, special handler
@anchor{handler names}
- A filter script can define up to eight @dfn{milter state handlers},
+ The filter script can define up to eight @dfn{milter state handlers},
called after the names of milter states: @samp{connect}, @samp{helo},
@samp{envfrom}, @samp{envrcpt}, @samp{header}, @samp{eoh},
@samp{body}, and @samp{eom}. Two special handlers are available for
@@ -1156,9 +1161,10 @@ of @code{accept}, the @acronym{MTA} will accept the message for
delivery, in the case of @code{discard} it will silently discard it.
If any of the handlers returns @code{reject} or @code{tempfail}, the
-result depends on the handler: the @code{envrcpt} handler will cause
-this particular recipient address to be rejected, all other handlers
-will cause the whole message will be rejected.
+result depends on the handler. If this code is returned by
+@code{envrcpt} handler, it causes this particular recipient address to
+be rejected. When returned by any other handler,
+it causes the whole message will be rejected.
The @code{reject} and @code{tempfail} actions executed by
@code{helo} handler do not take effect immediately. Instead their
@@ -1180,7 +1186,7 @@ declaration has the form:
@group
prog @var{name}
do
- @dots{}
+ @dots{}
done
@end group
@end smallexample
@@ -1197,7 +1203,7 @@ commands, instructing @command{mailfromd} how to process the message.
@group
prog envfrom
do
- accept
+ accept
done
@end group
@end smallexample
@@ -1221,7 +1227,7 @@ two arguments are supplied, the second argument must be either an
@dfn{extended reply code} (@acronym{RFC} 1893/2034) or a textual string to be
returned along with the @acronym{SMTP} reply. Finally, if all three
arguments are supplied, then the second one must be an extended reply
-code and the third one must give the textual string. The following
+code and the third one must supply the textual string. The following
examples illustrate all possible ways of using the @code{reject}
statement:
@@ -1241,7 +1247,7 @@ Please note the quotes around the textual string.
@node Conditional Execution
@section Conditional Execution
- Programs consisting of a single action are rarely useful, in most
+ Programs consisting of a single action are rarely useful. In most
cases you will want to do some checking and decide whether to process
the message depending on its result. For example, if you do not want
to accept messages from the address @samp{<badguy@@some.net>}, you
@@ -1251,11 +1257,11 @@ could write the following program:
@group
prog envfrom
do
- if $f = "badguy@@some.net"
- reject
- else
- accept
- fi
+ if $f = "badguy@@some.net"
+ reject
+ else
+ accept
+ fi
done
@end group
@end smallexample
@@ -1272,8 +1278,9 @@ arguments and evaluates to true if the two strings are exactly the
same, or to false otherwise. Apart from equality, you can use the
regular relational operators: @samp{!=}, @samp{>}, @samp{>=}, @samp{<}
and @samp{<=}. Notice that string comparison in @command{mailfromd}
-is always case sensitive. @xref{tolower}, and @ref{toupper}, for the
-ways to translate strings to lower or upper case.)
+is always case sensitive. To do case-insensitive comparison,
+translate both operands to upper or lower case (@xref{tolower}, and
+@pxref{toupper}).
The @code{if} statement decides what actions to execute depending
on the value its condition evaluates to. Its usual form is:
@@ -1285,7 +1292,7 @@ if @var{expression} @var{then-body} [else @var{else-body}] fi
The @var{then-body} is executed if the @var{expression} evaluates to
@code{true} (i.e. to any non-zero value). The optional
@var{else-body} is executed if the @var{expression} yields
-@code{false}. Both @var{then-body} and @var{else-body} can contain
+@code{false} (i.e. zero). Both @var{then-body} and @var{else-body} can contain
other @code{if} statements, their nesting depth is not limited. To
facilitate writing complex conditional statements, the @code{elif}
keyword can be used to introduce alternative conditions, for example:
@@ -1294,13 +1301,13 @@ keyword can be used to introduce alternative conditions, for example:
@group
prog envfrom
do
- if $f = "badguy@@some.net"
- reject
- elif $f = "other@@domain.com"
- tempfail 470 "Please try again later"
- else
- accept
- fi
+ if $f = "badguy@@some.net"
+ reject
+ elif $f = "other@@domain.com"
+ tempfail 470 "Please try again later"
+ else
+ accept
+ fi
done
@end group
@end smallexample
@@ -1368,9 +1375,9 @@ for various purposes. There are two basic function classes:
@dfn{built-in} functions, that are implemented by the @acronym{MFL}
runtime environment in @command{mailfromd}, and @dfn{library}
functions, that are implemented in @acronym{MFL}. The built-in
-functions are always available, no preparatory work is needed before
+functions are always available and no preparatory work is needed before
calling them. In contrast, the library functions are defined in
-@dfn{modules}, special @acronym{MFL} source files grouping functions
+@dfn{modules}, special @acronym{MFL} source files that contain functions
designed for a particular task. In order to access a library
function, you must first @dfn{require} a module it is defined in.
This is done using @code{#require} statement. For example, the
@@ -1408,9 +1415,9 @@ example below:
prog envfrom
do
- if hostname($client_addr) = $client_addr
- reject
- fi
+ if hostname($client_addr) = $client_addr
+ reject
+ fi
done
@end group
@end smallexample
@@ -1433,11 +1440,11 @@ purpose:
@group
on poll $f do
when success:
- accept
+ accept
when not_found or failure:
- reject 550 5.1.0 "Sender validity not confirmed"
+ reject 550 5.1.0 "Sender validity not confirmed"
when temp_failure:
- tempfail 450 4.1.0 "Try again later"
+ tempfail 450 4.1.0 "Try again later"
done
@end group
@end smallexample
@@ -1447,7 +1454,7 @@ purpose:
argument (in the example above it is the value of the Sendmail macro
@samp{$f}). The check can result in the following conditions:
-@table @asis
+@table @code
@item success
The address exists.
@@ -1489,18 +1496,18 @@ this address:
@group
prog envfrom
do
- if $f == ""
- accept
- else
- on poll $f do
- when success:
- accept
- when not_found or failure:
- reject 550 5.1.0 "Sender validity not confirmed"
- when temp_failure:
- tempfail 450 4.1.0 "Try again later"
- done
- fi
+ if $f == ""
+ accept
+ else
+ on poll $f do
+ when success:
+ accept
+ when not_found or failure:
+ reject 550 5.1.0 "Sender validity not confirmed"
+ when temp_failure:
+ tempfail 450 4.1.0 "Try again later"
+ done
+ fi
done
@end group
@end smallexample
@@ -1586,22 +1593,22 @@ tolerable.
An @code{envfrom} program consisting only of the @code{on poll}
statement will work smoothly for incoming mails, but will create
-infinite loops for outgoing mails. Indeed, upon sending the outgoing
-mail @command{mailfromd} will start the verification procedure, which
-will initiate an @acronym{SMTP} transaction with the own server. This
-transaction will in turn trigger execution of @code{on poll}
-statement, etc. @i{ad infinitum}. To avoid this, any properly written
-filter script should not run the verification procedure on the email
-addresses in those domains that are relayed by the server it runs on.
-This can be achieved using @code{relayed} function. The function returns
-@code{true} if its argument is contained in one of the predefined
-@dfn{domain list} files. These files correspond to @command{Sendmail}
-plain text files used in @code{F} class definition forms
-(see @cite{Sendmail Installation and Operation Guide}, chapter 5.3),
-i.e. they contain one domain name per line, with empty lines and lines
-started with @samp{#} being ignored. The domain files consulted by
-@code{relayed} function are defined using the special @code{#pragma
-option relay} statement:
+infinite loops for outgoing mails. This is because, upon sending an outgoing
+message @command{mailfromd} will start the verification procedure, which
+will initiate an @acronym{SMTP} transaction with the same mail server
+that runs it. This transaction will in turn trigger execution of
+@code{on poll} statement, etc. @i{ad infinitum}. To avoid this, any
+properly written filter script should not run the verification
+procedure on the email addresses in those domains that are relayed by
+the server it runs on. This can be achieved using @code{relayed}
+function. The function returns @code{true} if its argument is
+contained in one of the predefined @dfn{domain list} files. These
+files correspond to @command{Sendmail} plain text files used in
+@code{F} class definition forms (see @cite{Sendmail Installation and
+Operation Guide}, chapter 5.3), i.e. they contain one domain name per
+line, with empty lines and lines started with @samp{#} being ignored.
+The domain files consulted by @code{relayed} function are defined
+using the special @code{#pragma option relay} statement:
@smallexample
@group
@@ -1626,36 +1633,35 @@ server@footnote{class @samp{R}}.
prog envfrom
do
- if $f == ""
- accept
- elif relayed hostname($@{client_addr@}
- accept
- else
- on poll $f do
- when success:
- accept
- when not_found or failure:
- reject 550 5.1.0 "Sender validity not confirmed"
- when temp_failure:
- tempfail 450 4.1.0 "Try again later"
- done
- fi
+ if $f == ""
+ accept
+ elif relayed(hostname($@{client_addr@}))
+ accept
+ else
+ on poll $f do
+ when success:
+ accept
+ when not_found or failure:
+ reject 550 5.1.0 "Sender validity not confirmed"
+ when temp_failure:
+ tempfail 450 4.1.0 "Try again later"
+ done
+ fi
done
@end group
@end smallexample
If you feel that your Sendmail's relayed domains are not restrictive
enough for @command{mailfromd} filters (for example you are relaying
-mails from some third-party servers), you can use a database of mail
-server addresses to decide whether the mail must be checked or not.
-If the number of such servers is small enough, a single @samp{or}
-statement can be used, e.g.:
+mails from some third-party servers), you can use a database of
+trusted mail server addresses. If the number of such servers is small
+enough, a single @samp{or} statement can be used, e.g.:
@smallexample
- elif $@{client_addr@} = "10.10.10.1"
- or $@{client_addr@} = "192.168.11.7"
- accept
- @dots{}
+ elif $@{client_addr@} = "10.10.10.1"
+ or $@{client_addr@} = "192.168.11.7"
+ accept
+ @dots{}
@end smallexample
@noindent
@@ -1664,20 +1670,20 @@ several @acronym{CIDR}s, you can use the @code{match_cidr} function
(@pxref{Internet address manipulation functions}), e.g.:
@smallexample
- elif match_cidr ($@{client_addr@}, "199.232.0.0/16")
- accept
- @dots{}
+ elif match_cidr ($@{client_addr@}, "199.232.0.0/16")
+ accept
+ @dots{}
@end smallexample
@noindent
-Finally, you can keep a @acronym{DBM} database of relayed addresses
-and use @code{dbmap} or @code{dbget} function for checking
-(@pxref{Database functions}).
+or combine both methods. Finally, you can keep a @acronym{DBM}
+database of relayed addresses and use @code{dbmap} or @code{dbget}
+function for checking (@pxref{Database functions}).
@smallexample
- elif dbmap(__statedir__"/relay.db", $@{client_addr@})
- accept
- @dots{}
+ elif dbmap(__statedir__ "/relay.db", $@{client_addr@})
+ accept
+ @dots{}
@end smallexample
@node HELO Domain
@@ -1690,11 +1696,11 @@ and use @code{dbmap} or @code{dbget} function for checking
account the following caveats. Firstly, although @command{Sendmail}
passes the helo domain in @code{$s} macro, it does not do this
consistently. In fact, the @code{$s} macro is available only to
-@code{helo} handler, all other handlers won't see it, no matter what
+the @code{helo} handler, all other handlers won't see it, no matter what
the value of the corresponding @code{Milter.macros.@var{handler}}
statement. So, if you wish to access its value within an other
-handler, you will have to store it in a @dfn{variable} in @code{helo}
-handler and than use this variable value in the other handler. This
+handler, you will have to store it in a @dfn{variable} in the @code{helo}
+handler and then use this variable value in the other handler. This
brings us to the concept of variables in @command{mailfromd} scripts.
@cindex Variables, introduced
@@ -1706,9 +1712,9 @@ brings us to the concept of variables in @command{mailfromd} scripts.
@end smallexample
@noindent
-where where @var{variable} is the variable name and @var{type} is
-@samp{string} if the variable is to hold a string value and
-@samp{number} if it is supposed to have a numeric value.
+where @var{variable} is the variable name and @var{type} is
+@samp{string}, if the variable is to hold a string value, and
+@samp{number}, if it is supposed to have a numeric value.
@cindex variable assignment
@cindex assignment to variable
@@ -1734,7 +1740,7 @@ variable (@xref{Variables, Variable classes}, for the detailed description
of both kinds of variables).
The following example illustrates the approach that allows to use
-the helo domain name in any handler:
+the @code{HELO} domain name in any handler:
@smallexample
@group
@@ -1743,16 +1749,16 @@ string helohost
prog helo
do
- # @r{Save the host name for further use}
- set helohost $s
+ # @r{Save the host name for further use}
+ set helohost $s
done
prog envfrom
do
- # @r{Reject hosts claiming to be @i{localhost}}
- if %helohost = "localhost"
- reject 570 "Please specify real host name"
- fi
+ # @r{Reject hosts claiming to be @i{localhost}}
+ if %helohost = "localhost"
+ reject 570 "Please specify real host name"
+ fi
done
@end group
@end smallexample
@@ -1773,8 +1779,8 @@ handler from the example above can be rewritten as follows:
@group
prog helo
do
- # @r{Save the host name for further use}
- set helohost $1
+ # @r{Save the host name for further use}
+ set helohost $1
done
@end group
@end smallexample
@@ -1798,9 +1804,9 @@ in variable @code{%rcpt_count}, which can be controlled in
@group
prog envrcpt
do
- if %rcpt_count > 10
- reject 550 5.7.1 "Too many recipients"
- fi
+ if %rcpt_count > 10
+ reject 550 5.7.1 "Too many recipients"
+ fi
done
@end group
@end smallexample
@@ -1815,9 +1821,9 @@ to 10 for incoming mail from other domains:
@group
prog envrcpt
do
- if not relayed hostname $client_addr and %rcpt_count > 10
- reject 550 5.7.1 "Too many recipients"
- fi
+ if not relayed hostname $client_addr and %rcpt_count > 10
+ reject 550 5.7.1 "Too many recipients"
+ fi
done
@end group
@end smallexample
@@ -1836,7 +1842,7 @@ operator scoping, the above @code{if} condition can be rewritten as
follows:
@smallexample
- if (not (relayed hostname $client_addr)) and (%rcpt_count > 10)
+ if (not (relayed (hostname ($client_addr)))) and (%rcpt_count > 10)
@end smallexample
Finally, it is important to notice that all boolean expressions
@@ -1859,6 +1865,11 @@ If @code{@var{x} @result{} @code{true}}, do not evaluate @var{y} and
return @code{true}.
@end table
+ Thus, in the expression @code{not relayed hostname $client_addr and
+%rcpt_count > 10}, the value of the @code{rcpt_count} variable will be
+compared with @samp{10} only if the @code{relayed} function yielded
+@code{false}.
+
To further enhance our sample filter, you may wish to make the
@code{reject} output more informative, to let the sender know what
the recipient limit is. To do so, you can use the fact that in
@@ -1870,9 +1881,9 @@ the enhanced filter version could look like:
set max_rcpt 10
prog envrcpt
do
- if not relayed hostname $client_addr and %rcpt_count > 10
- reject 550 5.7.1 "Too many recipients, max=" %max_rcpt
- fi
+ if not relayed hostname $client_addr and %rcpt_count > 10
+ reject 550 5.7.1 "Too many recipients, max=" %max_rcpt
+ fi
done
@end group
@end smallexample
@@ -1892,7 +1903,7 @@ database consists of a @code{key}, for which the rate is computed, and
the rate value, in form of a double precision floating point number,
representing the average number of messages per second sent by this
@code{key} within the last sampling interval. In the simplest case,
-the @code{key} can be the sender email address, however we recommend
+the sender email address can be used as a @code{key}, however we recommend
to use a conjunction @var{email}-@var{sender_ip} instead, so the
actual @var{email} owner won't be blocked by actions of some spammer
abusing his/her address.
@@ -1904,28 +1915,30 @@ which the actual sending rate value is converted. Remember, that it is
stored internally as a floating point number, and thus cannot be used
in @command{mailfromd} filters, which operate only on integer numbers.
To use the rate value, it is first converted to messages per given
-interval, which is an integer number. For example, the number
-@code{0.138888} converted to 1-hour interval gives @code{500}
+interval, which is an integer number. For example, the rate
+@code{0.138888} brought to 1-hour interval gives @code{500}
(messages per hour).
Wherever the @code{rate} function is called, it recomputes and
updates the rate record for the given @var{key}, and returns its
value, converted to messages per interval. For example, the following
code limits the mail sending rate for each @samp{email
-address}-@samp{@acronym{IP}} combination to 180 per hour. If the rate value is
-exceeded, the sender is returned a temporary failure response:
+address}-@samp{@acronym{IP}} combination to 180 per hour. If the
+actual rate value exceeds this limit, the sender is returned a
+temporary failure response:
@smallexample
@group
prog envfrom
do
- if rate($f "-" $@{client_addr@}, 3600) > 180
- tempfail 450 4.7.0 "Mail sending rate exceeded. Try again later"
- fi
+ if rate($f "-" $@{client_addr@}, 3600) > 180
+ tempfail 450 4.7.0 "Mail sending rate exceeded. Try again later"
+ fi
done
@end group
@end smallexample
+@noindent
Notice argument concatenation, used to produce the key.
It is often inconvenient to specify intervals in seconds,
@@ -1938,7 +1951,7 @@ this function, the function invocation would be:
rate($f "-" $@{client_addr@}, interval("1 hour"))
@end smallexample
- For more information about @code{rate} function, @ref{rate}. The
+ For more information about @code{rate} function, see @ref{rate}. The
@code{interval} function is described in @ref{interval} and time
intervals are discussed in @ref{time interval specification}.
@@ -1950,7 +1963,7 @@ proposed by Evan Harris. In few words, it consists in recording the
@samp{sender @acronym{IP}}-@samp{sender email}-@samp{recipient email} triplet of
mail transactions. Each time the unknown triplet is seen, the
corresponding message is rejected with @code{tempfail} code. If the
-mail is legitimate, this will make the originating server will retry
+mail is legitimate, this will make the originating server retry
the delivery later, at which time the destination will accept it. If,
however, the mail is a spam, it will probably never be retried, so
the users will not be bothered by it. Even if the spammer will retry
@@ -1970,12 +1983,11 @@ the @code{key}, identifying the greylisting triplet, and the
@code{interval}. The function looks up the key in the @dfn{greylisting
database}. If such a key is not found, a new entry is created for it
and the function returns @code{true}. If the key is
-found, @code{greylist} returns @code{false} if it was inserted to the
+found, @code{greylist} returns @code{false}, if it was inserted to the
database more than @code{interval} seconds ago, and @code{true} otherwise.
-Thus, from the point of view of the greylisting algorithm, the
+In other words, from the point of view of the greylisting algorithm, the
function returns @code{true} when the message delivery should be
-blocked, and the simplest implementation of the algorithm would be
-this:
+blocked. Thus, the simplest implementation of the algorithm would be:
@smallexample
@group
@@ -1991,26 +2003,26 @@ done
@cindex greylist_seconds_left, global variable, introduced
However, the message returned by this example, is not informative
enough. In particular, it does not tell when the message will be
-accepted. To help you produce more informative messages the @code{greylist}
+accepted. To help you produce more informative messages, @code{greylist}
function stores the number of seconds left to the end of the
greylisting period in the global variable
-@code{%greylist_seconds_left}, so the above example could be enhanced
-as:
+@code{greylist_seconds_left}, so the above example could be enhanced
+as follows:
@smallexample
@group
prog envrcpt
do
- set gltime interval("1 hour")
- if greylist($@{client_addr@} "-" $f "-" $@{rcpt_addr@}, %gltime)
- if %greylist_seconds_left = %gltime
+ set gltime interval("1 hour")
+ if greylist($@{client_addr@} "-" $f "-" $@{rcpt_addr@}, %gltime)
+ if %greylist_seconds_left = %gltime
tempfail 451 4.7.1
"You are greylisted for " %gltime " seconds"
- else
+ else
tempfail 451 4.7.1
"Still greylisted for " %greylist_seconds_left " seconds"
- fi
- fi
+ fi
+ fi
done
@end group
@end smallexample
@@ -2018,7 +2030,7 @@ done
In real life you will have to avoid greylisting some messages, in
particular those coming from the @samp{<>} address and from the @acronym{IP}
addresses in your relayed domain. It can easily be done using the
-techniques described in previous sections and is left as an exercises
+techniques described in previous sections and is left as an exercise
to the reader.
@anchor{whitelisting}
@@ -2026,8 +2038,8 @@ to the reader.
One special case is @dfn{whitelisting}, which is often used
together with greylisting. To implement it, @command{mailfromd}
provides the function @code{dbmap}, which takes two mandatory arguments:
-@code{dbmap(@var{file}, @var{key})} (@xref{dbmap}, for the
-description of the optional third argument). The first argument is
+@code{dbmap(@var{file}, @var{key})} (it also allows an optional third
+argument, see @ref{dbmap}, for the description of it). The first argument is
the name of the @acronym{DBM} file where to search for the key, the second one
is the key to be searched. Assuming you keep your whitelist database
in file @file{/var/run/whitelist.db}, a more practical example will be:
@@ -2036,20 +2048,20 @@ in file @file{/var/run/whitelist.db}, a more practical example will be:
@group
prog envrcpt
do
- set gltime interval("1 hour")
+ set gltime interval("1 hour")
- if not ($f = "" or relayed hostname $@{client_addr@}
+ if not ($f = "" or relayed hostname $@{client_addr@}
or dbmap("/var/run/whitelist.db", $@{client_addr@}))
- if greylist($@{client_addr@} "-" $f "-" $@{rcpt_addr@}, %gltime)
- if %greylist_seconds_left = %gltime
+ if greylist($@{client_addr@} "-" $f "-" $@{rcpt_addr@}, %gltime)
+ if %greylist_seconds_left = %gltime
tempfail 451 4.7.1
"You are greylisted for " %gltime " seconds"
- else
+ else
tempfail 451 4.7.1
"Still greylisted for " %greylist_seconds_left " seconds"
- fi
- fi
- fi
+ fi
+ fi
+ fi
done
@end group
@end smallexample
@@ -2059,42 +2071,43 @@ done
@section Local Account Verification
In your filter script you may need to verify if the given
-user name is served by the server, in other words, to verify if it is a
-@dfn{local account}. Notice that in this context, the word
+user name is served by your mail server, in other words, to verify if
+it represents a @dfn{local account}. Notice that in this context, the word
@dfn{local} does not necessarily mean that the account is local for
the server running @command{mailfromd}, it simply means any account
whose mailbox is served by the mail servers using @command{mailfromd}.
- To verify the account, function @code{validuser} can be used. The
-function takes one argument, the user name, and returns @code{true} if
+ The @code{validuser} function may be used for this purpose. It
+takes one argument, the user name, and returns @code{true} if
this name corresponds to a local account. To verify this