Rockstable Wiki:

postfix

Netiquette

IETF rfc2142

Debugging

When I had no clue what was going on, i took a look into the logs at a higher debugging level. In case of postfix it's as simple as to add -v to the appropriate line in /etc/postfix/master.cf. In this example smtpd -v.

   1 # ==========================================================================
   2 # service type  private unpriv  chroot  wakeup  maxproc command + args
   3 #               (yes)   (yes)   (no)    (never) (100)
   4 # ==========================================================================
   5 smtp      inet  n       -       y       -       -       smtpd -v

Don't forget to remove it later on.

Debug Peer List

To gather additional information about the misbehaving host add a line to
/etc/postfix/main.cf

   1 debug_peer_list = 127.0.0.1, REM.OTE.N.ET/SNM

And reload postfix

   1 postfix reload

Maintenance mode

/etc/postfix/main.cf

   1 ### MAINTENANCE MODE SWITCH -> soft_bounce
   2 ### CHANGES SERVER RESPONSES FROM
   3 ### HARD (5XX) to SOFT (4XX)
   4 ### DEFAULT: no
   5 soft_bounce = yes

And reload postfix

   1 postfix reload

Important commands

Don't forget about the following commands:

   1 postconf -d     #DEFAULTS
   2 postconf -n     #CHANGED
   3 postmap -q      #QUERY DATABASE FOR KEY
   4 mailq           #SHOW QUEUE
   5 postqueue -p    #SHOW QUEUE, SAME AS mailq
   6 postqueue -f    #FLUSH/SEND ANY MAIL IN QUEUE
   7 postqueue -i ID #IMMEDIATLY REQUEUE MAIL WITH ID
   8 postsuper -d ID #DELETE QUEUED EMAIL
   9 db_dump         #SHOW CONTENT OF BERKELEY DBS
  10 

Find and delete a stuck email by address

   1 ### WITH INTERMEDIATE JSON
   2 postqueue -j \
   3         |jq -s '.[]|select(.recipients[]|.address=="DST_EMAIL@ADDRESS.TLD")|.queue_id' \
   4         |xargs -L1 postsuper -d
   5 
   6 ### OLD SCHOOL
   7 postqueue -p \
   8         |grep -B2 "DST_EMAIL@ADDRESS.TLD" \
   9         |cut -d\  -f1 \
  10         |grep -Eo '^[0-9A-F]+' \
  11         |xargs -L1 postsuper -d 

Or as a script
/usr/local/sbin/postfix_delete_mail.sh

   1 #!/bin/bash
   2 
   3 DST="$1"
   4 declare -a IDS
   5 
   6 if [ -n "$DST" ]; then
   7         IDS=( $(postqueue -p \
   8                 |grep -B2 "$DST" \
   9                 |cut -d\  -f1 \
  10                 |grep -Eo '^[0-9A-F]+')
  11         )
  12         [ "${#IDS[@]}" -gt 0 ] && \
  13                 xargs -n1 postsuper -d <<< "${IDS[@]}"
  14 else
  15         cat <<-EOL
  16         Please specify destination email address
  17         as first positional parameter.
  18         EOL
  19 fi

Redirect stuck mail

/usr/local/sbin/postfix_redirect_mail.sh

   1 #!/bin/bash -e
   2 
   3 declare -a IDS
   4 
   5 SELF="$(basename $0)"
   6 
   7 usage () {
   8         cat <<-EOF
   9         $SELF
  10 
  11                 -h|--help)              Display this page
  12                 -n|--new-dest)          New target email-address
  13                 -o|--old-dest)          Old target email-address
  14                 -s|--skip-header)       Skip the old header
  15         EOF
  16 }
  17 
  18 # Note that we use `"$@"' to let each command-line parameter expand to a
  19 # separate word. The quotes around `$@' are essential!
  20 # We need TEMP as the `eval set --' would nuke the return value of getopt.
  21 TEMP=`getopt -o hn:o:s --long help,new-dest:,old-dest:,skip-header \
  22      -n "$SELF" -- "$@"`
  23 
  24 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
  25 
  26 # Note the quotes around `$TEMP': they are essential!
  27 eval set -- "$TEMP"
  28 
  29 while true ; do
  30         case "$1" in
  31                 -h|--help) usage; exit ; shift ;;
  32                 -n|--new-dest) DST_NEW="$2" ; shift 2 ;;
  33                 -o|--old-dest) DST_OLD="$2" ; shift 2 ;;
  34                 -s|--skip-header) SKIP_HEADER=true ; shift ;;
  35                 #-c|--c-long)
  36                 #       # c has an optional argument. As we are in quoted mode,
  37                 #       # an empty parameter will be generated if its optional
  38                 #       # argument is not found.
  39                 #       case "$2" in
  40                 #               "") echo "Option c, no argument"; shift 2 ;;
  41                 #               *)  echo "Option c, argument \`$2'" ; shift 2 ;;
  42                 #       esac ;;
  43                 --) shift ; break ;;
  44                 *) echo "Internal error!" ; exit 1 ;;
  45         esac
  46 done
  47 #echo "Remaining arguments:"
  48 #for arg do echo '--> '"\`$arg'" ; done
  49 
  50 ### SANITIZE USER INPUT
  51 if [ -z "$DST_NEW" ]; then
  52         echo "Please specify a new destination."
  53         exit 1
  54 elif [ -z "$DST_OLD" ];then
  55         echo "Please specify a old destination."
  56         exit 1
  57 fi
  58 
  59 ### GET MAIL FOR DST
  60 #IDS="$(postqueue -j \
  61 #       |jq -s '.[]|select(.recipients[]|.address=="'"$DST_OLD"'")|.queue_id' )"
  62 
  63 IDS=( $(postqueue -p \
  64         |grep -B2 "$DST_OLD" \
  65         |cut -d\  -f1 \
  66         |grep -Eo '^[0-9A-F]+')
  67 )
  68 
  69 if [ "${#IDS[@]}" -gt 0 ]; then
  70         DIR_TMP=$(mktemp -d)
  71 
  72         echo -e "Mail-IDs to be redirected:\n${IDS[@]}"
  73         ### PUT EMAILS ON HOLD
  74         xargs -L1 postsuper -h <<< ${IDS[@]}
  75 
  76         for ID in "${IDS[@]}"; do
  77                 if [ $SKIP_HEADER ]; then
  78                         postcat -qb "$ID" > "$DIR_TMP/$ID"
  79                 else
  80                         postcat -qbh "$ID" > "$DIR_TMP/$ID"
  81                 fi
  82 
  83                 FROM="$(postcat -qh "$ID" \
  84                         |grep '^From: ' \
  85                         |sed -r 's/^From: //')"
  86 
  87                 sendmail -f "$FROM" "$DST_NEW" < "$DIR_TMP/$ID"
  88                 [ "$?" == 0 ] && postsuper -d "$ID"
  89                 rm "$DIR_TMP/$ID"
  90         done
  91         rmdir "$DIR_TMP"
  92 else
  93         echo "No mail in queue for '$DST_OLD'. Exiting …"
  94 fi

Get a bunch of MX-Records

   1 while read LINE; do
   2         MX_RECORD="$(dig -t MX "$LINE" +short)";
   3         echo -e "$LINE:"'\t'"$MX_RECORD";
   4 done <<< "$(awk '{print $1}' /etc/postfix/virtual_mailbox_domains)" \
   5 | column -t

Compare custom config to postfix defaults

/usr/local/bin/postfix_compare_defaults.sh

   1 #!/bin/bash
   2 # Copyright Rockstable IT 2020
   3 # License: GPLv2+
   4 # Delivered as is, no warranty, no liability,…
   5 
   6 set -o pipefail
   7 
   8 ### INITIALIZE
   9 CONFIG_DIR="/etc/postfix"
  10 SELF="$(basename "$0")"
  11 
  12 usage () {
  13         cat <<-EOL
  14 
  15         $SELF - Compare postfix configuration to defaults.
  16 
  17         Synopsis:
  18             $PROGAM [-h|--help] [-c|--config_dir "/absolute/path/to/directory"]
  19 
  20         []: Optional
  21         EOL
  22 }
  23 
  24 
  25 # Note that we use `"$@"' to let each command-line parameter expand to a
  26 # separate word. The quotes around `$@' are essential!
  27 # We need TEMP as the `eval set --' would nuke the return value of getopt.
  28 TEMP=`getopt -o c:h --long config_dir:,help \
  29      -n "$SELF" -- "$@"`
  30 
  31 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
  32 
  33 # Note the quotes around `$TEMP': they are essential!
  34 eval set -- "$TEMP"
  35 
  36 while true ; do
  37         case "$1" in
  38                 -h|--help) usage; exit 0; shift ;;
  39                 -c|--config-dir) CONFIG_DIR="$2" ; shift 2 ;;
  40                 #-c|--c-long)
  41                 #       # c has an optional argument. As we are in quoted mode,
  42                 #       # an empty parameter will be generated if its optional
  43                 #       # argument is not found.
  44                 #       case "$2" in
  45                 #               "") echo "Option c, no argument"; shift 2 ;;
  46                 #               *)  echo "Option c, argument \`$2'" ; shift 2 ;;
  47                 #       esac ;;
  48                 --) shift ; break ;;
  49                 *) echo "Internal error!" ; exit 1 ;;
  50         esac
  51 done
  52 
  53 
  54 if [ "$CONFIG_DIR" == "/etc/postfix" ]; then
  55         echo "Comparing to default config_dir '/etc/postfix'";
  56         CONF_CURRENT="$(postconf -n)"
  57 elif [ -n "$CONFIG_DIR" ] && [ -d "$CONFIG_DIR" ]; then
  58         echo "Comparing to specifed config_dir '$CONFIG_DIR'";
  59         CONF_CURRENT="$(postconf -n -c "$CONFIG_DIR")"
  60 else
  61         cat <<-EOL
  62 
  63                 Error: Invalid argument to option '-c|--config_dir': '$CONFIG_DIR'.
  64                 Maybe:
  65                  * undefined
  66                  * not a directory
  67         EOL
  68         usage
  69         exit 1
  70 fi
  71 
  72 while read LINE; do
  73         KEY="$(sed -r 's/^([[:alnum:]_$-]+)\s*=.*$/\1/' <<< "$LINE")"
  74         echo -e "\n= Key: '$KEY' ="
  75         VALUE="$(sed -r 's/.*=\s*([^=]+)$/\1/' <<< "$LINE")"
  76         VALUE="$(fold -s <<< "$VALUE")"
  77         if [ -z "$VALUE" ] || grep -E '=$' <<< "$VALUE"; then
  78                 VALUE="NULL"
  79         fi
  80         echo -e "Current: '$VALUE'"
  81         DEFAULT="$(postconf -d "$KEY" 2>&1 \
  82                 |sed -r 's/.*=\s*([^=]+)$/\1/')"
  83         if grep -E 'unknown parameter' <<< "$DEFAULT"; then
  84                 echo "postconf -d '$KEY' -> warned unknown parameter - custom/typo?"
  85                 DEFAULT="NO DEFAULT"
  86         elif [ -z "$DEFAULT" ] || grep -Eq '=$' <<< "$DEFAULT"; then
  87                 DEFAULT="NULL"
  88         fi
  89         DEFAULT="$(fold -s <<< "$DEFAULT")"
  90         echo -e "Default: '$DEFAULT'"
  91 
  92 done <<< "${CONF_CURRENT}"

Analyse aliases file

/usr/local/bin/postfix_test_aliases.sh

   1 #!/bin/bash
   2 # Copyright Rockstable IT 2020
   3 # License: GPLv2+
   4 # Delivered as is, no warranty, no liability,…
   5 
   6 ### INITIALIZE
   7 declare -a DOMAIN_BLACKLIST
   8 BLACKLIST=false
   9 FILE="/etc/aliases"
  10 ALIAS_COUNT=0
  11 ADDRESS_COUNT=0
  12 KEEP=0
  13 KEEP_FDA=0
  14 KEEP_PURPOSE=0
  15 REMOVE=0
  16 REMOVE_BLACKLIST=0
  17 REMOVE_REDUNDANT=0
  18 LINE_NUMBER=0
  19 PRINT="ALL"
  20 PROGRAM="$(basename $0)"
  21 SYNTAX_ERROR_COUNT=0
  22 
  23 ### FUNCTIONS
  24 split () {
  25         local DELIM="$1"
  26         local STRING="$2"
  27         local IFS
  28         local OIFS
  29         ### ARRAY IS DECLARED LOCALLY (no -g)
  30         declare -a ARRAY
  31 
  32         OIFS="$IFS"
  33         IFS="$DELIM"
  34         ARRAY=( ${STRING// /} )
  35         IFS="$OIFS"
  36         echo "${ARRAY[@]}"
  37 }
  38 
  39 usage () {
  40         cat <<-EOL
  41         $PROGRAM - Analyse postfix aliases file
  42 
  43         Synopsis:
  44         $PROGRAM \\
  45                 [-a|--aliases /path/to/aliases] [-k|--keepable] [-r|--removeable [-s|--short] \\
  46                 [--] [domain1.tld] [domain2.tld2] […]
  47 
  48         []: optional
  49         (): mandatory
  50 
  51         Most useful when blacklist domain is specified.
  52         EOL
  53 }
  54 
  55 ### PARSE OPTIONS
  56 # Note that we use `"$@"' to let each command-line parameter expand to a
  57 # separate word. The quotes around `$@' are essential!
  58 # We need TEMP as the `eval set --' would nuke the return value of getopt.
  59 TEMP=`getopt -o a:hkrs --long aliases:,help,keepable,removeable,short \
  60      -n "$PROGRAM" -- "$@"`
  61 
  62 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
  63 
  64 # Note the quotes around `$TEMP': they are essential!
  65 eval set -- "$TEMP"
  66 
  67 while true ; do
  68         case "$1" in
  69                 -a|--aliases)           FILE="$2" ; shift 2 ;;
  70                 -h|--help)              usage; exit 0 ; shift ;;
  71                 -k|--keepable)          PRINT="KEEPABLE" ; shift ;;
  72                 -r|--removeable)        PRINT="REMOVABLE" ; shift ;;
  73                 -s|--short)             SHORT=true ; shift ;;
  74 
  75                 #-c|--c-long)
  76                 #       # c has an optional argument. As we are in quoted mode,
  77                 #       # an empty parameter will be generated if its optional
  78                 #       # argument is not found.
  79                 #       case "$2" in
  80                 #               "") echo "Option c, no argument"; shift 2 ;;
  81                 #               *)  echo "Option c, argument \`$2'" ; shift 2 ;;
  82                 #       esac ;;
  83                 --) shift ; break ;;
  84                 *) echo "Internal error!" ; exit 1 ;;
  85         esac
  86 done
  87 ##echo "Remaining arguments:"
  88 ##for arg do echo '--> '"\`$arg'" ; done
  89 
  90 DOMAIN_BLACKLIST=( "$@" )
  91 
  92 if [ ${#DOMAIN_BLACKLIST[@]} -ge 1 ]; then
  93         BLACKLIST=true
  94         echo "Blacklisted domains: '${DOMAIN_BLACKLIST[@]}'"
  95 fi
  96 
  97 ### MAIN
  98 
  99 # PREPARE FILE
 100 ALIASES_RAW="$(cat "$FILE")"
 101 ALIASES_CLEANED="$(sed -r '/^\s*(#.*)?$/d' <<< "$ALIASES_RAW")"
 102 ALIASES_JOINED="$(sed -zr 's/\n\s+/ /g' <<< "$ALIASES_CLEANED")"
 103 
 104 # ANALYSE LINES
 105 while read LINE; do
 106         ((ALIAS_COUNT++))
 107         unset DEST_ADDRESS
 108         unset FDA
 109 
 110         if grep -qE '^@' <<< "$LINE"; then
 111                 FDA=true
 112         fi
 113 
 114         ALIAS="$(sed -r 's/(^[^: ]+):?\s.*/\1/' <<< "$LINE")"
 115         DEST_STR="$(sed -r 's/(^[^: ]+):?\s+([^,]+)/\2/' <<< "$LINE")"
 116         LINE_NUMBER="$(awk '/'"$ALIAS"'/{ print NR; exit }' <<< "$ALIASES_RAW")"
 117 
 118         ### CHECK DESTINATION STRING
 119         COUNT_WORDS="$(wc -w <<< "$DEST_STR")"
 120         COUNT_COMMAS="$(tr -d -c ',' <<< "$DEST_STR" \
 121                 |awk '{ print length }')"
 122         if [ "$COUNT_WORDS" -gt 2 ] && \
 123                 [ "$COUNT_COMMAS" -lt "$((COUNT_WORDS-1))" ]; then
 124                 SYNTAX="Check of line '$LINE_NUMBER' failed:"
 125                 SYNTAX+=" Words: '$COUNT_WORDS'"
 126                 SYNTAX+=", Commas: '$COUNT_COMMAS'"
 127                 SYNTAX+=", Commas expected: '$((COUNT_WORDS-1))'"
 128                 ((SYNTAX_ERROR_COUNT++))
 129         else
 130                 SYNTAX="Fine."
 131         fi
 132 
 133         # GET LOCAL PART
 134         ALIAS_LOCAL="${ALIAS/@*/}"
 135         [ -z "$ALIAS_LOCAL" ] && ALIAS_LOCAL="NULL"
 136 
 137         # GET DOMAIN PART
 138         if grep -Eq '@[^@]+' <<< "${ALIAS}"; then
 139                 ALIAS_DOMAIN="${ALIAS/*@/}"
 140         else
 141                 ALIAS_DOMAIN="NULL"
 142         fi
 143 
 144         ### bash4.4
 145         #mapfile -d ';' -t LOCAL < <(printf '%s;' "${DEST/,\s+/,/}")
 146 
 147         declare -a DEST_ADDRESS
 148         DEST_ADDRESSES=( $(split "," "$DEST_STR") )
 149 
 150         for DEST_ADDRESS in ${DEST_ADDRESSES[@]}; do
 151                 ((ADDRESS_COUNT++))
 152                 unset ACTION
 153 
 154                 # GET LOCAL PART
 155                 DEST_LOCAL="${DEST_ADDRESS/@*/}"
 156                 [ -z "$DEST_LOCAL" ] && DEST_LOCAL="NULL"
 157 
 158                 # GET DOMAIN PART
 159                 if grep -Eq '@[^@]+' <<< "${DEST_ADDRESS}"; then
 160                         DEST_DOMAIN="${DEST_ADDRESS/*@/}"
 161                 else
 162                         DEST_DOMAIN="NULL"
 163                 fi
 164 
 165                 ### ANALYSE
 166                 if [ $FDA ]; then
 167                         ACTION="keep"
 168                         REASON="fda"
 169                 fi
 170 
 171                 if      [ $BLACKLIST ] && \
 172                         [ "$ALIAS_LOCAL" == "$DEST_LOCAL" ] && \
 173                         [ "$ALIAS_DOMAIN" == "NULL" ] && \
 174                         grep -Eq "$DEST_DOMAIN" <<< "${DOMAIN_BLACKLIST[@]}"; then
 175                         ACTION="remove"
 176                         REASON="blacklist"
 177                 elif [ "$ALIAS_LOCAL" == "$DEST_LOCAL" ] && \
 178                         [ "$ALIAS_DOMAIN" == "$DEST_DOMAIN" ]; then
 179                         ACTION="remove"
 180                         REASON="redundant"
 181                 else
 182                         ACTION="keep"
 183                         REASON="purpose"
 184                 fi
 185 
 186                 case "$ACTION" in
 187                         "keep") ((KEEP++));;
 188                         "remove") ((REMOVE++));;
 189                 esac
 190 
 191                 case "$REASON" in
 192                         "fda") ((KEEP_FDA++));;
 193                         "purpose") ((KEEP_PURPOSE++));;
 194                         "blacklist") ((REMOVE_BLACKLIST++));;
 195                         "redundant") ((REMOVE_REDUNDANT++));;
 196                 esac
 197 
 198 
 199                 ### OUTPUT
 200                 if [ "$PRINT" == "ALL" ] || \
 201                         ([ "$PRINT" == "REMOVABLE" ]    && [ "$ACTION" == "remove" ]) || \
 202                         ([ "$PRINT" == "KEEPABLE" ]     && [ "$ACTION" == "keep" ]) ; then
 203                         [ ! $SHORT ] && echo
 204                         echo "Alias: $ALIAS"
 205                         if [ ! $SHORT ]; then
 206                                 echo "Line:             $LINE_NUMBER"
 207                                 echo -e "Syntax:                $SYNTAX"
 208                                 echo "Raw Line: $LINE"
 209                                 echo "Alias local:      $ALIAS_LOCAL"
 210                                 echo "Alias domain:     $ALIAS_DOMAIN"
 211                                 echo "Dest Address:     $DEST_ADDRESS"
 212                                 echo "Dest Local:       $DEST_LOCAL"
 213                                 echo "Dest Domain:      $DEST_DOMAIN"
 214                                 echo "Action:           $ACTION"
 215                                 echo "Reason:           $REASON"
 216                                 [ $FDA ] && echo -e "Type:\t\tFull domain alias"
 217                         fi
 218                 fi
 219         done
 220 done <<< "$ALIASES_JOINED"
 221 
 222 REMOVE1=$((REMOVE_REDUNDANT+REMOVE_BLACKLIST))
 223 
 224 cat <<-EOL
 225 
 226 = Summary =
 227 
 228 $ALIAS_COUNT    aliases have been processed.
 229 $ADDRESS_COUNT  destination addresses have been compared.
 230 $KEEP   alias-destination pairs should be kept.
 231 $KEEP_FDA       alias-destination pairs are full domain aliases (catch all).
 232 $KEEP_PURPOSE   alias-destination pairs serve a purpuse.
 233 $REMOVE_REDUNDANT       alias-destination pairs are redundant.
 234 $REMOVE_BLACKLIST       alias-destination pairs are blacklisted.
 235 $REMOVE alias-destination pairs should be removed.
 236 $SYNTAX_ERROR_COUNT     syntax errors have been found.
 237 EOL

Install

   1 aptitude install postfix mailutils 

Unix-Permissions

   1 root@mail /etc/postfix # find /etc/postfix -type f -exec chmod o-rx {} \;
   2 root@mail /etc/postfix # find /etc/postfix/ -type d -exec chmod -v 750 {} \;
   3 der Modus von „/etc/postfix/“ wurde von 0755 (rwxr-xr-x) in 0750 (rwxr-x---) geändert
   4 der Modus von „/etc/postfix/sasl“ wurde von 0755 (rwxr-xr-x) in 0750 (rwxr-x---) geändert
   5 Modus von „/etc/postfix/ldap“ als 0750 (rwxr-x---) erhalten
   6 root@mail /etc/postfix # find /etc/postfix/ -type d -exec chgrp -v postfix {} \;
   7 die Gruppe von „/etc/postfix/“ wurde von root in postfix geändert
   8 die Gruppe von „/etc/postfix/sasl“ wurde von root in postfix geändert
   9 die Gruppe von „/etc/postfix/ldap“ wurde von root in postfix geändert
  10 root@mail /etc/postfix # find /etc/postfix/ -exec chgrp -v postfix {} \;
  11 die Gruppe von „/etc/postfix/“ wurde als postfix erhalten
  12 die Gruppe von „/etc/postfix/sasl“ wurde als postfix erhalten
  13 die Gruppe von „/etc/postfix/sasl/smtpd.conf“ wurde von root in postfix geändert
  14 die Gruppe von „/etc/postfix/postfix-files“ wurde von root in postfix geändert
  15 die Gruppe von „/etc/postfix/postfix-script“ wurde von root in postfix geändert
  16 die Gruppe von „/etc/postfix/post-install“ wurde von root in postfix geändert
  17 die Gruppe von „/etc/postfix/dynamicmaps.cf“ wurde von root in postfix geändert
  18 die Gruppe von „/etc/postfix/master.cf“ wurde von root in postfix geändert
  19 die Gruppe von „/etc/postfix/ldap“ wurde als postfix erhalten
  20 die Gruppe von „/etc/postfix/ldap/mailenabled_distgroups.cf“ wurde von root in postfix geändert
  21 die Gruppe von „/etc/postfix/ldap/virtual_alias_maps_mailforwarding.cf“ wurde von root in postfix geändert
  22 die Gruppe von „/etc/postfix/ldap/transport_maps.cf“ wurde von root in postfix geändert
  23 die Gruppe von „/etc/postfix/ldap/virtual_alias_maps_sharedfolders.cf“ wurde von root in postfix geändert
  24 die Gruppe von „/etc/postfix/ldap/mailenabled_dynamic_distgroups.cf“ wurde von root in postfix geändert
  25 die Gruppe von „/etc/postfix/ldap/local_recipient_maps.cf“ wurde von root in postfix geändert
  26 die Gruppe von „/etc/postfix/ldap/virtual_alias_maps.cf“ wurde von root in postfix geändert
  27 die Gruppe von „/etc/postfix/ldap/mydestination.cf“ wurde von root in postfix geändert
  28 die Gruppe von „/etc/postfix/transport.db“ wurde von root in postfix geändert
  29 die Gruppe von „/etc/postfix/header_checks.inbound“ wurde von root in postfix geändert
  30 die Gruppe von „/etc/postfix/header_checks.inbound.db“ wurde von root in postfix geändert
  31 die Gruppe von „/etc/postfix/header_checks.internal“ wurde von root in postfix geändert
  32 die Gruppe von „/etc/postfix/header_checks.internal.db“ wurde von root in postfix geändert
  33 die Gruppe von „/etc/postfix/header_checks.submission“ wurde von root in postfix geändert
  34 die Gruppe von „/etc/postfix/header_checks.submission.db“ wurde von root in postfix geändert
  35 die Gruppe von „/etc/postfix/transport“ wurde von root in postfix geändert
  36 die Gruppe von „/etc/postfix/main.cf“ wurde von root in postfix geändert

Basics

   1 aptitude install db-util

   1 adduser postfix ssl-cert

Compatibility Level

Postfix 3.0 introduces a safety net that runs Postfix programs with backwards-compatible default settings after an upgrade. The safety net will log a warning whenever a "new" default setting could have an negative effect on your mail flow.

Postfix compares the build in compatibility_level (at compile time) to the one specified in main.cf compatibility_level (default: 0). It determines settings in default state and takes actions if compatibility_level in main.cf is less than compiled in.

Sources:

Backwards-compatible default settings that may kick in:

Restrictions

TODO

   1 ### RESTRICTIONS
   2 ### SEE: http://www.postfix.org/SMTPD_ACCESS_README.html 
   3 ### ORDER:
   4 ### 1. client, helo, etrn
   5 ### 2. client, helo, sender, relay, recipient, data, or end-of-data
   6 ### EVALUATION IS DEFERED TO "RCPT TO"
   7 ### BY 'smtpd_delay_reject' = yes (DEFAULT: yes)

   1 

Choose your setup

Postfix:

  1. local ALIAS: shared domains, UNIX system accounts
  2. virtual MAILBOX: separate domains, non-UNIX accounts
  3. virtual ALIAS: separate domains, UNIX system accounts

vmail setup

Dovecot as backend

Please prepare dovecot first by foolowing follow dovecot#vmail_setup and return here when done.

/etc/postfix/main.cf

   1 ### ALIASED DOMAINS AND ADDRESSES
   2 ### POINTING TO REMOTE DOMAINS
   3 #virtual_maps = 
   4 virtual_maps = hash:/etc/postfix/virtual
   5 virtual_alias_maps = $virtual_maps
   6 #virtual_alias_domains = $virtual_alias_maps
   7 virtual_alias_domains = hash:/etc/postfix/virtual_alias_domains
   8 
   9 ### MAILBOXED DOMAINS AND ADDRESSES WHERE THIS
  10 ### MTA IS FINAL TARGET
  11 
  12 ### ENSURE virtual_mailbox_maps IS EMPTY
  13 ### OR smtpd_reject_unlisted_recipient (default: yes)
  14 ### WILL ENFORCE EVERY USER TO BE LISTED IN THIS DB
  15 virtual_mailbox_maps = 
  16 #virtual_mailbox_domains = $virtual_mailbox_maps
  17 virtual_mailbox_domains = hash:/etc/postfix/virtual_mailbox_domains
  18 
  19 ### virtual_transport CAN BE OVERRIDDEN BY /etc/postfix/transports
  20 #virtual_transport = virtual
  21 virtual_transport = lmtp:unix:private/dovecot-lmtp

/etc/postfix/virtual_mailbox_domains

   1 rockstable.it        WORD

Query AD for virtual mailbox maps

If you don't have dovecot as a backend, you may use the following to proof that a mailbox exists by queriing AD/ldap.

Prepare your ADDC or ldap-server to support cryptography! If you use AD and bind to it with a username and password combination, you don't want your credentials to be transmitted in plain-text!

Provide the AD CA-Certificate at /etc/postfix/ldap/cacert.pem.

/etc/postfix/ldap/virtual_mailbox_users

   1 ### LOOKUP MAILBOX ADDRESSES IN AD
   2 ### FOR OPTIONS PLEASE SEE: man 5 ldap_table
   3 
   4 ### debuglevel (default: 0)
   5 #debuglevel = 0
   6 ### timeout (default: 10 seconds)
   7 timeout = 4
   8 ### version (default: 2)
   9 version = 3
  10 ### start_tls (default: no)
  11 start_tls = no
  12 ### tls_ca_cert_file (No default; set either this or tls_ca_cert_dir)
  13 tls_ca_cert_file = /etc/postfix/ldap/cacert.pem
  14 ### server_host (default: localhost)
  15 server_host =
  16         ldaps://dc1.example.com:636
  17         ldaps://dc2.example.com:636
  18 ### search_base (No default; you must configure this)
  19 search_base = CN=Users,DC=example,DC=com
  20 ### bind_dn (default: empty)
  21 bind_dn = CN=postfix,CN=Users,DC=example,DC=com
  22 ### bind_pw (default: empty)
  23 bind_pw = secure_long_password
  24 ### query_filter (default: mailacceptinggeneralid=%s)
  25 #query_filter = (&(mail=%s)(objectclass=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
  26 query_filter = (&(&(mail=*)(!(mail=HealthMailbox*)))(objectclass=person)(!(userAccountControl:1.2.840.113556.1.
  27 4.803:=2)))
  28 #query_filter = (&(objectclass=person)(userPrincipalName=%s))
  29 ### result_attribute (default: maildrop)
  30 result_attribute = mail
  31 #result_attribute = userPrincipalName

Some notes to the query_filter:

   1 ### LOOKUP PUBLIC FOLDER ADDRESSES IN AD
   2 ### FOR OPTIONS PLEASE SEE: man 5 ldap_table
   3 
   4 ### debuglevel (default: 0)
   5 #debuglevel = 0
   6 ### timeout (default: 10 seconds)
   7 timeout = 4
   8 ### version (default: 2)
   9 version = 3
  10 ### start_tls (default: no)
  11 start_tls = no
  12 ### tls_ca_cert_file (No default; set either this or tls_ca_cert_dir)
  13 tls_ca_cert_file = /etc/postfix/ldap/cacert.pem
  14 ### server_host (default: localhost)
  15 server_host =
  16         ldaps://dc1.example.com:636
  17         ldaps://dc2.example.com:636
  18 ### search_base (No default; you must configure this)
  19 search_base = CN=Microsoft Exchange System Objects,DC=example,DC=com
  20 
  21 ### bind_dn (default: empty)
  22 bind_dn = CN=postfix,CN=Users,DC=example,DC=com
  23 ### bind_pw (default: empty)
  24 bind_pw = secure_long_password
  25 ### query_filter (default: mailacceptinggeneralid=%s)
  26 #query_filter = (&(mail=%s)(objectclass=publicFolder)(!(msExchHideFromAddressLists=TRUE)))
  27 query_filter = (&(|(mail=%s)(proxyAddresses=smtp:%s))(objectclass=publicFolder)(!(msExchHideFromAddressLists=TRUE)))
  28 ### result_attribute (default: maildrop)
  29 result_attribute = mail

Please make sure to use correct unix-permissions so postfix can read the credentials by the group permssions.

   1 chown root:postfix /etc/postfix/ldap/*
   2 chmod 0640 /etc/postfix/ldap/*

You can now reference it as a lookup in
/etc/postfx/main.cf

   1 virtual_mailbox = proxy:ldap:/etc/postfix/ldap/virtual_mailbox_users

The proxy: delegates these lookups to the postfix proxymap daemon (man 8 proxymap). This may be interesting if you:

Address verify cache

   1 ### ADDRESS VERIFY CACHE
   2 address_verify_map = btree:$data_directory/verify_cache
   3 #address_verify_negative_cache = yes
   4 address_verify_negative_cache = no
   5 #address_verify_negative_expire_time = 3d
   6 #address_verify_negative_refresh_time = 3h
   7 #address_verify_positive_expire_time = 31d
   8 #address_verify_positive_refresh_time = 7d
   9 address_verify_virtual_transport = $virtual_transport

You can look inside into the verify cache with the following command:

   1 db_dump -p /var/lib/postfix/verify_cache

Crypto

   1 ### IF SYNTAX HIGHLIGHTING IS MISSING:
   2 ## -> "make vim_syntax"
   3 
   4 ciphers_insecure = RC4
   5 cipher_suite_minimum = high
   6 protocols_insecure = !SSLv2,!SSLv3,!TLSv1
   7 tls_security_level = may
   8 
   9 
  10 ### Cipherlists
  11 ##tls_export_cipherlist = aNULL:-aNULL:ALL:+RC4:@STRENGTH
  12 ##tls_high_cipherlist = aNULL:-aNULL:ALL:!EXPORT:!LOW:!MEDIUM:+RC4:@STRENGTH
  13 ##tls_low_cipherlist = aNULL:-aNULL:ALL:!EXPORT:+RC4:@STRENGTH
  14 ##tls_medium_cipherlist = aNULL:-aNULL:ALL:!EXPORT:!LOW:+RC4:@STRENGTH
  15 ##tls_null_cipherlist = eNULL:!aNULL
  16 
  17 
  18 ### LMTP Client
  19 #lmtp_enforce_tls (default: no)
  20 #lmtp_sasl_tls_security_options (default: $lmtp_sasl_security_options)
  21 #lmtp_sasl_tls_verified_security_options (default: $lmtp_sasl_tls_security_options)
  22 #lmtp_starttls_timeout (default: 300s)
  23 #lmtp_tls_CAfile (default: empty)
  24 #lmtp_tls_CApath (default: empty)
  25 #lmtp_tls_block_early_mail_reply (default: empty)
  26 #lmtp_tls_cert_file (default: empty)
  27 #lmtp_tls_ciphers (default: export)
  28 lmtp_tls_ciphers = $cipher_suite_minimum
  29 #lmtp_tls_dcert_file (default: empty)
  30 #lmtp_tls_dkey_file (default: $lmtp_tls_dcert_file)
  31 #lmtp_tls_eccert_file (default: empty)
  32 #lmtp_tls_eckey_file (default: empty)
  33 #lmtp_tls_enforce_peername (default: yes)
  34 #lmtp_tls_exclude_ciphers (default: empty)
  35 lmtp_tls_exclude_ciphers = $ciphers_insecure
  36 #lmtp_tls_fingerprint_cert_match (default: empty)
  37 #lmtp_tls_fingerprint_digest (default: md5)
  38 lmtp_tls_fingerprint_digest = sha1
  39 #lmtp_tls_force_insecure_host_tlsa_lookup (default: no)
  40 #lmtp_tls_key_file (default: $lmtp_tls_cert_file)
  41 #lmtp_tls_loglevel (default: 0)
  42 #lmtp_tls_mandatory_ciphers (default: empty)
  43 lmtp_tls_mandatory_ciphers = $cipher_suite_minimum
  44 #lmtp_tls_mandatory_exclude_ciphers (default: empty)
  45 lmtp_tls_mandatory_exclude_ciphers = $ciphers_insecure
  46 #lmtp_tls_mandatory_protocols (default: !SSLv2)
  47 lmtp_tls_mandatory_protocols  = $protocols_insecure
  48 #lmtp_tls_note_starttls_offer (default: no)
  49 #lmtp_tls_per_site (default: empty)
  50 #lmtp_tls_policy_maps (default: empty)
  51 #lmtp_tls_protocols (default: empty)
  52 lmtp_tls_protocols = $protocols_insecure
  53 #lmtp_tls_scert_verifydepth (default: 9)
  54 #lmtp_tls_secure_cert_match (default: nexthop)
  55 #lmtp_tls_security_level (default: empty)
  56 # possible values:      none, may, encrypt, dane, dane-only,
  57 #                       fingerprint, verify, secure
  58 lmtp_tls_security_level = $tls_security_level
  59 #lmtp_tls_session_cache_database (default: empty)
  60 #lmtp_tls_session_cache_timeout (default: 3600s)
  61 #lmtp_tls_trust_anchor_file (default: empty)
  62 #lmtp_tls_verify_cert_match (default: hostname)
  63 #lmtp_use_tls (default: no) <- deprecaded with 2.3 -> smtpd_tls_security_level
  64 
  65 
  66 ### SMTP Client
  67 #smtp_enforce_tls (default: no)
  68 #smtp_sasl_tls_security_options (default: $smtp_sasl_security_options)
  69 #smtp_sasl_tls_verified_security_options (default: $smtp_sasl_tls_security_options)
  70 #smtp_starttls_timeout (default: 300s)
  71 #smtp_tls_CAfile (default: empty)
  72 #smtp_tls_CApath (default: empty)
  73 #smtp_tls_block_early_mail_reply (default: no)
  74 #smtp_tls_cert_file (default: empty)
  75 #smtp_tls_cipherlist (default: empty) <- obsolete
  76 #smtp_tls_ciphers (default: export)
  77 smtp_tls_ciphers = $cipher_suite_minimum
  78 #smtp_tls_dcert_file (default: empty)
  79 #smtp_tls_dkey_file (default: $smtp_tls_dcert_file)
  80 #smtp_tls_eccert_file (default: empty)
  81 #smtp_tls_eckey_file (default: $smtp_tls_eccert_file)
  82 #smtp_tls_enforce_peername (default: yes)
  83 #smtp_tls_exclude_ciphers (default: empty)
  84 smtp_tls_exclude_ciphers = $ciphers_insecure
  85 #smtp_tls_fingerprint_cert_match (default: empty)
  86 #smtp_tls_fingerprint_digest (default: md5)
  87 smtp_tls_fingerprint_digest = sha1
  88 #smtp_tls_force_insecure_host_tlsa_lookup (default: no)
  89 #smtp_tls_key_file (default: $smtp_tls_cert_file)
  90 #smtp_tls_loglevel (default: 0)
  91 #smtp_tls_mandatory_ciphers (default: medium)
  92 smtp_tls_mandatory_ciphers = $cipher_suite_minimum
  93 #smtp_tls_mandatory_exclude_ciphers (default: empty)
  94 smtp_tls_mandatory_exclude_ciphers = $ciphers_insecure
  95 #smtp_tls_mandatory_protocols (default: !SSLv2)
  96 smtp_tls_mandatory_protocols = $protocols_insecure
  97 #smtp_tls_note_starttls_offer (default: no)
  98 #smtp_tls_per_site (default: empty)
  99 #smtp_tls_policy_maps (default: empty)
 100 #smtp_tls_protocols (default: !SSLv2)
 101 smtp_tls_protocols = $protocols_insecure
 102 #smtp_tls_scert_verifydepth (default: 9)
 103 #smtp_tls_secure_cert_match (default: nexthop, dot-nexthop)
 104 #smtp_tls_security_level (default: empty)
 105 # possible values:      none, may, encrypt, dane, dane-only,
 106 #                       fingerprint, verify, secure
 107 smtp_tls_security_level = $tls_security_level
 108 #smtp_tls_session_cache_database (default: empty)
 109 #smtp_tls_session_cache_timeout (default: 3600s)
 110 #smtp_tls_trust_anchor_file (default: empty)
 111 #smtp_tls_verify_cert_match (default: hostname)
 112 #smtp_use_tls (default: no) <- deprecaded with 2.3 -> smtp_tls_security_level
 113 
 114 
 115 ### SMTPD Server
 116 #smtpd_client_new_tls_session_rate_limit (default: 0)
 117 #smtpd_enforce_tls (default: no)
 118 #smtpd_sasl_tls_security_options (default: $smtpd_sasl_security_options)
 119 #smtpd_starttls_timeout (default: see postconf -d output)
 120 #smtpd_tls_CAfile (default: empty)
 121 #smtpd_tls_CApath (default: empty)
 122 #smtpd_tls_always_issue_session_ids (default: yes)
 123 #smtpd_tls_ask_ccert (default: no)
 124 #smtpd_tls_auth_only (default: no)
 125 #smtpd_tls_ccert_verifydepth (default: 9)
 126 #smtpd_tls_cert_file (default: empty)
 127 #smtpd_tls_cipherlist (default: empty) <- obsolete
 128 #smtpd_tls_ciphers (default: export)
 129 smtpd_tls_ciphers = $cipher_suite_minimum
 130 #smtpd_tls_dcert_file (default: empty)
 131 #smtpd_tls_dh1024_param_file (default: empty)
 132 #smtpd_tls_dh512_param_file (default: empty)
 133 #smtpd_tls_dkey_file (default: $smtpd_tls_dcert_file)
 134 #smtpd_tls_eccert_file (default: empty)
 135 #smtpd_tls_eckey_file (default: $smtpd_tls_eccert_file)
 136 #smtpd_tls_eecdh_grade (default: see postconf -d output)
 137 #smtpd_tls_exclude_ciphers (default: empty)
 138 smtpd_tls_exclude_ciphers = $ciphers_insecure
 139 #smtpd_tls_fingerprint_digest (default: md5)
 140 smtpd_tls_fingerprint_digest = sha1
 141 #smtpd_tls_key_file (default: $smtpd_tls_cert_file)
 142 #smtpd_tls_loglevel (default: 0)
 143 #smtpd_tls_mandatory_ciphers (default: medium)
 144 smtpd_tls_mandatory_ciphers = $cipher_suite_minimum
 145 #smtpd_tls_mandatory_exclude_ciphers (default: empty)
 146 smtpd_tls_mandatory_exclude_ciphers = $ciphers_insecure
 147 #smtpd_tls_mandatory_protocols (default: !SSLv2)
 148 smtpd_tls_mandatory_protocols = $protocols_insecure
 149 #smtpd_tls_protocols (default: none)
 150 smtpd_tls_protocols=$protocols_insecure
 151 #smtpd_tls_received_header (default: no)
 152 #smtpd_tls_req_ccert (default: no)
 153 #smtpd_tls_security_level (default: empty)
 154 # possible values:      none, may, encrypt
 155 smtpd_tls_security_level = $tls_security_level
 156 #smtpd_tls_session_cache_database (default: empty)
 157 #smtpd_tls_session_cache_timeout (default: 3600s)
 158 #smtpd_tls_wrappermode (default: no)
 159 #smtpd_use_tls (default: no) <- deprecaded with 2.3 -> smtpd_tls_security_level

You can delete all these comments in vim to get a clean version by:

   1 :g/^#[^#]/d

   1 ### Customs
   2 ciphers_insecure = RC4
   3 cipher_suite_minimum = high
   4 protocols_insecure = !SSLv2,!SSLv3,!TLSv1
   5 tls_security_level = may
   6 
   7 
   8 ### Cipherlists
   9 ##tls_export_cipherlist = aNULL:-aNULL:ALL:+RC4:@STRENGTH
  10 ##tls_high_cipherlist = aNULL:-aNULL:ALL:!EXPORT:!LOW:!MEDIUM:+RC4:@STRENGTH
  11 ##tls_low_cipherlist = aNULL:-aNULL:ALL:!EXPORT:+RC4:@STRENGTH
  12 ##tls_medium_cipherlist = aNULL:-aNULL:ALL:!EXPORT:!LOW:+RC4:@STRENGTH
  13 ##tls_null_cipherlist = eNULL:!aNULL
  14 
  15 
  16 ### LMTP Client
  17 lmtp_tls_ciphers = $cipher_suite_minimum
  18 lmtp_tls_exclude_ciphers = $ciphers_insecure
  19 lmtp_tls_fingerprint_digest = sha1
  20 lmtp_tls_mandatory_ciphers = $cipher_suite_minimum
  21 lmtp_tls_mandatory_exclude_ciphers = $ciphers_insecure
  22 lmtp_tls_mandatory_protocols  = $protocols_insecure
  23 lmtp_tls_protocols = $protocols_insecure
  24 lmtp_tls_security_level = $tls_security_level
  25 
  26 
  27 ### SMTP Client
  28 smtp_tls_ciphers = $cipher_suite_minimum
  29 smtp_tls_exclude_ciphers = $ciphers_insecure
  30 smtp_tls_fingerprint_digest = sha1
  31 smtp_tls_mandatory_ciphers = $cipher_suite_minimum
  32 smtp_tls_mandatory_exclude_ciphers = $ciphers_insecure
  33 smtp_tls_mandatory_protocols = $protocols_insecure
  34 smtp_tls_protocols = $protocols_insecure
  35 smtp_tls_security_level = $tls_security_level
  36 
  37 
  38 ### SMTPD Server
  39 smtpd_tls_ciphers = $cipher_suite_minimum
  40 smtpd_tls_exclude_ciphers = $ciphers_insecure
  41 smtpd_tls_fingerprint_digest = sha1
  42 smtpd_tls_mandatory_ciphers = $cipher_suite_minimum
  43 smtpd_tls_mandatory_exclude_ciphers = $ciphers_insecure
  44 smtpd_tls_mandatory_protocols = $protocols_insecure
  45 smtpd_tls_protocols=$protocols_insecure
  46 smtpd_tls_security_level = $tls_security_level

Perfect forward secrecy (PFS)

First generate Diffie-Hellmann parameters and return here afterwards: OpenSSL#Generate or renew files with Diffie-Hellman-Parameters

Enable PFS in postfix

Defaults:

   1 smtpd_tls_dh1024_param_file =
   2 smtpd_tls_dh512_param_file =
   3 smtpd_tls_eecdh_grade = auto
   4 tls_eecdh_auto_curves = X25519 X448 prime256v1 secp521r1 secp384r1
   5 tls_eecdh_strong_curve = prime256v1
   6 tls_eecdh_ultra_curve = secp384r1
   7 tlsproxy_tls_dh1024_param_file = $smtpd_tls_dh1024_param_file
   8 tlsproxy_tls_dh512_param_file = $smtpd_tls_dh512_param_file
   9 tlsproxy_tls_eecdh_grade = $smtpd_tls_eecdh_grade

Hardened:

   1 smtpd_tls_dh1024_param_file = /etc/ssl/dhparam/dhparam_2048.pem
   2 smtpd_tls_dh512_param_file = /etc/ssl/dhparam/dhparam_1024.pem
   3 smtpd_tls_eecdh_grade = strong

Makefile

Nice trick to save some work - use a Makefile
/etc/postfix/Makefile

   1 postmap:
   2         postmap /etc/postfix/access_client
   3         postmap /etc/postfix/access_helo
   4         postmap /etc/postfix/access_sender
   5         postmap /etc/postfix/access_recipient
   6         postmap /etc/postfix/body_checks
   7         postmap /etc/postfix/esmtp_access
   8         postmap /etc/postfix/header_checks
   9         postmap /etc/postfix/relay_domains
  10         postmap /etc/postfix/virtual
  11         postmap /etc/postfix/transport
  12         newaliases
  13 
  14 vim_syntax:
  15         cat vim_syntax.vim >> /usr/share/vim/vim73/syntax/pfmain.vim

Define a syntax-file to be appended
/etc/postfix/vim_syntax.vim

   1 syntax keyword pfmainConf ciphers_insecure
   2 syntax keyword pfmainConf cipher_suite_minimum
   3 syntax keyword pfmainConf protocols_insecure
   4 syntax keyword pfmainConf tls_security_level
   5 
   6 syntax match pfmainRef "$\<ciphers_insecure\>"
   7 syntax match pfmainRef "$\<cipher_suite_minimum\>"
   8 syntax match pfmainRef "$\<protocols_insecure\>"
   9 syntax match pfmainRef "$\<tls_security_level\>"

   1 make postmap

Submission

Prepare postfix for dovecot submission:

Because dovecot-submissiond binds to tcp/587 we need to add an alternate submission port to /etc/services.

   1 submission-alt  10587/tcp                       # Submission [RFC4409]
   2 

Now we configure /etc/postfix/master.cf to fire up a submission-service bound to localhost.

Postgrey

Wenn eine Email an den Mail-Server versendet zugestellt wird, trägt "postgrey" ein Tripel aus (Client, Sender, Recipient) zusammen mit einem Timestamp in die Datenbank "/var/lib/postgrey/postgrey.db" ein, sollte dieses noch nicht dort zu finden sein. Postgrey versendet einem solchen unbestätigten Client dann ein Return-Code 450 "Try again later". Ist ein konfigurierbares Delay (Default: 300s) erreicht, so ist es dem Client erneut gestattet die Email einzuliefern. Die Datenbank wird standardmäßig von Triplets befreit, zu welchen es seit 35d keinen Kontakt mehr gab. Postgrey stellt Whitelists für clients und recipients bereit.

Ich halte postgrey im Produktivbetrieb für absolut einsetzbar, denn nur die erste Email eines Triplets wird um 5min verzögert.

Evtl. kann das Bereinigungsintervall auf einen höheren Wert gesetzt werden, um seltene Prozesse zu beschleunigen oder interne Server von denen ständig wechselnde Email-Adressen kommt, in die Whitelist eingetragen werden.

About Postgrey

Configuration

   1 root@mail /etc/postgrey # cat /etc/default/postgrey
   2 # postgrey startup options, created for Debian
   3 
   4 # you may want to set
   5 #   --delay=N   how long to greylist, seconds (default: 300)
   6 #   --max-age=N delete old entries after N days (default: 35)
   7 # see also the postgrey(8) manpage
   8 
   9 POSTGREY_OPTS="--inet=127.0.0.1:10023"
  10 
  11 # the --greylist-text commandline argument can not be easily passed through
  12 # POSTGREY_OPTS when it contains spaces.  So, insert your text here:
  13 #POSTGREY_TEXT="Your customized rejection message here"
  14 

Inclusion via restriction in /etc/postfix/main.cf

   1 smtpd_recipient_restrictions =
   2 
   3         check_policy_service inet:127.0.0.1:10023,
   4 

Whitelists

   1 root@mail /etc/postgrey # ls -1 /etc/postgrey/*
   2 /etc/postgrey/whitelist_clients
   3 /etc/postgrey/whitelist_clients.local
   4 /etc/postgrey/whitelist_recipients
   5 /etc/postgrey/whitelist_recipients.local

Whitelist format for recipient addresses

domain.addr              "domain.addr" domain and subdomains.
name@                    "name@.*" and extended addresses "name+blabla@.*".
name@domain.addr         "name@domain.addr" and extended addresses.
/regexp/                 anything that matches "regexp" (the full address is matched).

Whitelist format for client addresses

domain.addr              "domain.addr" domain and subdomains.
IP1.IP2.IP3.IP4          IP address IP1.IP2.IP3.IP4. You can also leave off one number, in which case only the first specified numbers will be checked.
IP1.IP2.IP3.IP4/MASK     CIDR-syle network. Example: 192.168.1.0/24
/regexp/                 anything that matches "regexp" (the full address is matched).

policy-weightd

policyd-weight(8) is a SMTP policy daemon written in perl(1) for postfix(1). It evaluates based on RBL/RHSBL results, HELO and MAIL FROM domain and subdomain arguments and the client IP address the possibility of forgery or SPAM. It is designed to be called before the SMTP DATA command at the RCPT TO stage. This way it is a) possible to reject a mail attempt before the body has been received and b) to keep multirecipient mail intact, i.e. provide the functionality of selective usage based on recipients.

Configuration

   1 root@mail /etc (git)-[master] # cat /etc/policyd-weight.conf
   2 #policyd-weight  uses  a perl(1) style configuration file which it reads
   3 #on  startup.  The  cache  re-reads  the  configuration  after  $MAINTE‐
   4 #NANCE_LEVEL  (default:  5) queries. If -f is not specified, it searches
   5 #for configuration files on following locations:
   6 
   7 
   8 #CACHE SETTINGS
   9 #       $CACHESIZE (default: 2000)
  10 #              Set the minimum size of the SPAM cache.
  11 #       $CACHEMAXSIZE (default: 4000)
  12 #              Set the maximum size of the SPAM cache.
  13 #       $CACHEREJECTMSG
  14 #              (default: 550 temporarily blocked because of previous errors)"
  15 #              Set the SMTP status code and a explanatory message for  rejected
  16 #              mails due to cached results
  17 #       $NTTL (default: 1)
  18 #              The client is penalized for that many retries.
  19 $NTTL=10;
  20 #       $NTIME (default: 30)
  21 #              The  $NTTL  counter will only be decremented if the client waits
  22 #              at least $NTIME seconds.
  23 $NTIME=5;
  24 #       $POSCACHESIZE (default: 1000)
  25 #              Set the minimum size of the HAM cache.
  26 #       $POSCACHEMAXSIZE (default: 2000)
  27 #              Set the maximum size of the HAM cache.
  28 #       $PTTL (default: 60)
  29 #              After that many queries the  HAM  entry  must  succeed  one  run
  30 #              through the RBL checks again.
  31 #       $PTIME (default: 3h)
  32 #              after  $PTIME in HAM Cache the client must pass one time the RBL
  33 #              checks again.  Values must be nonfractal.  Accepted  time-units:
  34 #              s(econds), m(inutes), h(ours), d(ays)
  35 #       $TEMP_PTIME (default: 1d)
  36 #              The  client  must  pass  this time the RBL checks in order to be
  37 #              listed as hard-HAM. After this time the client will pass immedi‐
  38 #              ately  for  PTTL  within  PTIME.  Values  must  be  non-fractal.
  39 #              Accepted time-units: s(econds), m(inutes), h(ours), d(ays)
  40 
  41 
  42 #DEBUG SETTINGS
  43 #       $DEBUG (default: 0)
  44 #              Turn debugging on (1) or off (0)
  45 
  46 
  47 
  48 #DNS SETTINGS
  49 #       $DNS_RETRIES (default: 2)
  50 #              How many times a single DNS query may be repeated
  51 #       $DNS_RETRY_IVAL (default: 2)
  52 #              Retry a query without response after that many seconds
  53 #       $MAXDNSERR (default: 3)
  54 #              If that many queries fail, the mail is accepted with  $MAXDNSER‐
  55 #              RMSG.
  56 #              In total DNS queries this means: $MAXDNSERR * $DNS_RETRIES
  57 
  58 
  59 #MISC SETTINGS
  60 #       $MAINTENANCE_LEVEL (default: 5)
  61 #              After  that  many  policy requests the cache (and in daemon mode
  62 #              child processes) checks for configuration file changes
  63 #       $MAXIDLECACHE (default: 60)
  64 #              After that many seconds of being idle the cache checks for  con‐
  65 #              figuration file changes.
  66 #       $PIDFILE (default: /var/run/policyd-weight.pid)
  67 #              Path and filename to store the master pid (daemon mode)
  68 #       $LOCKPATH (default: /tmp/.policyd-weight/)
  69 #              Directory   where   policyd-weight   stores  sockets  and  lock-
  70 #              files/directories. Its argument must contain a trailing slash.
  71 #       $SPATH (default: $LOCKPATH.'/polw.sock')
  72 #              Path and filename which the cache has to use for communication.
  73 #       $TCP_PORT (default: 12525)
  74 #              TCP port on which the policy server listens (daemon mode)
  75 #       $BIND_ADDRESS (default: '127.0.0.1')
  76 #              IP Address on which policyd-weight binds. Currently either  only
  77 #              one  or all IPs are supported. Specify 'all' if you want to lis‐
  78 #              ten on all IPs.
  79 #       $SOMAXCONN (default: 1024)
  80 #              Maximum connections which policyd-weight accepts.  This  is  set
  81 #              high enough to cover most scenarios.
  82 #       $USER (default: polw)
  83 #              Set the user under which policyd-weight runs
  84 #       $GROUP (default: $USER)
  85 #              Set the group under which policyd-weight runs
  86 
  87 
  88 #OUTPUT AND LOG SETTINGS
  89 #       $ADD_X_HEADER (default: 1)
  90 #              Insert a X-policyd-weight: header with evaluation messages.
  91 #              1 = on, 0 = off
  92 #       $LOG_BAD_RBL_ONLY (default: 1)
  93 #              Insert  only  RBL  results  in  logging strings if the RBL score
  94 #              changes the overall score. Thus RBLs with  a  GOOD  SCORE  of  0
  95 #              don't appear in logging strings if the RBL returned no BAD hit.
  96 #              1 = on, 0 = off
  97 #       $MAXDNSBLMSG (default: 550 Your MTA is listed in too many DNSBLs)
  98 #              The  message sent to the client if it was reject due to $MAXDNS‐
  99 #              BLHITS and/or $MAXDNSBLSCORE.
 100 #       $REJECTMSG (default: 550 Mail appeared to be SPAM or forged.  Ask  your
 101 #       Mail/DNS-Adminisrator  to  correct  HELO  and DNS MX settings or to get
 102 #       removed from DNSBLs)
 103 #              Set the SMTP status code for rejected mails and  a  message  why
 104 #              the action was taken
 105 
 106 
 107 
 108 #RESOURCE AND OPTIMIZATIONS
 109 #       $CHILDIDLE (default: 120)
 110 #              How  many  seconds  a  child  may be idle before it dies (daemon
 111 #              mode)
 112 #       $MAX_PROC (default: 50)
 113 #              Process limit on how many processes  policyd-weight  will  spawn
 114 #              (daemon mode)
 115 #       $MIN_PROC (default: 2)
 116 #              Minimum child processes which are kept alive in idle times (dae‐
 117 #              mon mode)
 118 #       $PUDP (default: 0)
 119 #              Set persistent UDP connections used for DNS queries  on  (1)  or
 120 #              off (0).
 121 
 122 
 123 
 124 #SCORE SETTINGS
 125 #       Positive values indicate a bad (SPAM) score, negative values indicate a
 126 #       good (HAM) score.
 127 #       @bogus_mx_score (2.1, 0)
 128 #              If the sender domain has neither  MX  nor  A  records  or  these
 129 #              records resolve to a bogus IP-Address (for instance private net‐
 130 #              works) then this check asigns the full score of  bogus_mx_score.
 131 #              If  there  is no MX but an A record of the sender domain then it
 132 #              receives a penalty only if DNSBL-listed.
 133 #              Log Entries:
 134 #              BOGUS_MX
 135 #               The sender A and MX records are bogus or empty.
 136 #              BAD_MX
 137 #               The sender domain has an empty  or  bogus  MX  record  and  the
 138 #               client is DNSBL listed.
 139 #              Related RFCs:
 140 #              [1918] Address Allocation for Private Internets
 141 #              [2821] Simple Mail Transfer Protocol (Sect 3.6 and Sect 5)
 142 #       @client_ip_eq_helo_score (1.5, -1.25)
 143 #              Define  scores  for  the  match of the reverse record (hostname)
 144 #              against the HELO argument. Reverse lookups are done, if the for‐
 145 #              ward lookups failed and are not trusted.
 146 #              Log Entries:
 147 #              REV_IP_EQ_HELO
 148 #               The  Client's  PTR  matched  the  HELO  argument.
 149 #              REV_IP_EQ_HELO_DOMAIN
 150 #               Domain portions  of Client PTR and HELO argument matched.
 151 #              RESOLVED_IP_IS_NOT_HELO
 152 #               Client  PTRs  found   but  did  not  match  HELO argument.
 153 #       @helo_score (1.5, -2)
 154 #              Define  scores for the match of the Client IP and its /24 subnet
 155 #              against the A records of HELO or MAIL FROM domain/host. It  also
 156 #              holds the bad score for MX verifications.
 157 #              Log Entries:
 158 #              CL_IP_EQ_HELO_NUMERIC
 159 #               Client IP matches the [IPv4] HELO.
 160 #              CL_IP_EQ_FROM_IP
 161 #               Client  IP  matches   the  A  record  of  the  MAIL FROM sender
 162 #               domain/host.
 163 #              CL_IP_EQ_HELO_IP
 164 #               Client  IP  matches  the  A  record  of the HELO argument.
 165 #              CL_IP_NE_HELO
 166 #               The IP and  the /24  subnet did  not  match  A/MX  records   of
 167 #               HELO  and MAIL FROM  arguments and their subdomains.
 168 #       @helo_from_mx_eq_ip_score (1.5, -3.1)
 169 #              Define  scores  for  the  match of Client IP against MX records.
 170 #              Positive (SPAM) values are used in case the  MAIL  FROM  matches
 171 #              not the HELO argument AND the client seems to be dynamic AND the
 172 #              client is no MX for HELO and  MAIL  FROM  arguments.  The  total
 173 #              DNSBL score is added to its bad score.
 174 #              Log Entries:
 175 #              CL_IP_EQ_FROM_MX
 176 #               Client IP  matches  the MAIL FROM domain/host MX record
 177 #              CL_IP_EQ_HELO_MX
 178 #               Client IP matches the HELO domain/host MX record
 179 #              CLIENT_NOT_MX/A_FROM_DOMAIN
 180 #               Client  is  not a verified  HELO and doesn't match A/MX records
 181 #               of MAIL FROM argument
 182 #              CLIENT/24_NOT_MX/A_FROM_DOMAIN
 183 #               Client's subnet does  not  match A/MX records of the MAIL  FROM
 184 #               argument
 185 #       $dnsbl_checks_only (default: 0)
 186 #              Disable  HELO/RHSBL  verifications  and  the  like.  Do only RBL
 187 #              checks.
 188 #              1 = on, 0 = off
 189 #       @dnsbl_score (default: see below)
 190 #              A list of RBLs to be checked. If you want that  a  host  is  not
 191 #              being  evaluated any further if it is listed on several lists or
 192 #              a very trustworthy list you can control a immediate REJECT  with
 193 #              $MAXDNSBLHITS  and/or  $MAXDNSBLSCORE.  A  list  of RBLs must be
 194 #              build as follows:
 195 #              @dnsbl_score = (
 196 #                  RBLHOST1,   HIT SCORE,  MISS SCORE,     LOG NAME,
 197 #                  RBLHOST2,   HIT SCORE,  MISS SCORE,     LOG NAME,
 198 #                  ...
 199 #              );
 200 #              The default is:
 201 #              @dnsbl_score = (
 202 #                  "dynablock.njabl.org",  3.25,   0,      "DYN_NJABL",
 203 #                  "dnsbl.njabl.org",      4.25,   -1.5,   "BL_NJABL",
 204 #                  "bl.spamcop.net",       1.75,   -1.5,   "SPAMCOP",
 205 #                  "sbl-xbl.spamhaus.org", 4.35,   -1.5,   "SBL_XBL_SPAMHAUS",
 206 #                  "list.dsbl.org",        4.35,   0,      "DSBL_ORG",
 207 #                  "ix.dnsbl.manitu.net",  4.35,   0,      "IX_MANITU",
 208 #                  "relays.ordb.org",      3.25,   0,      "ORDB_ORG"
 209 #              );
 210 #       @rhsbl_score (default: see below)
 211 #              Define a list of RHSBL host which are  queried  for  the  sender
 212 #              domain.  Results  get additionally scores of 0.5 * DNSBL results
 213 #              and @rhsbl_penalty_score.  A list of RHSBL hosts to  be  queried
 214 #              must be build as follows:
 215 #              @rhsbl_score = (
 216 #                  RHSBLHOST1,  HIT SCORE,  MISS SCORE,     LOG NAME,
 217 #                  RHSBLHOST2,  HIT SCORE,  MISS SCORE,     LOG NAME,
 218 #                  ...
 219 #              );
 220 #              The default is:
 221 #              @rhsbl_score = (
 222 #                  "rhsbl.ahbl.org",              1.8,     0,  "AHBL",
 223 #                  "dsn.rfc-ignorant.org",        3.2,     0,  "DSN_RFCI",
 224 #                  "postmaster.rfc-ignorant.org", 1 ,      0,  "PM_RFCI",
 225 #                  "abuse.rfc-ignorant.org",      1,       0,  "ABUSE_RFCI"
 226 #              );
 227 #       @rhsbl_penalty_score (3.1, 0)
 228 #              This  score  will be added to each RHSBL hit if following crite‐
 229 #              rias are met:
 230 #                  Sender has a random local-part (i.e. yztrzgb@example.tld)
 231 #               or MX records of sender domain are bogus
 232 #               or FROM matches not HELO
 233 #               or HELO is untrusted (Forward record matched, reverse record
 234 #                  did not match)
 235 #       $MAXDNSBLHITS (default: 2)
 236 #              If the client is listed in more than $MAXDNSBLHITS RBLs it  will
 237 #              be  rejected  immediately  with $MAXDNSBLMSG and without further
 238 #              evaluation. Results are cached by default.
 239 #       $MAXDNSBLSCORE (default: 8)
 240 #              If the BAD SCOREs of @dnsbl_score  listed  RBLs  reach  a  level
 241 #              greater  than $MAXDNSBLSCORE the client will be rejected immedi‐
 242 #              ately with $MAXDNSBLMSG and without further evaluation.  Results
 243 #              are cached by default.
 244 #       $REJECTLEVEL (default: 1)
 245 #              Score  results equal or greater than this level will be rejected
 246 #              with $REJECTMSG
 247 

Defaults

   1 ## This is a POSIX shell fragment sourced by /etc/init.d/policyd-weight
   2 ## variable: DAEMON_OPTS
   3 ## daemon options to policyd-weight, possible options:
   4 ## 
   5 ## Options
   6 ##    -D                   Don't detach master - run master in foreground
   7 ##    -d                   Debug, don't daemonize, log to STDOUT
   8 ##    -f /path/to/file     Specify a configuration file
   9 ##    -h                   This help
  10 ##    -k                   Kill cache instance
  11 ##    -s                   Show  cache entries and exit. With -d show debug
  12 ##                         cache entries
  13 ##    -v                   Show version and exit
  14 ##
  15 ## default: unset
  16 DAEMON_OPTS="-f /etc/policyd-weight.conf"

Inclusion via restriction in /etc/postfix/main.cf

   1 smtpd_recipient_restrictions =
   2 
   3         check_policy_service inet:127.0.0.1:12525,
   4 

rspamd

For installation see rspamd

/etc/postfix/main.cf

   1 ### RSPAMD
   2 
   3 #smtpd_milters = unix:/var/lib/rspamd/milter.sock
   4 # or for TCP socket
   5 smtpd_milters = inet:localhost:11332
   6 non_smtpd_milters = inet:localhost:11332
   7 
   8 # skip mail without checks if something goes wrong
   9 milter_default_action = accept
  10 
  11 # 6 is the default milter protocol version;
  12 # prior to Postfix 2.6 the default protocol was 2.
  13 # milter_protocol = 6
  14 
  15 milter_default_action = accept
  16 milter_mail_macros = i {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer}
  17 #milter_mail_macros = i {auth_authen} {client_addr} {client_name} {mail_addr}

Sender Policy Framwork (SPF)

Only the Server behind MX-Record may send email. v=spf1 mx -all

   1 $TTL    86400
   2 $ORIGIN rockstable.it.
   3 
   4 ; SOA RECORD WITH INCREMENTED SERIAL OMITTED
   5 
   6 @               MX      10      mx1
   7                 TXT     "v=spf1 mx -all"

sendmail

Send a test email from cli

   1 FROM="root@test.rockstable.it"
   2 DST="tobias_stein@rockstable.it"
   3 echo "Test1"|sendmail -f "$FROM" "$DST"

Rockstable Wiki: postfix (last edited 2020-04-01 09:59:59 by RockStable)