Architecture
Some mail systems such as Sendmail are implemented as one large monolithic program that does everything. One large program certainly makes it easy to share data between different parts of the system. Unfortunately, one large program also makes it easy to make fatal mistakes.
Postfix is based on semi-resident, mutually-cooperating, processes that perform specific tasks for each other, without any particular parent-child relationship. Postfix is implemented as a resident master server that runs Postfix daemon processes on demand: daemon processes to send or receive network mail messages, daemon processes to deliver mail locally. Postfix is intended to be a sendmail replacement. For this reason it tries to be compatible with existing infrastructure.
Mail queues
Postfix has four different queues: maildrop, incoming, active and deferred. Locally-posted mail is deposited into the maildrop, and is copied to the incoming queue after some cleaning up. The incoming queue is for mail that is still arriving or that the queue manager hasn't looked at yet. The active queue is a limited-size queue for mail that the queue manager has opened for delivery. Mail that can't be delivered goes to the deferred queue, so that it does not get in the way of other deliveries.
The queue manager qmgr keeps information in memory about the active queue only. The active queue size is limited on purpose: the queue manager should never run out of working memory because of a peak message workload. Whenever there is space in the active queue, the queue manager lets in one message from the incoming queue and one from the deferred queue. This guarantees that new mail will get through even when there is a large backlog.
Sendmail
The sendmail program implements the Postfix to Sendmail compatibility interface. For the sake of compatibility with existing applications, some Sendmail command-line options are recognized but silently ignored.
By default, sendmail reads a message from standard input until EOF or until it reads a line with only a . character, and arranges for delivery. sendmail attempts to create a queue file in the maildrop directory. The command mailq List the mail queue. Each entry shows the queue file ID, message size, arrival time, sender, and the recipients that still need to be delivered. The command newaliases initialize the alias database.
Suppose, you have the following file to_akadia .....
From:
To:
Subject: This is a Postfix Sendmail Test
This message is sent with the sendmail front end from the postfix mail system
-- Regards Martin
.... then you can send this local email in the known sendmail syntax as follows:
# cat to_akadia | /usr/sbin/sendmail -t -bm -v
sendmail: open maildrop/746D52C01F
# mailq or sendmail -bp
# newaliases or sendmail -bi
Pickup
The pickup daemon waits for hints that new mail has been dropped into the world-writable maildrop directory, and feeds it into the cleanup daemon. This program expects to be run from the master process manager. The pickup daemon does not interact with the outside world. It daemon runs with superuser privileges so that it 1) can open a queue file with the rights of the submitting user and 2) can access the Postfix private IPC channels. Pickup does some sanity checks, in order to protect the rest of the Postfix system.
Smtpd
The SMTP server accepts network connection requests and performs zero or more SMTP transactions per connection. Each received message is piped through the cleanup daemon, and is placed into the incoming queue as one single queue file. For this mode of operation, the program expects to be run from the master process manager. Alternatively, the SMTP server takes an established connection on standard input and deposits messages directly into the maildrop queue. In this so-called stand-alone mode, the SMTP server can accept mail even while the mail system is not running.
Cleanup
The cleanup daemon implements the final processing stage for new mail. It adds missing From: and other message headers, arranges for address rewriting to the standard user@fully.qualified.domain form, and optionally extracts recipient addresses from message headers. The cleanup daemon inserts the result as a single queue file into the incoming queue, and notifies the queue manager of the arrival of new mail. The cleanup daemon can be configured to transform addresses on the basis of canonical and virtual table lookups.
On request by the cleanup daemon, the trivial-rewrite daemon rewrites addresses to the standard user@fully.qualified.domain form. The initial Postfix version does not implement a rewriting language. Implementing one would take a lot of effort, and most sites do not need it. Instead, Postfix makes extensive use of table lookups.
Qmgr
The queue manager is the heart of the Postfix mail system. It contacts the local, smtp, or pipe delivery agents, and sends a delivery request with queue file pathname information, the message sender address, the host to deliver to if the destination is remote, and one or more message recipient addresses.
The queue manager maintains a separate deferred queue for mail that cannot be delivered, so that a large mail backlog will not slow down normal queue accesses.
The queue manager maintains a small active queue with just the few messages that it has opened for delivery. The active queue acts as a limited window on the potentially much larger incoming or deferred queues. The small active queue prevents the queue manager from running out of memory under heavy load.
Optionally, the queue manager bounces mail for recipients that are listed in the relocated table. This table contains contact information for users or even entire domains that no longer exist.
Resolve
On request by the queue manager, the resolve daemon resolves destinations. By default, it only distinguishes between local and remote destinations. Additional routing information can be specified with the optional transport table.
Bounce and Defer
On request by the queue manager, the bounce or defer daemon generates non-delivery reports when mail cannot be delivered, either due to an unrecoverable error or because the destination is unreachable for an extended period of time.
Local
The local delivery agent understands UNIX-style mailboxes, sendmail-style system-wide alias databases, and sendmail-style per-user .forward files. Multiple local delivery agents can be run in parallel, but parallel delivery to the same user is usually limited. Together with the
sendmail mail posting agent, the local delivery agent implements the familiar Sendmail user interface.
The local delivery agent has hooks for alternative forms of local delivery: you can configure it to
deliver to mailbox files in user home directories, and you can even configure it to delegate mailbox
delivery to an external command such as the popular
procmail program.
Smtp
The SMTP client looks up a list of mail exchangers for the destination host, sorts the list by preference, and tries each address in turn until it finds a server that responds. On a busy Postfix system you will see several SMTP client processes running in parallel.
Pipe
The pipe mailer is the outbound interface to other mail transports (the
sendmail program is the inbound interface) such as UUCP.
Basic Postfix Configuration
All of the many configuration parameters can be found in the main.cf file, located in the ./conf directory in the postfix source. You need not change every parameter, as they are set to sensible defaults. Here are the details on some of the more important parameters, which will affect the performance of Postfix the most. Please note that if you change the main.cf file after installation, you must issue the postfix reload command.
# postconf -d (Show default values)
# postconf -n (Show non default values)
Basic Parameters
# Mail Queue
queue_directory = /usr/local/postfix/spool
# Daemon Directory
daemon_directory = /usr/local/postfix/bin
# Mail Owner
mail_owner = postfix
-
myorigin - the origin is set to $myhostname by default, which defaults to the local hostname of the machine. This should not be used unless you are running a very small site. Most people want to change myorigin to $mydomain which will default to the parent domain of the machine name (i.e. if the hostname is rabbit.akadia.com and you are using $myhostname, the origin will be rabbit.akadia.com. On the other hand if you were using $mydomain, the origin will be akadia.com.)
# My own domain name
mydomain = akadia.com
# What domain to use in outbound mail
myorigin = $mydomain
# Listen to
inet_interfaces = all
# What domains to receive mail for
mydestination = $myhostname, localhost.$mydomain
-
mailbox_command - this parameter defines the external command to use instead of local mailbox delivery. It is a completely optional parameter. If you're interested in having procmail to do your mail, this is where you set it.
-
mynetworks - mynetworks specifies a certain list of network addresses that are local to this machine. The list is used to distinguish lusers from strangers. The addresses go in the format of X.X.X.0/X and can be separated by a comma. By default the list of all of the networks attached to the machine is a complete class A network (X.0.0.0/8), a complete class B network (X.X.0.0/16), a complete class C network (X.X.X.0/24), and so on. You can also specify a path of a pattern file instead of listing the patterns here.
# Accept Mail only from
mynetworks = 192.168.32.32/32, 195.65.134.0/26, 127.0.0.0/8
-
notify_classes - You should set up a postmaster alias that points to a human person. This alias is required to exist, so that people can report mail delivery problems. The Postfix system itself also reports problems to the postmaster alias. You may not be interested in all types of trouble reports, so this reporting mechanism is configurable. The default is to report only serious problems (resource, software) to postmaster:
# Notify Errors to
notify_classes = bounce,delay,policy,protocol,
resource,software
Address Manipulation with Postfix
Although the initial Postfix release has no address rewriting language, it can do quite a bit of address manipulation via table lookup. While a message flows through the Postfix system, its addresses are mangled in the order described in this document. Unless indicated otherwise, all parameters described here are in the main.cf file. If you change parameters of a running Postfix system, don't forget to issue a postfix reload command.
Canonical address mapping
Before the cleanup daemon stores inbound mail into the incoming queue, it uses the canonical table to rewrite all addresses in message envelopes and in message headers, local or remote. The mapping is useful to replace login names by Firstname.Lastname style addresses, or to clean up invalid domains in mail addresses produced by legacy mail systems. In addition to the canonical maps which are applied to both sender and recipient addresses, you can specify canonical maps that are applied only to sender addresses or to recipient addresses. For example:
sender_canonical_maps = hash:/etc/postfix/sender_canonical
recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
The sender and recipient canonical maps are applied before the common canonical maps.
Sender-specific rewriting is useful when you want to rewrite ugly sender addresses to pretty ones, and still want to be able to send mail to the those ugly address without creating a mailer loop.
You are a dial-up with the local name "zahn@saphir" and you want to convert this address to "martin dot zahn at akadia dot ch", so the ISP will accept the name. Enter the following line in /usr/local/postfix/etc/canonical:
zahn@saphir martin dot zahn at akadia dot ch
Canonical mapping is disabled by default. To enable, edit the canonical_maps parameter in the main.cf file and specify one or more lookup tables, separated by whitespace or commas. For example:
canonical_maps = hash:/usr/local/postfix/etc/canonical
Be sure to run
# postmap /usr/local/postfix/etc/canonical
# postfix reload
Important Note
For canonical address mapping the address must not be a local user as it is in Alias mapping |
Address masquerading
Address masquerading is a method to hide all hosts below a domain behind their mail gateway, and to make it appear as if the mail comes from the gateway itself, instead of from individual machines.
Address masquerading is disabled by default. To enable, edit the masquerade_domains parameter in the main.cf file and specify one or more domain names separated by whitespace or commas. For example:
masquerade_domains = $mydomain, akadia.ch
In this example, addresses of the form martin.zahn@rabbit.akadia.com would be rewritten to martin dot zahn at akadia dot ch.
The masquerade_exceptions configuration parameter specifies what user names should not be subjected to address masquerading. Specify one or more user names separated by whitespace or commas. For example, masquerade_exceptions = root. By default, Postfix makes no exceptions.
Important Note
Address masquerading is applied only to message headers and envelope sender addresses, not to envelope recipients, envelope addresses can be manipulated with virtual address mapping ... see next section. |
Virtual address mapping
After applying the canonical and masquerade mappings, the cleanup daemon uses the virtual table to redirect mail for all recipients, local or remote. Virtual lookups are useful to redirect mail for virtual domains to real user mailboxes, and to redirect mail for domains that no longer exist. Virtual lookups can also be used to transform Firstname.Lastname back into UNIX login names, although it seems that local aliases are a more appropriate vehicle.
virtual_alias_maps = hash:$config_directory/virtual
virtual_alias_domains = $virtual_alias_maps
Important Note
Virtual address mapping is applied only to envelope recipients; it has no effect on message headers or envelope senders, message headers and envelope sender addresses can be manipulated with address masquerading ... see previous section. |
The first line in the virtual table describes the virtual domain. This line is necessary to avoid
- Postfix does not refuse mail for unknown virtual users.
- Mail for unknown virtual users fails with "mail loops back to myself".
- Postfix refuses mail for virtual domains with "user unknown".
- Postfix refuses mail for virtual domains with "relay access denied".
The left part of the next lines defines the E-Mail address which should be forwarded, the right part are local users or external E-Mail addresses.
Example of /etc/postfix/virtual for individual addresses
arkum.ch My Virtual Domain
info@arkum.ch info@akadia.ch, martin dot zahn at akadia dot ch
zahn@arkum.ch zahn_martin@hotmail.com
Example of /etc/postfix/virtual if all addresses should be transparently forwared
arkum.ch My Virtual Domain
@arkum.ch @akadia.com
The second line defines, that all E-Mail for ARKUM.CH should be forwarded to AKADIA.COM
Relocated users table
Next, the queue manager runs each recipient name through the relocated database. This table provides information on how to reach users that no longer have an account, or what to do with mail for entire domains that no longer exist. When mail is sent to an address that is listed in this table, the message is bounced with an informative message.
Lookups of relocated users are disabled by default. To enable, edit the relocated_maps parameter in the main.cf file and specify one or more lookup tables, separated by whitespace or commas.
relocated_maps = hash:/etc/postfix/relocated
Example of /etc/postfix/relocated
hans.mueller@infoline.ch Hans Mueller has left
Alias database
When mail is to be delivered locally, the local delivery agent runs each local recipient name through the aliases database. The mapping does not affect addresses in message headers. Local aliases are typically used to implement distribution lists, or to direct mail for standard aliases such as postmaster to real people. The table can also be used to map Firstname.Lastname addresses to login names. Alias lookups are enabled by default. The default configuration depends on the system environment, but it is typically one of the following:
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
The path to the alias database file is controlled via the alias_database configuration parameter. The value is system dependent. Usually it is one of the following:
Example of /etc/aliases
# Postfix User
postfix: root
# Person who should get root's mail
root: martin dot zahn at akadia dot ch
Mail transport switch (Mail Proxy, Mail Gateway)
Once the queue manager has established the destination of a message, the optional transport table controls how the message will be delivered (this table is used by the address rewriting and resolving daemon). By default, everything is sent via the
smtp transport. The transport table can be used to send mail to a mail server in the HSZ, in this case we implement a mail gateway (proxy) in the DMZ.
Transport table lookups are disabled by default. To enable, edit the transport_maps parameter in the main.cf file and specify one or more lookup tables, separated by whitespace or commas.
transport_maps = hash:/etc/postfix/transport
Example of /etc/postfix/transport
arkum.ch smtp:[192.168.32.32]
.arkum.ch smtp:[192.168.32.32]
paragon.akadia.com local:
localhost.akadia.com local:
The first line (arkum.ch) forwards all E-Mails user@arkum.ch the internal E-Mail server on 192.168.32.32. The second line is used to forward E-Mails for user@firewall to 192.168.32.32. Do not omit the entries that deliver mail locally, or else mail will bounce with a "mail loops to myself" condition.
Keeping out Unsolicited Commercial E-mail
Junk mail is one of the most common and annoying types of e-mail abuse. Postfix offers protection against UCE (Unsolicited Commercial E-mail) via a couple of settings in main.cf. Some caution is in order, however: there's a fine line between spam and legitimate dissemination, and it's entirely possible that even modest UCE controls will cause some legitimate (i.e., desired) mail to be dropped.
See more information
here
Postfix Installation
Download
# gunzip postfix-2.2.0.tar.gz
# tar xvf postfix-2.2.0.tar
# cd postfix-2.2.0
# make makefiles CCARGS='-DDEF_CONFIG_DIR=\"/usr/local/postfix/etc\"'
# For Postfix 1.1.x
# make makefiles CCARGS=-DDEF_CONFIG_DIR=
\\\\\\\"/usr/local/postfix/etc\\\\\\\"
# make
This will install Postfix in /usr/local/postfix, and therefore no conflicts with an existing sendmail configuration will happen.
Configuration
If you are replacing an existing sendmail installation with Postfix, you may need to keep the old sendmail program running for some time in order to flush the mail queue. As superuser,
execute the following commands (your sendmail, newaliases and mailq programs may be in a different place).
# mv /usr/sbin/sendmail /usr/sbin/sendmail.OFF
# mv /usr/bin/newaliases /usr/bin/newaliases.OFF
# mv /usr/bin/mailq /usr/bin/mailq.OFF
# chmod 755 /usr/sbin/sendmail.OFF /usr/bin/newaliases.OFF
/usr/bin/mailq.OFF
In order to install or upgrade Postfix
Create a user "postfix" with a unique user id and group id. Preferably, this is an account that no-one can log into. The account does not need an executable login shell, and needs no existing home directory.
postfix:*:12345:12345:postfix:/no/where:/no/shell
Make sure there is a corresponding alias in /etc/aliases
postfix: root
Create a group "postdrop" with a group id that is not used by any other user account. Not even by the postfix user account.
postdrop:*:54321:
Run the "make install" script as the super-user
# make install
install_root: [/] /
tempdir: /tmp
config_directory: /usr/local/postfix/etc
daemon_directory: /usr/local/postfix/bin
command_directory: /usr/local/postfix/sbin
queue_directory: /usr/local/postfix/spool
sendmail_path: /usr/local/postfix/sendmail/sendmail
newaliases_path: /usr/local/postfix/sendmail/newaliases
mailq_path: /usr/local/postfix/sendmail/mailq
mail_owner: postfix
setgid_group: postdrop
manpages: /usr/local/postfix/man
sample_directory: /usr/local/postfix/sample
readme_directory: /usr/local/postfix/readme
Copy /etc/aliases to /usr/local/postfix/etc
# cd /usr/local/postfix/sendmail
# ./newaliases
Important Commands
postconf mail_version | Find out what Postfix Version is installed |
mailq | Show Mail Queue |
postsuper -d ALL | Remove bounced mail from the queue. |
postfix flush | Flush the Mail Queue |
postfix check | Check Installation |
telnet mail-abuse.org | Test your own Mailserver against attacks. |
How to check your mailserver against attacks
The delivery of unsolicited commercial email (UCE) must be avoided on a secure mailserver. But how to check the mailserver against relaying and attacks? Abuse.org offers a public mailserver, which can be used to check the own mailserver.
-
Login to your mailserver
-
Execute: telnet mail-abuse.org
Now you can see, how your system will be attacked and how secure it is.
Escape character is '^]'.
<<< 220 SMTP service ready
>>> HELO dante.mail-abuse.org
<<< 250 Requested mail action okay, completed
:Relay test: #Test 1
>>> mail from:
<<< 250 Requested mail action okay, completed
>>> rcpt to:
<<< 554 Transaction failed
>>> rset
<<< 250 Requested mail action okay, completed
:Relay test: #Test 2
.....
.....
<<< 250 Requested mail action okay, completed
>>> QUIT
<<< 221 SMTP server closing transmission channel
Tested host banner: 220 SMTP service ready
System appeared to reject relay attempts
Typical Configurations
Postfix Mailbox Host in the DMZ
Email is saved on the Postfix Mailbox Host, located in the DMZ. All clients get their E-Mail using POP or IMAP. All clients uses the Mailbox Host as their Relay-Host. The Mailbox Host delivers E-Mail directly to the recipient using DNS and SMTP. The disadvantage of this solution is, that the Mailboxes are located in the DMZ.
postfix_root = /usr/local/postfix
config_directory = $postfix_root/etc
queue_directory = $postfix_root/spool
program_directory = $postfix_root/sbin
command_directory = $program_directory
daemon_directory = $postfix_root/bin
mail_owner = postfix
mydomain = akadia.com
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain,
$mydomain, akadia.ch, arkum.ch
relayhost =
masquerade_domains = $mydomain
alias_maps = hash:$config_directory/aliases
alias_database = hash:$config_directory/aliases
notify_classes = bounce,delay,policy,protocol,resource,software
mynetworks = 193.247.121.192/28, 192.168.138.0/24, 127.0.0.0/8
maps_rbl_domains = rbl.maps.vix.com
smtpd_client_restrictions =
permit_mynetworks,
check_client_access hash:$config_directory/access,
reject_maps_rbl
Postfix Host inside the Intranet (on HSZ)
Email is saved on the Postfix Mailbox Host, located in the DMZ. All clients get their E-Mail using POP or IMAP. This example shows how to configure a Postfix Client in the HSZ, which delivers all Mail to the Relayhost 193.247.121.196.
postfix_root = /usr/local/postfix
config_directory = $postfix_root/etc
queue_directory = $postfix_root/spool
program_directory = $postfix_root/sbin
command_directory = $program_directory
daemon_directory = $postfix_root/bin
mail_owner = postfix
mydomain = akadia.com
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain,
$mydomain, akadia.ch, arkum.ch
relayhost = $mydomain
masquerade_domains = $mydomain
transport_maps = hash:$config_directory/transport
alias_maps = hash:$config_directory/aliases
alias_database = hash:$config_directory/aliases
notify_classes = bounce,delay,policy,protocol,resource,software
mynetworks = 192.168.138.0/24, 127.0.0.0/8
smtpd_client_restrictions = permit_mynetworks
akadia.com smtp:[193.247.121.196]
.akadia.com smtp:[193.247.121.196]
akadia.ch smtp:[193.247.121.196]
.akadia.ch smtp:[193.247.121.196]
arkum.ch smtp:[193.247.121.196]
.arkum.ch smtp:[193.247.121.196]
paragon local:
paragon.akadia.com local:
localhost.akadia.com local:
Postfix as a Proxy Mailhost in the DMZ
Email is saved on the Postfix Mailbox Host (192.168.138.10), located in the HSZ. The Postfix Mail-Proxy (193.247.121.196) forwards all E-Mail to the Mailbox Host in the HSZ. All clients get their E-Mail using POP or IMAP from the Mailbox Host in the HSZ. All clients use the Mail-Proxy as their Relay-Host. The Mail-Proxy delivers E-Mail directly to the recipient using DNS and SMTP. The advantage of this solution is, that the Mailboxes are located in the HSZ, therefore we suggest to use this architecture.
postfix_root = /usr/local/postfix
config_directory = $postfix_root/etc
queue_directory = $postfix_root/spool
program_directory = $postfix_root/sbin
command_directory = $program_directory
daemon_directory = $postfix_root/bin
mail_owner = postfix
mydomain = akadia.com
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain,
$mydomain, akadia.ch, arkum.ch
relayhost =
masquerade_domains = $mydomain
transport_maps = hash:$config_directory/transport
alias_maps = hash:$config_directory/aliases
alias_database = hash:$config_directory/aliases
notify_classes = bounce,delay,policy,protocol,resource,software
mynetworks = 193.247.121.192/28, 192.168.138.0/24, 127.0.0.0/8
smtpd_client_restrictions = permit_mynetworks
akadia.com smtp:[192.168.138.10]
.akadia.com smtp:[192.168.138.10]
akadia.ch smtp:[192.168.138.10]
.akadia.ch smtp:[192.168.138.10]
arkum.ch smtp:[192.168.138.10]
.arkum.ch smtp:[192.168.138.10]
Postfix as a Multi Domain Mail-Host (for ISPs)
If you want to server multiple domains, then Postfix is the right tool. Use the virtual table to configure the domains.
The optional virtual table specifies redirections for local and non-local recipients or domains. The redirections are used by the cleanup daemon. The redirections are recursive. The virtual redirection is applied only to the recipient envelope address, and does not affect message headers. Think Sendmail rule set S0, if you like. Use canonical mapping to rewrite header and envelope addresses in general.
postfix_root = /usr/local/postfix
config_directory = $postfix_root/etc
queue_directory = $postfix_root/spool
program_directory = $postfix_root/sbin
command_directory = $program_directory
daemon_directory = $postfix_root/bin
mail_owner = postfix
mydomain = akadia.com
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain, $mydomain,
$config_directory/localdomains
relayhost =
masquerade_domains = $mydomain
virtual_maps = hash:$config_directory/virtual
alias_maps = hash:$config_directory/aliases
alias_database = hash:$config_directory/aliases
notify_classes = bounce,delay,policy,protocol,resource,software
mynetworks = 193.247.121.192/28, 192.168.138.0/24, 127.0.0.0/8
smtpd_client_restrictions = permit_mynetworks
The "localdomains" file is not mapped or hashed. It uses plain text, one listing per line. It's equivalent to class w with sendmail.
akadia.com
akadia.ch
arkum.com
arkum.ch
bohl.ch
bohl.com
Typical support for a virtual domain looks like the following:
virtual.domain Description for the Domain
postmaster@virtual.domain postmaster
user1@virtual.domain address1
user2@virtual.domain address2, address3
#
# Domain AKADIA.CH
#
akadia.ch Virtual Domain for Akadia
martin.zahn@akadia.ch zahn@akadia.com,zahn@hotmail.com
info@akadia.ch zahn@akadia.com
marianne.zahn@akadia.ch pmz@akadia.com
#
# Forward transparently all address for ARKUM.CH to AKADIA.COM
#
arkum.ch Virtual Domain for Akadia
@arkum.ch @akadia.com
#
# Domain BOHL.CH
#
bohl.ch Virtual Domain for employee
info@bohl.ch bohl@akadia.com