diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-05-05 19:59:22 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-05-05 19:59:22 +0000 |
commit | 5d929766e74bf61a5ee324b1ab616d34db2fbee4 (patch) | |
tree | 012886df7b8c917cc8b97219647c8b8ff03cb3f4 /doc | |
parent | 0aa7e4583600de267f6a23b1a9f32f92cab19aae (diff) | |
download | mailfromd-5d929766e74bf61a5ee324b1ab616d34db2fbee4.tar.gz mailfromd-5d929766e74bf61a5ee324b1ab616d34db2fbee4.tar.bz2 |
Update
git-svn-id: file:///svnroot/mailfromd/trunk@1412 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'doc')
-rw-r--r-- | doc/mailfromd.texi | 1050 | ||||
-rw-r--r-- | doc/mtasim.texi | 4 |
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}. |