LINUXOR.SK ... open source notes ...

Postfix 07 - Notes on MDAs (procmail and maildrop)

category: learnz/postfix · date: 2007-11-30 · source: old.linuxor.sk/MAIL/POSTFIX-HOWTOs/BH_Procmail_Maildrop.txt · theme: github

Postfix Mail Server Learning · Previous: body_checks and header_checks · Next: EnGarde Secure Linux - installing a mail gateway

The Slovak original of this document: Postfix 07 - Poznámky k MDA (procmail a maildrop) (slovensky).

asciiart
|=---------------------------=[ Procmail/Maildrop ]=-----------------------=|
+---------------------------------------------------------------------------+
|                                                                           |
|                       Notes on MDAs (procmail and maildrop)               |
|                                                                           |
|                                                                           |
+---------------------------------------------------------------------------+
|=-------------------------------=[ BH 2007 ]=-----------------------------=|

1. Procmail

asciiart
$HOME/.procmailrc

1.1 Rule syntax

asciiart
:0 [flags] [ : [locallockfile] ]
<zero or more conditions (one per line)>
<exactly one action>

1.2 Flags

asciiart
H = Egreps the header (default).

B = Egreps the body.

D = Sets the internal egrep to distinguish between upper and lower case
    (the default is to ignore case)

A = This rule will not be executed unless the condition of the last preceding rule
    (at the current nesting level) without the flag 'A' or 'a' matches. This lets
    us chain actions that depend on a common condition.

a = This flag means the same as 'A', with the additional condition
    that the rule immediately before it has to have finished successfully
    before this rule runs.

E = This rule is executed if the rule immediately before this rule
    was not executed. Executing this rule also disables any immediately
    following rules with the 'E' flag. This lets us specify actions of the
    'else if' type.

e = This rule is executed only if the previous rule failed
    (e.g. the action line was attempted, but ended with an error).

h = Sends the header to the pipe, the file or the mail destination (the default).

b = Sends the body to the pipe, the file or the mail destination (the default).

f = Treats the pipe as a filter.

c = Generates a copy of this mail. This is meaningful in delivery rules

w = Waits for the filter or program to finish and checks its exit code
    (normally ignores it); if the filter fails, the text is left unfiltered.

W = Means the same as the flag "w", but suppresses any "Program failure" message.

i = Ignores any write error in this rule
    (for example, when the pipe is closed early).

r = Raw mode; makes no attempt to have the mail end with an empty line,
    writes it as it is.

1.3 Special conditions

asciiart
! = Inverts the condition.

$ = Evaluates the rest of this condition according to the shell substitution rules
    inside double quotes, skips whitespace and then reparses it.

? = Uses the exit code of the specified program.

< = Checks whether the total size of the mail is smaller than the given number of bytes (decimal).

> = Analogous to '<'

variable_name  ?? = Matches the rest of this condition against the value of this environment variable
                    (which cannot be a pseudo-variable). A special case is when the variable name
                    matches 'B', 'H', 'HB' or 'BH'; this completely overrides the default
                    header/body search areas defined by the initial flags on
                    this rule.

1.4 Extended regular expressions

asciiart
^       = Start of a line.
$       = End of a line.
.       = Any character except a newline. (e.g.: .aco => laco, maco)
a*      = A sequence of zero or more 'a' characters (,a,aa,aaa). (e.g.: Lac* Hajzer => La Hajzer, Lac Hajzer, Lacccc Hajzer)
a+      = A sequence of one or more 'a' characters (a,aa,aaa). (e.g.: La(co)+ => Laco, Lacococo)
a?      = Zero or one 'a' character. (e.g.: Laco? => Lac, Laco)
[^-a-d] = Any character that is not '-', 'a', 'b', 'c', 'd' or a newline.
[abcd]  = A character class, meaning one of the listed characters.
de|abc  = The sequence 'de' or 'abc' .
(abc)*  = Zero or more 'abc' sequences.
\.      = A single dot. To match any special character, we put the '\' character in front of it.

-----------------------------------------------------------------
 Example 1: forwarding all e-mails to another e-mail address
-----------------------------------------------------------------
:0 H:
* ^To:.*mail@domena.sk
! inymail@inadomena.sk

-----------------------------------------------------------------
 Example 2: forwarding all e-mails to another e-mail address + storing them
 in the local mail folder
-----------------------------------------------------------------
:0 Hc:
* ^To:.*mail@domena.sk
! inymail@inadomena.sk

-----------------------------------------------------------------
 Example 3: forwarding e-mails to another e-mail address by subject
-----------------------------------------------------------------
:0 H:
* ^Subject: .*UDALOST
! udalost@domena.sk

-----------------------------------------------------------------
 Example 4: sorting e-mails into folders by subject
-----------------------------------------------------------------
:0 H:
* ^Subject: .*UDALOST
~/udalosti

-----------------------------------------------------------------
 Example 5: an out-of-office auto-reply. The user sets it up themselves by sending an e-mail.
-----------------------------------------------------------------
# touch /home/user/.procmailrc
# chown user:user /home/user/.procmailrc
# chmod 700 /home/user/.procmailrc

We edit the file /home/user/.procmailrc
---------------------------------------
$VACATION_PASSWORD - the password for turning the auto-reply on/off
$VACATION_SENDER - the e-mail address we are setting the auto-reply for (user@domena.sk)

in case of problems we uncomment the following lines in the file /home/user/.procmailrc
------------------------------------------------------------------------------------------
#LOGFILE=/tmp/procmailvacation.log
#VERBOSE=on

Turning the auto-reply on
-------------------------
The user sends a mail with the subject: password vacation on (password is the password defined in .procmailrc)
The body of the mail becomes the text of the auto-reply.

Turning the auto-reply off
--------------------------
The user sends a mail with the subject: password vacation off (password is the password defined in .procmailrc)

From http://www.clarkconnect.com/wiki/index.php?title=Howtos_-_Procmail_Vacation_Auto-Reply_Recipe

------------------------------------ .procmailrc --------------------------------
# vim: ft=procmail

# User-managed vacation recipe for procmail
# Written by Jason Thaxter
#  (http://www.google.com/search?q=jason+thaxter)

# To use from a shell:
#
#   * Include this file in your procmail recipe.
#   * Define $VACATION_SENDER in your procmail recipe: it will be "from" this
#     address.
#   * Put your message text in a file specified by $VACATION_MSG.
#     (defaults to ".vacation_mesg")
#   * Remove the $VACATION_MSG file to turn off vacation messages.

# For users without shell access:
#
#   * Include this file in the procmail file.
#   * Set $VACATION_PASSWORD. (for security, this is mandatory)
#   * Define $VACATION_SENDER in your procmail recipe: it will be "from" this
#     address.
#   * E-mail a message with $VACATION_PASSWORD and $VACATION_ON in the subject
#     line. The body of the message becomes the vacation message. $VACATION_ON
#     can be set prior to the INCLUDERC, but it defaults to "vacation on".
#   * To turn it off, e-mail a message with $VACATION_PASSWORD and $VACATION_OFF
#     in the subject line. Likewise, $VACATION_OFF defaults to "vacation off".

# Note that you probably want this to execute *after* any mailing list or spam
# delivery recipes. You can set $VACATION_SKIP to disable vacation processing
# if it's inconvenient to skip this recipe.

# TODO:
#   * configurable regex so we can reply "from" whatever they sent it "to" (if
#     we can match on the regex, of course). kinda like mutt's "alternates".
#   * optionally, send a vacation message for EVERY incoming message from a
#     given email, not just the first one.
#   * Duh: better documentation.
#   * Nicer defaults for people who let mailing-list mail and spam hit
#     this recipe (though we will *always* try to avoid replying to those).

# -----------------------------------------------------------------------------
# Configurable variables: These variables allow you to use this vacation recipe
# as an include and customize it from your main procmail file.
#
# lockfile:
VACATION_LOCK=${VACATION_LOCK:-".vacation$LOCKEXT"}
# cache file:
VACATION_CACHE=${VACATION_CACHE:-".vacation_cache"}
# cache size:
VACATION_CACHE_SZ=${VACATION_CACHE_SZ:-8192}
# message file
VACATION_MSG=${VACATION_MSG:-".vacation_mesg"}
# what to use as the xloop header
HOSTNAME=${HOSTNAME:-`hostname`}
VACATION_XLOOP=${VACATION_XLOOP:-"$LOGNAME@$HOSTNAME"}
# base token for default $VACATION_ON and $VACATION_OFF
# so you could set this and not those individually
VACATION_COOKIE=${VACATION_COOKIE:-"vacation"}
VACATION_ON=${VACATION_ON:-"$VACATION_COOKIE on"}
VACATION_OFF=${VACATION_OFF:-"$VACATION_COOKIE off"}

# UNSTABLE:
# get the sender for later use
VACATION_MSG_SEND_TO=`formail -rtx To: | expand | sed -e 's/^[ ]*//g' -e 's/[ ]*$//g'`
# not sure what to do for weird cases of these... yet
VACATION_SENDMAILFROM=${VACATION_SENDMAILFROM:-"-f$VACATION_SENDER"}
VACATION_SENDMAILFLAGS="-oi -t $VACATION_SENDMAILFROM"
# who are we? needs to be extracted with a regex using ALTERNATES
#VACATION_RECIPIENT=`formail -XTo: \ | expand | sed -e 's/^[ ]*//g' -e 's/[ ]*$//g'`
# -----------------------------------------------------------------------------

SENDMAIL_CMD="$SENDMAIL $VACATION_SENDMAILFLAGS"
SHELL=/bin/sh

# check if we should send vacation message, add user to cache
:0 Whc: $VACATION_LOCK
# if i haven't been instructed to skip processing
* ? test -z $VACATION_SKIP
# if i have a vacation message file
* ? test -f $VACATION_MSG
# and the message is not from a daemon or mailer
* !^FROM_DAEMON
* !^FROM_MAILER
# not declared spam by spamassassin
* !^X-Spam-Flag: YES
# not discernably in a mailing list
* !^List-
* !^(Mailing-List|Approved-By|BestServHost|Resent-(Message-ID|Sender)):
* !^X-[^:]*-List:
* !^X-(Sent-To|(Listprocessor|Mailman)-Version):
# and not x-loop
* !^X-Loop: $VACATION_XLOOP
# add it to the cache
| formail -rD $VACATION_CACHE_SZ $VACATION_CACHE

:0 ehc
# if the name was not in the cache
# if we can find who we're sending it to
# and who we are sending this "From"
* ? test -n ${VACATION_MSG_SEND_TO}
* ? test -n ${VACATION_SENDER}
| (formail -r \
        -I"Precedence: junk" \
        -A"From: $VACATION_SENDER" \
        -A"X-Loop: $VACATION_XLOOP"; \
        cat  $VACATION_MSG ) | \
        $SENDMAIL_CMD

# Add/remove vacation message
:0
# only do this if we have a password set
* ? test -n $VACATION_PASSWORD
# and it's in the subject line
* $^Subject:.*${VACATION_PASSWORD}
{

        # VACATION ON
        # if subject line matches magic cookie for ON:
        :0
        * $^Subject:.*${VACATION_ON}
        {
                # pipe the body into the vacation message file
                :0c:$VACATION_LOCK
                | formail -I "" > $VACATION_MSG

                # add message to the body
                :0f
                | cat - ; \
                  echo; \
                  echo '---------- VACATION -----------------'; \
                  echo 'The above text was installed as your vacation message'
        }

        # VACATION OFF
        # if subject line matches magic cookie for OFF:
        # delete the vacation file and notify
        :0f
        * $^Subject:.*${VACATION_OFF}
        | cat -;  \
                echo '---------- VACATION -----------------'; \
                echo 'Removing message and cache: '; \
                rm -vf $VACATION_MSG; \
                rm -vf $VACATION_CACHE; \
                echo ; \
                echo "Removed vacation message."

}
------------------------------------ .procmailrc --------------------------------

----------
 Examples
----------
http://www.erehwon.org/erehwon/procmailex.html

Maildrop

Procmail vs Maildrop

asciiart
Function                        procmail                                maildrop
-----------------------------------------------------------------------------------------------
Delivering a message            | /cesta/k/programu                     to "|/cesta/k/programu"
by an external program                                                  or
                                                                        cc "|/cesta/k/programu"

Filtering a message             the same, but the start of the rule     xfilter "/cesta/k/programu"
by an external program          must contain the f flag:
                                :0 f

Filtering messages              :0                                      if ($SIZE > 10000000)
by size                         * > 10000000                            to spravy_nad_10MB
                                spravy_nad_10MB                         or
                                                                        if ($LINES > 500)
                                                                        to spravy_nad_500_riadkov

Reformatting messages           the external program formail:           the external program reformail:
(e.g. adding a header)          :0 f                                    xfilter "reformail -A'X-Envelope-From: $FROM'"
                                | formail -A"Message-ID:"
                                                                        maildrop also contains the program reformime, which makes it possible to work with MIME messages

DOC

asciiart
man procmail
man procmailrc
man procmailex
man procmailsc

LINKZ

asciiart
http://pm-doc.sourceforge.net/
http://www.perlcode.org/tutorials/procmail/proctut/

http://www.impsec.org/email-tools/procmail-security.html
http://www.root.cz/clanky/procmail-vs-maildrop/
http://www.root.cz/clanky/procmail-pre-zaciatocnikov/
http://www.ii.com/internet/robots/procmail/qs/
http://partmaps.org/era/procmail/links.html
http://lipas.uwasa.fi/~ts/info/proctips.html

Current practice (checked 2026-10)

noteThe article above is kept as it was written in 2007. This section lists what has changed since and what to do instead today.

Sources:

← learnz/postfix(EN | SK)