This is a survival guide to Postfix. A popular Open source SMTP Agent that needs a corresponding Mail Agent (a.k.a POP3 or IMAP server) such as Dovecot or Courier-IMAP to provide a complete mail solution. We happen to use Dovecot at this time.
Mostly this survival guide is about FreeBSD[bsd] but we note Linux - Fedora Core[fc] locations, commands and other trivia where available, or relevant, or when we can remember. The postfix configuration principles are the same for all platforms - paths and some port numbers may change. Postfix installation is not covered - if you need this level of advice this guide is not for you.
Updated for Postfix 2.8.x on FreeBSD 8.x. At some point the Postfix install options were enhanced to include the option INST_BASE which changes the default script/application locations from /usr/local/sbin and /usr/local/libexec to /usr/sbin and /usr/libexec respectively, and the configuration files from /usr/local/etc/postfix to /etc/postfix. In all cases below the default paths assume this option has NOT been specified. One assumes the justification for this option is to allow the installation of test versions as non-base (modifying any config files without disturbing the base versions) and trivially reverting to the current base version if anything goes wrong during testing then, when completely happy, to reinstall the test version as the base version (using 'make config FORCE_PKG_REGISTER=yes install clean' or 'portupgrade -f package-name'). Note also, the port in installed as postfix-version or postfix-base-version package names.
Postfix can use some confusing, IOHO, terminology. We try and explain some of it here so that the, otherwise excellent, documentation can make perfect sense.
|local mail||This term refers to local, unix style mail accounts whose name is that of a user account and that typically do not have any associated domain name, for example, 'root' mail account is sent mail output from many host scripts. In unix style, mail is read by logged on users. Local mailboxes, however, are not required since local account names, such as 'root', can be mapped using the alias_maps parameter of main.cf to virtual domain mailboxes.|
|virtual alias domain||Defined by the virtual_alias_domains = parameter of main.cf are source domains where address manipulations (carried out through the virtual_alias_maps definitions) will NOT result in any address for that domain. Or to phrase in the negative form - all address manipulations will result in a mail address for another domain which can be locally hosted or be relayed to some other mail server. For example, assume that the address firstname.lastname@example.org was to be sent to email@example.com then example.com would be defined as a virtual alias domain and the actual transformation defined in virtual_alias_maps. Virtual_alias_domains do not use the virtual_mailbox_maps parameter.|
|virtual mailbox domain||Defined using the virtual_mailbox_domains = parameter of main.cf are hosted domains that have local mailboxes/Maildirs on this server or in a filesystem visible to this server. These differ from local mail in that they have a domain suffix (for example firstname.lastname@example.org). Typically the mail will be read using a Mail Agent (POP3 or IMAP) server which may also be hosted on this server in smaller configurations. Virtual_mailbox_domains require virtual_mailbox_maps which define where, for a given incoming mail account, the mail will be stored and in what format. Mail addresses for virtual_alias_domains may be transformed by using a virtual_alias_maps parameter into destinations for virtual_mailbox_domains since this transform occurs prior to lookup in the virtual_mailbox_maps.|
The term virtual_alias_maps suggests that they are only related to virtual_alias_domains which is not the case. Instead the information in the virtual_alias_map is used to manipulate mail addresses globally and will allow such forms as:
Relaying of mail, sending incoming mail to another location, is an essential process which if incorrectly configured can result in the MTA being OPEN, that is it will send mail from ANY incoming source to another location. Postfix goes to some considerable trouble to make sure that it is as difficult as possible to configure an OPEN relay. In general Postfix relaying is tied to its acceptance of incoming mail (and thus relay domains are defined in smtpd_recipient_restrictions). Mail will be relayed if:
The following commands control the operation of postfix.
# start/stop/restart postfix # preferred method uses postfix tools postfix [stop | start | reload] # OR [fc]/etc/rc.d/init.d/postfix [stop | start | restart] [fc]service postfix [stop | start | restart] [bsd]/usr/local/etc/rc.d/postfix [start | stop | restart] # OR stop using long manual method more /var/spool/postfix/pid/master.pid [gives xxx = pid] # then kill xxx # OR another manual method ps ax|grep postfix [gives xxx= pid] # then kill xxx # OR nice and quick for bsd [bsd]killall postfix # display configurations postconf [all parameters] postconf -n [only user supplied parameters] postconf -d [display all default values] postcong -m [display database types supported] postconf mail_version [displays version number] # start at boot # [bsd] add to /etc/rc.conf postfix_enable="YES" # BSD only: completely disable sendmail # in /etc/rc.conf sendmail_enable="NO" sendmail_outbound_enable="NO" sendmail_submit_enable="NO" sendmail_msp_queue_enable="NO" # linux[fc] place KXXpostfix and SXXpostfix link in rcY.d directory # XX is arbitrary and Y is run level ln /etc/rc.d/init.d/postfix /etc/rc.d/rc5.d/K69postfix ln /etc/rc.d/init.d/postfix /etc/rc.d/rc5.d/S69postfix
Defines the default locations for binaries, scripts and config files with normal postfix distributions and packages.
[fc]/usr/sbin [scripts e.g. sendmail] [fc]/usr/libexec/postfix [daemons] [bsd]/usr/local/sbin [scripts] [bsd]/usr/local/libexec/postfix [daemons]
Note: The installation option INST_BASE in FreeBSD changes the paths above to /usr/sbin and /usr/libexec respectively.
[fc]/usr/share/docs/postfix-xxx/html [where xxx is release] [bsd]/usr/local/share/doc/postfix/index.html
Postfix uses syslogd for logging which, depending on the /etc/syslog.conf file, will typically stream to /var/log/maillog. Read with either:
# read last entries vi + /var/log/maillog # OR tail [-n 20] /var/log/maillog # where -n optionally defines the number of lines at # the end of the file to be displayed. default is 10 # find specific mail-address log entries cat /var/log/maillog|grep mail-address
/var/spool/postfix /var/spool/postfix/maildrop [sendmail output location]
Used to store mail for virtual domains hosted on this server and may be in mailbox (mbox) or Maildir format. Base directory is user defined in main.cf using virtual_mailbox_base = path parameter. We use the following directory structure as an example only:
# generic mail directory structure /var/email/domains/domain-name/mailbox-name # e.g. mail for email@example.com in mailbox (mbox) format /var/email/domains/example.com/info # Maildir format /var/email/domains/domain-name/mailbox-name/Maildir/ # Maildir format uses three sub directories tmp, new, cur # virtual_mailbox_base = /var/email/domains for all above examples
# primary configuration file [fc]/etc/postfix/main.cf [bsd]/usr/local/etc/postfix/main.cf # defines ports and various services used by postfix [fc]/etc/postfix/master.cf [bsd]/usr/local/etc/postfix/master.cf # local mail alias file - used by mail originating from server # defined in main.cf using alias_maps = db:path/to/file [fc]/etc/postfix/aliases [bsd]/usr/local/etc/postfix/aliases # virtual domain configuration files # N.B. use any name you want for these files - just a suggestion # virtual_mailbox_domains maps # user defined in main.cf using virtual_mailbox_maps = db:path/to/file # defines mailbox name to location # e.g. virtual_mailbox_maps = hash:/etc/postfix/virtual_mboxes [fc]/etc/postfix/virtual_mboxes [bsd]/usr/local/etc/postfix/virtual_mboxes # virtual_alias_domains maps # user defined in main.cf using virtual_alias_maps = db:path/to/file # defines incoming to outgoing mailbox aliasing # e.g. virtual_alias_maps = hash:/etc/postfix/virtual_aliases [fc]/etc/postfix/virtual_aliases [bsd]/usr/local/etc/postfix/virtual_aliases
Note: The installation option INST_BASE in FreeBSD changes the paths of all configuration files from/usr/local/etc/postix to /etc/postfix.
There are many parameters controlling the behavior of postfix - this ends up being both a strength and a weakness. Adding to the confusion is that, like PERL, there is usually more than one way to do anything. The following files show the minimum parameters required to get postfix running with one or more virtual domains as a CLOSED MTA (does not allow relaying of external mail). The sample distribution file is big and well documented but can be a bit daunting. The following is the minimum required:
Word of Caution: Get a basic configuration running and deliverying email before you attempt anything else.
# main.cf - minimal file # you can always read the values of all postfix parameters # including defaults by using # postconf [all values] # postconf -n [only those defined by user] # only change the next two lines if the default username (nobody) does # not exist. On many systems installation creates a unique postfix # account and group which should be used instead default_privs = nobody mail_owner = nobody # next two lines can be omitted since they will default to # servers name and domain name myhostname = hostname.example.com mydomain = example.com # added to unqualified mailbox addresses - used by local mail service # can be ommitted if a valid aliases file exists since this does the # same thing myorigin = $mydomain # local aliases normal default value - aliases file MUST be edited alias_maps = hash:/usr/local/etc/postfix/aliases # same thing again alias_database = hash:/usr/local/etc/postfix/aliases # next line is the default so could be omitted inet_interfaces = all # defines local network which is permitted by default to relay mail # hereafter the key word mynetworks refers to this IP or IPs mynetworks = 192.168.2.0/28, 10.5.0.0/16 # controls email sent to postmaster # default is shown below - omit if this is OK notify_classes = resource,software # can also include - bounce, 2bounce, delay, policy, protocol # # VIRTUAL DOMAIN Definitions # # VIRTUAL ALIAS DOMAINS # if no address manipulation required omit this section # continue on new line if required but MUST start with a space virtual_alias_domains = example.com # next line defines the aliasing for each mailbox address virtual_alias_maps = hash:/etc/postfix/virtual_aliases # VIRTUAL MAILBOX DOMAINS # for all domains that have mailboxes on this server/filesystem # continue on new line if required but MUST start with a space virtual_mailbox_domains = example.org example.net # base for delivery to virtual_mailbox_domains virtual_mailbox_base = /var/email/domains # defines the location of each mailbox virtual_mailbox_maps = hash:/etc/postfix/virtual_mboxes
The aliases files is used to define how local mail (without a domain suffix) is mapped or aliased to either other local mail accounts or domain based mail accounts. Local mail is typically generated by server scripts, daemons and other stuff. The name of the aliases file is defined by the alias_maps parameter of main.cf.
# User defines how this file is organized from the version supplied with # postfix. It is used ONLY for mail originating on the server (normally # from applications and scripts) using unix (no domain name part) mail # accounts such as root, bin or postmaster # In a typical virtual domain configuration, local names are mapped to # useful domain based addresses such as firstname.lastname@example.org # We use the following trivial policy: # postmaster mail is mapped to email@example.com mailbox # which leaves firstname.lastname@example.org for external mail only # root is mapped to email@example.com for operational mail # such as weekly/daily/monthly reports and other such related stuff # NOTE: short extract from distribution version for illustration # of principles only # this maps all postmaster stuff to an external mailbox postmaster: firstname.lastname@example.org # this maps root to a real account root: email@example.com # address to report security problems security: firstname.lastname@example.org # DNS administrator (DNS soa records should use this) hostmaster: email@example.com # http/web service administrator www: root webmaster: root # FTP administrator (especially anonymous FTP) ftp: root
For use with virtual_mailbox_domains and specified by virtual_mailbox_maps in main.cf - defines the location and type of storage (mbox or Maildir).
Example file format:
# EXAMPLE.COM DOMAIN virtual_mboxes file # defines path to local account mail, added to virtual_mailbox_base to # create full path # uses Maildir format (end slash is vital) firstname.lastname@example.org example.com/info/Maildir/ # multiple entries may be defined for same account # this is another way of doing aliasing and perhaps avoids defining a # virtual_alias_domains entry email@example.com example.com/info/Maildir/ # here is another common example firstname.lastname@example.org example.com/jsmith/Maildir/ email@example.com example.com/jsmith/Maildir/ # this format without a trailing slash uses mailbox format firstname.lastname@example.org exmple.com/sales # mailbox and Maildir may be used on a mailbox-by-mailbox basis # when file is updated run [fc]postmap /etc/postfix/virtual_aliases [bsd]postmap /usr/local/etc/postfix/virtual_aliases # then postfix reload
Defines the alias operation to be performed on a users mailbox - for use with virtual_alias_domains.
Example File format:
# maps to example.com to example.net which may be # local (a local virtual_mailbox_domain) or remote email@example.com firstname.lastname@example.org # maps to multiple delivery mailboxes email@example.com firstname.lastname@example.org,email@example.com # maps to a local system mailbox firstname.lastname@example.org sharon # maps any other mailbox to email@example.com @example.com firstname.lastname@example.org # when file is updated run [fc]postmap /etc/postfix/virtual_aliases [bsd]postmap /usr/local/etc/postfix/virtual_aliases # then postfix reload
Note: The installation option INST_BASE in FreeBSD changes the paths of all configuration files from/usr/local/etc/postix to /etc/postfix.
Quick reminder how to add a new domain and users:
Quick reminder how to add a new user to an existing domain:
If you want to, for example, send mail addressed to email@example.com to firstname.lastname@example.org or email@example.com to a local system mailbox, this requires a virtual_alias_domain.
Quick reminder how to add a new alias domain and users:
Postfix normally sends and receives on the standard SMTP port 25. Where this is blocked, port 587 (the message or submission port) or sometimes port 465 can be used. Port 587 normally is used for secure TLS/SSL authenticated access but this is not mandatory. To listen on port 587 (and port 25) edit master.cf as shown below. This file uses symbolic names as defined in /etc/services, if port 465 were being used the first entry would be changed from submission to 465 or find the relevant name in /etc/services for 465, either will work:
# # SPECIFY ONLY PROGRAMS THAT ARE WRITTEN TO RUN AS POSTFIX DAEMONS. # ALL DAEMONS SPECIFIED HERE MUST SPEAK A POSTFIX-INTERNAL PROTOCOL. # # DO NOT SHARE THE POSTFIX QUEUE BETWEEN MULTIPLE POSTFIX INSTANCES. # # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== smtp inet n - n - - smtpd # submission port normally commented out submission inet n - n - - smtpd # -o smtpd_etrn_restrictions=reject #628 inet n - n - - qmqpd pickup fifo n - n 60 1 pickup cleanup unix n - n - 0 cleanup qmgr fifo n - n 300 1 qmgr #qmgr fifo n - n 300 1 oqmgr rewrite unix - - n - - trivial-rewrite bounce unix - - n - 0 bounce defer unix - - n - 0 bounce trace unix - - n - 0 bounce verify unix - - n - 1 verify flush unix n - n 1000? 0 flush proxymap unix - - n - - proxymap smtp unix - - n - - smtp relay unix - - n - - smtp # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - n - - showq error unix - - n - - error local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - n - - lmtp anvil unix - - n - 1 anvil scache unix - - n - 1 scache
If mail is blocked on port 25 then you may want to send all mail on an alternate port, such as 587. There are two possible solutions. First use a relay host line in main.cf as shown below:
relayhost = name.of.host:587
The relay host will receive on port 587 and then send on, say, port 25. OR declare a transport map using this statememt in main.cf:
transport_maps = hash:/name/of/file
Create the file and populate with the host name and port number as shown below:
See also 'man transport' for file format details.
Postfix contains a lot of built-in anti-spam techniques that are remarkably effective and should always be invoked before getting to resource hungry techniques such as mail scanning, for example Amavis/Spamassassin. In general the following represents a priority order in terms of resources used versus effectiveness though local circumstances and policy will always dictate the actual order of checks:
Note: In the restrictions below (helo/sender/recipient) the first one that succeeds or fails stops processing so the order is VERY important.
smtpd_delay_reject = no # required for all restrictions smtpd_helo_required = yes # apply restrictions based on the helo/ehlo message # checks are done in order defined smtpd_helo_restrictions = permit_mynetworks reject_invalid_hostname reject_unknown_hostname # costs DNS access reject_non_fqdn_hostname # test before using # allow all other stuff through permit
smtpd_delay_reject = no # required for restrictions but only once # apply restrictions based on the senders address # checks are done in order defined smtpd_sender_restrictions = # bypass checks on outgoing mail for locally originated mail permit_mynetworks reject_unknown_sender_domain # costs DNS access reject_non_fqdn_sender # allow all other stuff through permit
smtpd_delay_reject = no # required for restrictions but only once # apply restrictions based on the recipients address # checks are done in order defined smtpd_recipient_restrictions = # bypass all checks on outgoing mail from local addresses permit_mynetworks # reject if not full email address - test before using # many email clients don't sent FQDN reject_non_fqdn_recipient # next line rejects if the account/domain does not exist # ALSO prevents OPEN RELAY - if missing RELAY is OPEN!! # MUST appear before the check_recipient_access reject_unauth_destination # perform optional filtering access by recipient name check_recipient_access hash:/usr/local/etc/postfix/filter_stuff # allow all other stuff through permit
So far the actual resource use is relatively trivial. It starts to get heavier from here onwards but again in the order defined below.
SPF - Read about the technique and why we've had a SPF Record since 2004. The last stats we read suggested that over 1 million domains are now carrying SPF records while primarily preventing identity theft it is a low cost method of reducing spam and in combination with greylisting is even more powerful. SPF configuration.
Mail scanning with Amavis (Spamassassin) - this a powerful, but hungry, monster that will suck up resources. Use any other technique to get rid of the spam load then let this feature rip at anything that is left - you may not even need it. This is the reason we place amavisd/spamassassin last. Amavis (Spamassassin) configuration.
In general we do not use virus scanners such as ClamAV so they are not mentioned here. Many people do perform virus scanning of mail. Our view is that since the viruses are sent by spammers, if we stop the spam we stop the viruses. The opposing view says viruses are usually attached to mail from well known (to each user) sources when they have been infected so you should always use virus scanning. Take your choice. It is relatively simple to add clamAV to an amavisd based configuration which is the necessary first step for both scanning (content and virus) techniques.
If you are using any anti-spam technique chances are you will need a filter of some sort. You can declare incoming address filters to perform or limit any process. Filters can operate on the senders address (smtpd_sender_restrictions), helo protocol message (smtpd_helo_restrictions) or the recipients mail address in which case you will declare them using an smtpd_recipient_restrictions = clause as shown below:
# FILTERING and INCOMING Restrictions # apply restrictions based on the recipients address # checks are done in order defined smtpd_recipient_restrictions = # bypass checks on outgoing mail permit_mynetworks # reject if not full email address reject_non_fqdn_recipient # next line rejects if the account/domain does not exist # ALSO prevents OPEN RELAY - if missing RELAY is OPEN!! # MUST appear before the check_recipient_access reject_unauth_destination # perform filter access by recipient name check_recipient_access hash:/usr/local/etc/postfix/filter_stuff # allow all other stuff through permit
Finally create the file filter_stuff - to define the actions based on recipient domains or mailbox address:
# general format is # name ACTION # allows email to be piped to a script for this mailbox address only firstname.lastname@example.org FILTER script:dummy # dummy is a keyword: script may be any value and is # used to reference the filter details in master.cf # no checks on this domain OR omit it # undefined local domains will # bypass all checks defined in this file example.net OK # discard all mail for this domain example.org DISCARD
Then postmap filter_stuff to create the .dat/.db/.dbm file and postfix reload.
There are many action types that may be added to this filter file type (see man 5 access) more are illustrated for piping to a scipt, postgrey and SPF below.
Note: This configuration change uses the filter technique since it is most unlikely that you want to deliver all mail to a script. Then again why not.
To pipe mail to a script, invoke a filter using either check_recipient_access or check_sender_access. We use check_recipient_access in the example below:
# FILTERING and INCOMING Restrictions # apply restrictions based on the recipients address # checks are done in order defined smtpd_recipient_restrictions = # bypass checks on outgoing mail permit_mynetworks # reject if not full email address reject_non_fqdn_recipient # next line rejects if the account/domain does not exist # ALSO prevents OPEN RELAY - if missing RELAY is OPEN!! # MUST appear before the check_recipient_access reject_unauth_destination # perform filter access by recipient name check_recipient_access hash:/usr/local/etc/postfix/script_filter # allow all other stuff through permit
Create script_filter file to describe the actions such as shown in the example below:
# allows email to be piped to a script for this mailbox address only email@example.com FILTER script:dummy # dummy is a keyword and must be present, script may be any value and is # used to reference the filter details in master.cf # second filter uses another script destination # will reference use support in master.cf (see below) firstname.lastname@example.org FILTER support:dummy # no checks on next domain OR omit # since undefined local domains will bypass all actions # defined in this file example.net OK # when complete postmap script_filter
We illustrate only the use of FILTER support:dummy in the file above as an example. Add to the end of master.cf as shown in the snippet below:
# this pipes mail to the defined script using the # left-hand support:dummy name from script_filter file example # it could have been filter, joe, bill or whatever support unix - n n - - pipe flags=Rq user=www argv=/usr/local/www/web/support/index.php -f $(sender) -- $(recipient) # above all on one line or use a continuation # line which MUST start with one or more spaces # where: (see 'man pipe' for more info) # flags=Rq # R = Prepend Return-Path header # q = quote white space fields in $sender and $recipient # user= is mandatory and must be appropriate # example uses apache located script so runs with same user # argv= is the script destination and any required parameters # $(sender) replaced with sender address # $(recipient) replaced with recipients address # i.e. above uses a sendmail style interface
Issue 'postfix reload' to pick up the changes.
Postfix has two grey listing capabilities. An out of the box feature called greylist.pl server and postgrey which typically must be separately installed - but is available in FreeBSD ports (mail/postgrey) and as an RPM for most Linux distributions.
Adding postgrey on FreeBSD (make install clean) will install/configure:
The FreeBSD startup script (postgrey.sh) among a bunch of other parameters causes postgrey to run as a daemon but is not activated by default - test with the following:
/usr/local/etc/rc.d/postgrey rcvar $postgrey_enable=NO # to activate script add to /etc/rc.conf postgrey_enable="YES" # then start postgrey using /usr/local/etc/rc.d/postgrey start
Postgrey supports a number of parameters which can be displayed using:
Paramters are as shown below:
|--help||[or -h] displays help info|
|--version||display version number and exit|
|--verbose||[or -v] increase verbosity level|
|--syslog-facility=name||syslog facility name to use (default is mail)|
|--quiet||[or -q] decrease verbosity level|
|--pidfile=/path/to/pid||default = /var/run/postgrey.pid|
|--inet=ip:port||[or -u=] Defines the IP and port on which the postgrey will run. Optional ip and port. FreeBSD uses port 10023, Linux tends to use 6000. If no ip assumes localhost (127.0.0.1), for example, --inet=10023 is the same as --inet=127.0.0.1:10023|
|--daemonize||[or -d] run as daemon, defined in standard FreeBSD startup script|
|--user=postgrey||valid account name to run postgrey|
|--group=postgrey||valid group name to run postgrey|
|--dbdir=/path/to/db||Path to database directory. FreeBSD uses /var/db/postgrey. Default is linux standard (?) /var/spool/postfix/postgrey|
|--delay=seconds||Time to wait before re-tried mail is allowed - a black-hole period. Default = 300 = 5 mins|
|--max-age=days||Time in days to keep entry before grey listed again. Default = 35 days|
|--whitelist-clients=/path/to/file||List of sender email address actions. Default for FreeBSD is /usr/local/etc/postfix/postgrey_whitelist_clients, for linux will be /etc/postfix/postgrey_whitelist_clients. Multiple instances are allowed to define multiple files, for example, global and local versions and by default postgrep will look for a file named postgrey_whitelist_clients.local. Note: location not affected by INST_BASE in FreeBSD install options. See below for file format description.|
|--whitelist-recipients=/path/to/file||List of recipient email address actions. Default for FreeBSD is /usr/local/etc/postfix/postgrey_whitelist_recipients, for linux will normally be /etc/postfix/postgrey_whitelist_recipients. Multiple instances are allowed to define multiple files, for example, global and local versions. Note: location not affected by INST_BASE in FreeBSD install options. See below for file format details|
|--retry-window=days||Default = 2 days. Allow this time before deleting unused greylist entry i.e. default waits for up to 2 days for smtp to retry sent mail. Appending 'h' to value defines time in hours, for example 48h = 2 days.|
|--auto-whitelist-clients=number||Default = 5. The default automatically whitelists clients on receipt of 5 emails. To disable auto whitelisting completely use a value of 0.|
|--hostname=fqdn||Default is value returned by 'hostname' command, an alternate host name can be supplied and should be the same as that which appears in myhostname= of main.cf file.|
|--unix=path||Path to unix socket, unix OR inet must be present.|
|--listen-queue-size=number||Allow 'number' of operations to be queued for the postgrey socket. Default is the max allowable value = 999.|
|--x-greylist-header=text||Defines the mail header that will be added to the mail item. Default is X-Greylist: delayed %t seconds by postgrey-%v at %h; %d. (for %x values see note below table).|
|--greylist-text=text||Text sent to user. Default gives the url of a site that will give additional information about greylisting. Text can be changed but will not accept whitespace. Easiest way is to edit the postgrey script. Look for where it accesses the variable greylist-text e.g. 'cat /usr/local/sbin/postgrey|grep greylist-text'.|
|--greylist-action=TYPE||Return action to Postfix/Exim when greylisted. Default = DEFER_IF_PERMIT which tells posfix to continue and defer the mail if it would otherwise accept the message with 450 message. 451 always sends a temp fail to user. Check return actions allowed in postfix access(5) ('man 5 access'). Again the limitation here is not allowing white space in any supplied action.|
|--lookup-by-host||Use all address bits when constructing triplet = single IP.|
|--lookup-by-subnet||Default. Strip last 8 bits when constructing triplet = class C range of IPs equivalent to IP/24.|
|--privacy||Store data using SHA1 hash - default is no.|
|--exim||Default no, use only when running with Exim MTA|
Note: In text fileds the following variables may be used %s - seconds remaining of greylist time (--delay=), %t - the value of the greylist blackhole period in seconds (--delay=), %r - the mail domain name, %v - postgrey version number, %d - the Time and Date, %h - hostname (--hostname= or default).
To make changes to the command line issued on startup - find the startup script on your system (normally [bsd] /usr/local/etc/rc.d/postgrey and [fc] /etc/rc.d/init.d/postgrey and edit. FreeBSD users can just add the following to /etc/rc.conf:
# add as many entries as you want postgrey_flags="--auto-whitelist-clients=2 --max-age=60"
The file postgrey_whilelist_clients contains a list of various domains, IPs and accounts that are either whitelisted by the user or that have proven to cause greylisting problems and bypasses postgrey processing to avoid the problems. Multiple --whitelist-client files may be defined and a file with .local suffix is also looked for local senders. File format:
# postgrey whitelist for mail client hostnames # -------------------------------------------- # file is # [bsd] /usr/local/etc/postfix/postgrey_whitelist_clients or specify its path # with --whitelist-clients=/path/to/file # entries may be domain name, any part or a regular expression # anything from this address southwest.com # subdomain scd.yahoo.com # full mail address email@example.com # regular expression /^ms-smtp.*\.rr\.com$/ # IP address 192.168.2.234 # or IP range range 192.168.2.0 to 255 192.168.2
The file postgrey_whilelist_recipients contains a list of incoming mailboxes that need to bypass the delay process all for fairly obvious reasons since theoretically they are used for urgent communication - you take the hit with spam on these boxes. File format:
# postgrey whitelist for mail recipients # -------------------------------------- # put this file in /etc/postfix or specify its path # with --whitelist-recipients=xxx # mail to any of these mailboxes in any hosted domain will # bypass greylisting postmaster@ abuse@ hostmaster@
To invoke postgrey from postfix will depend on whether you want all domains or a subset both methods are shown below. Add or edit the following lines in main.cf:
# all hosted domains will use greylist smtpd_recipient_restrictions = permit_mynetworks ..... # next line MUST appear before check_policy_service or relay is OPEN reject_unauth_destination # example shows FreeBSD default port may differ on Linux distros check_policy_service inet:127.0.0.1:10023 permit .... # To greylist only some hosted (recipient) domains define a # class using next line smtpd_restriction_classes = greylist # and the class action next greylist = check_policy_access inet:127.0.0.1:10023 # now define the recipients smtpd_recipient_restrictions = permit_mynetworks ..... # next line MUST appear before check_recipient_access or relay is OPEN reject_unauth_destination # invoke postgrey filter check_recipient_access hash:/usr/local/etc/postfix/greylist_filter permit # greylist_filter file contents # only example.com and example.net will use greylisting # they invoke the defined greylist class example.com greylist example.net greylist # example.org will not use greylisting example.org OK # the above may also be omitted since by default # anything which is not met by conditions passes # without any actions # selective greylisting based on senders address # would use same class technique but # smptd_sender_restrictions = clause
Especially in conjunction with greylisting, SPF is a low-resource feature that can help reduce spam by validating the allowed sources of email from any given domain. Essentially it tries to reduce the spammers ability to forge addresses.
postfix comes with its own SPF policy daemon or you can use postfix-policyd-spf-perl which is available in FreeBSD ports (mail/postfix-policyd-spf) but it looks as if you need to do a source install for Fedora Core.
We chose to go with postfix-policyd-spf since the native version seems to require a rebuild.
Install the software using ports in FreeBSD (or use this howto for Fedora Core or any Linux distro).
Add the following line to the end of master.cf.
# all on one line OR make sure there is a whitespace # at the beginning of the continuation line spf unix - n n -- spawn user=nobody argv=/usr/local/sbin/postfix-policyd-spf
Adding SPF to main.cf uses almost the same principles as postgrey:
# all hosted domains will use spf smtpd_recipient_restrictions = permit mynetworks ..... # next line MUST appear before check_policy_service or relay is OPEN reject_unauth_destination # example shows FreeBSD default port may differ on Linux distros check_policy_service inet:127.0.0.1:10023 # if both greylisting and SPF do SPF second # since it will only work on successful results # if no greylisting remove line above will not present check_policy_service unix:private/spf permit .... # OR # To SPF check only some hosted (recipient) domains define a # class using next line smtpd_restriction_classes = greylist, spf # and the class actions spf = check_policy_service unix:private/spf greylist = check_policy_access inet:127.0.0.1:10023 # NOTE: only one smtpd_restriction_classes parameter is allowed # to define all classes used. This example shows both greylist and # spf classes. If greylisting is not being used then use # smtpd_restriction_classes = spf # and the line beginning greylist above would not be present # now define the policy filter smtpd_recipient_restrictions = permit mynetworks ..... # next line MUST appear before check_recipient_access or relay is OPEN reject_unauth_destination # postgrey - if not required remove this line check_recipient_access hash:/usr/local/etc/postfix/greylist_filter # invoke SPF filter - after postgrey if present check_recipient_access hash:/usr/local/etc/postfix/spf_filter permit # spf_filter file contents # only example.com and example.net will use spf # they invoke the defined spf class example.com spf example.net spf # example.org will not use greylisting example.org OK # the above may also be omitted since by default # anything which is not met by conditions passes # without any actions # selective spf based on senders address # would use same class technique but # smptd_sender_restrictions = clause
The minimalist documentation for postfix-policyd-spf is in [bsd] /usr/local/share/doc/postfix-policyd-spf/README.
The documentation refers to some previous names for the script. The current name is as shown.
The FreeBSD port for mail/postfix-policyd-spf uses an older vesion of libspf2 than if you only installed libspf2. We did a 'make deinstall' for libspf2 because of conflicts then re-ran 'make install clean' for postfix-policy-spf to fix the problem.
Both the postfix and the minimal postfix-policyd-spf documentation show check_policy_access unix:private/policy. The name policy is like example.com it is illustrative - we use the more meaningful (in our eyes) spf. It can be any name you want as long as the SAME name is used in main.cf and master.cf.
Unlike almost every other postfix statement you can have more than one check_recipient_access as long as each refers to a different file.
Postfix-policyd-spf is spawned by postfix whenrequired hence it is defined in master.cf unlike postgrey. Postgrey runs as a standalone daemon and is invoked with 'check_policy_access inet:127.0.0.1:10023' which contains enough information for postfix and therefore does not require an entry in master.cf.
While everone focusses on spam-filters and anti-virus checks - they consume serious computing resources. They should be the last line of defence - not the first. See General Anti-Spam Policy.
There are a bunch of mail content scanning applications which can be quite confusing - well to us. Here's a short list to help wade your way through this stuff (you can spend the rest of your life in amavisd's config file):
Chances are if you need something it's probably referenced in the amavisd.conf file. Read it carefully when you have a few spare days.
Amavisd on FreeBSD is installed from ports (security/amavisd-new-xxx and installs spamassassin and tons of other stuff) and in the case of Fedora Core you will need to install amavisd-new and spamassassin RPMs. To install amavsid and spamassassin follow this list:
Create a basic amavisd.conf file in either /etc [fc] or /usr/local/etc [bsd] by copying the basic distribution file:
cp amavisd.conf-dist amavisd.conf
There are normally two other files amavisd.conf-default (defines all the parameters) and amavisd.conf-sample (defines some sample files).
check and edit the following minimal variables in amavisd.conf:
# these are negative values leave first commented if ClamAV is installed # if ClamAV not installed uncomment as shown @bypass_virus_checks_maps = (1); # uncomment to DISABLE anti-virus code # @bypass_spam_checks_maps = (1); # uncomment to DISABLE anti-spam code # check if the installation has a user/group for either vscan [bsd] or amavis # use vipw or similar to check if not create both a user and group for # one or other $daemon_user = 'vscan'; # (no default; customary: vscan or amavis), -u $daemon_group = 'vscan'; # (no default; customary: vscan or amavis), -g # define a domain here that can receive mail $mydomain = 'example.com'; # a convenient default for other settings # change this if you have particular reasons $MYHOME = '/home/var/amavis'; # a convenient default for other settings, -H # either chage this or make sure it exists $TEMPBASE = "$MYHOME/tmp"; # working directory, needs to exist # if you want to use quarantine define directory here else set to # '' = empty string $QUARANTINEDIR = ''; # # logging options $log_level = 3; # verbosity 0..5, -d $log_recip_templ = undef; # disable by-recipient level-0 log entries $DO_SYSLOG = 1; # log via syslogd (preferred) $syslog_facility = 'mail'; # Syslog facility as a string # e.g.: mail, daemon, user, local0, ... local7 $syslog_priority = 'info'; # Syslog base (minimal) priority as a string, # choose from: emerg, alert, crit, err, warning, notice, info, debug # make sure this is the same port as used in postfix main.cf $inet_socket_port = 10024; # listen on this local TCP port(s) (see $protocol) # these should be a valid email address on your system $virus_admin = "virusalert\@$mydomain"; # notifications recip. $mailfrom_notify_admin = "virusalert\@$mydomain"; # notifications sender $mailfrom_notify_recip = "virusalert\@$mydomain"; # notifications sender $mailfrom_notify_spamadmin = "spam.police\@$mydomain"; # notifications sender $mailfrom_to_quarantine = ''; # null return path; uses original sender if undef # again check this matches postfix master.cf $notify_method = 'smtp:[127.0.0.1]:10025'; $forward_method = 'smtp:[127.0.0.1]:10025'; # set to undef with milter! # we use discard could be # D_PASS - pass mail to postfix for user # D_BOUNCE - message bounced to sender # D_REJECT - reject with 550 or (554) $final_virus_destiny = D_DISCARD; $final_banned_destiny = D_DISCARD; $final_spam_destiny = D_DISCARD;
You might want to look at the other values - the file is well laid out - but since it's executable PERL watch the formatting!.
There is a spamassassin config file in /etc/spamassassin/local.cf [fc] or /etc/mail/spamassassin/local.cf [bsd] which you can inspect but nothing vital to get a basic config working.
You can now start amavisd using:
[bsd]/usr/local/etc/rc.d/amavisd.sh start [fc]/etc/rc.d/init.d/amavisd start # confirm running with ps ax|grep amavisd # if not check /var/log/maillog
To start amavisd at boot time:
[bsd] add to /etc/rc.conf amavisd_enable="YES" # linux[fc] place Kxxamavisd and Sxxamavisd link in rcy.d directory # xx is arbitrary and y is run level ln /etc/rc.d/init.d/amavisdx /etc/rc.d/rc5.d/K70amavisd ln /etc/rc.d/init.d/amavisd /etc/rc.d/rc5.d/S70amavisd
To call amavisd from postfix add to end of master.cf as shown in the snippet below:
Watch that the port number matches that defined by $inet_socket_port = 10024; in amavisd.conf. The values shown are FreeBSD defaults.
# amavis filtering smtp-amavis unix - - - - 2 smtp -o smtp_date_done_timeout=1200 -o disable_dns_lookups=yes 127.0.0.1:10025 inet n - - - - smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o strict_rfc821_envelopes=yes
Add this in suitable place in postfix main.cf (again watch port number).
# FILTERING and INCOMING Restrictions # AMAVIS FILTERING configuration content_filter=smtp-amavis:[127.0.0.1]:10024
Now spend some serious time looking at the various setting in amavisd.conf and spamassassin's local.cf files to tweak the various parameters.
SASL is a method of negotiating what form of authentication is required when accepting, and relaying, client mail. Postfix advertises a list of available methods using AUTH responses. Postfix supports two SASL methods: The Cyrus SASL library and Dovecot's SASL feature. Since we use Dovecot it makes configuration trivial - assuming your dovecot installation supports SASL. To configure postfix for SASL (the SASL methods advertised by Postfix are defined in the dovecot.conf file, postfix just passes and accepts data) make the changes shown in main.cf:
# main.cf ... # turn on sasl and use the dovecot version smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot # this next adds to the normal postfix mail storage path of # [bsd] /var/spool/postfix and has a corresponding entry for dovecot smtpd_sasl_path = private/auth # depending on how dovecot is configured this stops postfix advertising # anonymous login smtpd_sasl_options = noanonymous # allows a non-standard format of AUTH when dealing with # older MS software broken_sasl_auth_clients = yes # now permit sasl authenticated relaying # under smtpd_recipient_restrictions add in the order # required smtpd_recipient_restrictions = permit mynetworks ... permit_sasl_authenticated # next line MUST appear or relay is OPEN ... reject_unauth_destination
The world finds your mail server for inward bound mail by using a DNS query to find one or more MX (Mail Exchanger) Resource Records as shown below:
# fragment of zone file for example.com .... # mail exchanger/mail server RR for example.com IN MX 10 mail.example.com.
If this server (mail.example.com) is not available or busy then sensible (standard compliant) mail software will continue to retry, using a backoff algiorithm of some sort, over an extended period of time - typically from 12 to 48 hours. If however the mail server is still not available at the end of this extended period then an undeliverable notice is returned to the sender who must then take action to resend the message. To minimize problems it is possible to configure one or more backup (or secondary) mail servers which can accept mail in the event the primary mail server is busy or not available for a prolonged period of time. The role of a secondary or backup mail server is to accept the mail and continually try to forward (or relay) it to the primary mail server (see also notes on postfix realying).
Backup mail servers are defined in the DNS zone file and may be in the same domain as the main mail server or any other domain as required and shown below:
# fragment of zone file for example.com .... # mail exchanger/mail server RR for example.com # The value 10 in this case is the preference value # low numbers mean most preferred and are # relative to all other preference values IN MX 10 mail.example.com. # secondary or backup mail server for example.com # in this case it is shown being supplied by another domain IN MX 20 mail.example.net.
In the above example we assume that mail.example.net (the backup mail server) is running postfix and would be configured with following additions to the main.cf file:
# main.cf ... # define the domains that are valid relay destinations relay_domains = $mydestination backed-updomain.name permit_mx_backup_networks = backed-updomain.name smtpd_recipient_restrictions = ... # enable the backup feature permit_mx_backup reject_unauth_destination # optional - allows the primary server # to be out-of-service for up to 30 days # before mail is rejected undeliverable # NOTE: this parameter affects all mail retention # times not just for backup servers maximal_queue_lifetime = 30d # defines the transfort maps to allow mail to be routed # to the primary mail server(s) # (optional - if not present the primary # DNS MX RR is used to route) transport_maps = hash:/path/to/map/file
The file format used by transport_maps is:
# generic format of transport maps file # domain.name protocol:destination.host.name # usage illustration example.com smtp:mail.example.com # or if hosted by an external service example.com smtp:mail.example.net # note: the mail host may or may not be the same # as that defined in the primary DNS MX record
Cautionary Note: You cannot, in the ordinary sense of the word, read your mail from a backup mail server. Instead the backup mail server's role is to continue to try and forward (relay) your mail at the earliest opportunity. If you use an extended timeout parameter (maximal_queue_lifetime=) of, say, 30 days then assuming your mail servers are out for an extended period of time the effect will be that when, say a customer, sends you an email it appears to be accepted but you do not respond. An undeliverable message is received perhaps 30 days later which, as we all know, is essentially meaningless. It may be better to notify customers early that you are having problems by having mail be rejected normally on the default 5 day period (or lower) even from the backup server. Finally the maximal_queue_lifetime= parameter affects all mail queues not just for backup systems.
Problems, comments, suggestions, corrections (including broken links) or something to add? Please take the time from a busy life to 'mail us' (at top of screen), the webmaster (below) or info-support at zytrax. You will have a warm inner glow for the rest of the day.
If you are happy it's OK - but your browser is giving a less than optimal experience on our site. You could, at no charge, upgrade to a W3C standards compliant browser such as Firefox