Receiving mail

Creating the mail store

As this section will detail how to configure the Postfix server to receive email from the network and store it into virtual mailboxes, mailboxes not belonging to system users, we must first decide where we are going to store this email. Given that the quantity of mail we receive could be quite large, especially if we are going to try and keep up with services like Google Mail, it is probably a good idea to create a separate partition or logical volume to use for this purpose. We shall not detail how to create this storage area however we shall assume that such an area has been created and formatted with a suitable filesystem.

Once we have created and mounted our mail store we can begin to configure the Postfix server to receive and store mail there but before we do so we need to perform one more task. As our mail will be received on behalf of non-system users, and consequently they will not have a user id or group id to be used for permission settings, we shall create a user and group for this purpose and ensure that the mail store is owned and has permissions configured correctly for this user and group. We can achieve this end using the example commands given below.

lisa useradd -u 5000 -m -d /mnt/mailstore -s /sbin/nologin vmail
lisa chown vmail:vmail /mnt/mailstore

Creating a domain and mailbox

Now that we have somewhere for any mail we receive to be stored we can continue the configuration process by creating some database records for a domain and a mail box. To do this we shall need to use the psql application which we used to create the tables in the previous section.

lisa su - postgres
postgres@lisa psql mail mail_admin

Using the psql application enter the SQL commands shown in the example below to create a domain entry for the hacking.co.uk domain and the spamcatcher mailbox. You will, as always, need to modify these values so that they reflect the domain which you are using and the name of a suitable mail box.

postgres=# INSERT INTO domains(name) VALUES('hacking.co.uk'); 
INSERT 0 1 
postgres=# INSERT INTO mailboxes(domain_id, username, password) VALUES(1, 'spamcatcher', '$1$/g$hfp5Tly0QAzcqhfMUuRwS.'); 
INSERT 0 1 

Configuring the Postfix server for virtual mailboxes

With our mail store created and our database records entered all which remains is to configure the Postfix server to actually use the database and message store location which we have so painstakingly created. The first part of this task requires us to revisit the Postfix configuration file and add the following configuration parameters.

/etc/postfix/main.cf
virtual_mailbox_base = /mnt/mailstore

virtual_minimum_uid = 5000
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

virtual_mailbox_domains = pgsql:/etc/postfix/pgsql/pgsql-virtual-domains.cf
virtual_mailbox_maps = pgsql:/etc/postfix/pgsql/pgsql-virtual-mailmaps.cf

As you can see the parameters we set in the above example are all fairly self explanatory. The first line configures the base directory of our mail store. All mail paths are relative to this base path which should always be configured. The second group, consisting of three lines, sets the user and group which should be used to access the mail store for a particular mailbox, in this case we are using the static mapper to always return 5000 as it makes little sense to use a different user and group for each mailbox when using a purely virtual configuration, and the minimum allowed uid which is essentially a safety net against misconfiguration if we were using table lookups for user and group values.

The final two line stanza configures Postfix to use the pgsql mapper to perform database lookups for the virtual domains which we are hosting on this server and the mappings of addresses to mailboxes. As you can see each of these entries contains a path to a configuration file which will be used to configure the pgsql mapper.

So that our pgsql mapper configuration is separated from the main Postfix configuration we shall create a new directory, under the directory already used by the Postfix daemon, and the create our pgsql specific files there.

lisa mkdir /etc/postfix/pgsql
lisa nano -w /etc/postfix/pgsql/pgsql-virtual-domains.cf

The first file we need to create will be used to configure the pgsql mapper to access the list of domains which we are hosting on this server. As you can see from the example configuration below the syntax is very similar to that of the main Postfix configuration files consisting of variable names and their values.

/etc/postfix/pgsql/pgsql-virtual-domains.cf
hosts    = database
dbname = mail
user = mail_server
password = mail_server_password

query = SELECT domain FROM active_primary_domains WHERE domain = '%s'

As usual with files of this type the configuration parameters are mostly self explanatory. The first four lines configure the database hosts which should be queried, the database name to connect to and the user name and password to connect with. The final line configures the SQL query which will be used by the pgsql mapper to determine if the domain passes the required tests to be considered as locally hosted.

Now that we have created a configuration file for the pgsql mapper which allows the Postfix daemon to map domains we need only create one more configuration file, to allow the Postfix daemon to map email addresses at those domains to mailboxes, and we are done.

lisa nano -w /etc/postfix/pgsql/pgsql-virtual-mailmaps.cf

The configuration example below uses the active_mailbox_maps database view we created earlier to greatly simplify the task of writing this query. It also uses two special escape sequences which the pgsql mapper will replace at runtime. It should be obvious from the SQL below that the %u sequence will be expanded to the user name portion of the email address while the %d sequence will be expanded to the domain name portion of the email address and that the query returns the path to the mailbox should it succeed.

/etc/postfix/pgsql/pgsql-virtual-mailmaps.cf
hosts    = database
dbname = mail
user = mail_server
password = mail_server_password

query = SELECT maildir FROM active_mailbox_maps WHERE username = '%u' AND domain = '%d'

With the configuration complete all that remains is to signal the Postfix server to reload its configuration using the provided script. This can be done using the command below.

lisa /etc/init.d/postfix reload

Testing our configuration

Now our configuration has been loaded by Postfix we can perform another simple test, this time to see if mail is correctly accepted, queued for delivery and delivered to our virtual mailbox. We shall use the telnet application as before to connect to our server and simulate a simple mail transaction.

lisa ~ # telnet localhost 25
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
220 mail.hacking.co.uk ESMTP Postfix 
MAIL FROM: someone@example.com 
250 2.1.0 OK 
RCPT TO: spamcatcher@hacking.co.uk 
250 2.1.5 OK 
DATA 
354 End data with <CR><LF>.<CR><LF> 
To: spamcatcher@hacking.co.uk 
Subject: Test Message 
 
This is a test piece of mail. 
250 2.0.0 OK: queued as A943D2D02 
QUIT 
221 2.0.0 Bye 
Connection closed by foreign host. 

We can now check that the mail was actually delivered using the command below.

lisa ls -l /mnt/mailstore/hacking.co.uk/spamcatcher/new/
total 4 
-rw------- 1 vmail vmail 615 2008-04-07 16:18 1207592291.V811I6M569230.mail 
Caution:
If this test doesn't work for you check that you have the email addresses and domains correct in all the configuration files and database records as well as when you simulated the mail transfer. If you are still having difficulties sending the test mail check the system event logs for more information.
 

Configuring mailbox quotas

Once we are confident that the Postfix server is correctly receiving mail on behalf of our users we can move on to the final step in this section and configure the operation of mailbox quotas so that our users do not receive more mail than we can reasonably store.

We begin by creating a new configuration file in which we shall store the parameters necessary to configure the pgsql mapper so that it is able to read the quota information from our database.

lisa nano -w /etc/postfix/pgsql/pgsql-virtual-mailquotas.cf

As you can see, from the configuration example below, the file is almost identical to those we used in the previous sections to configure the Postfix daemon to access our databases to look up our active domains and mailbox mappings. The only difference is the query which looks up the quota we assigned our mailbox from the authentication_view view.

/etc/postfix/pgsql/pgsql-virtual-mailquotas.cf
hosts    = database
dbname = mail
user = mail_server
password = mail_server_password

query = SELECT quota FROM authentication_view WHERE username = '%u' AND domain = '%d'

Now we have created a configuration file for the mapping of quotas to email addresses we can configure the Postfix daemon to use this file by adding the configuration settings shown below to our existing configuration. As usual we have divided our configuration into sub-sections to make it easier to see which pieces of the configuration are related.

The first section of our example contains the configuration settings required to enable quotas. The first line of this section configures the maximum mailbox size which shall be allowed if no quota is set for the user in the mailboxes table. In this instance we have decided on a limit of 1GB. The second line of this section configures the Postfix server to look for the quota assigned to a user in the database as configured in the file we created a moment ago.

The second section of the example configures some extensions to the maildir format which can greatly improve the performance of quota enforcement on large mailboxes. The first line of this section instructs the Postfix daemon to create a file to assist in the calculation of the size of the mail directory while the second line enables the use of the extended maildir format which also helps to reduce the time taken to calculate the size of a mail directory.

The third and final section controls what the Postfix daemon shall do in the event that a user's mailbox is over its assigned quota. The first line instructs the server to "bounce" the message causing a failure notification to be sent to the sender of the mail informing them of the reason it was undeliverable. The second line configures the contents of this message.

/etc/postfix/main.cf
virtual_mailbox_limit = 1073741824
virtual_mailbox_limit_maps = pgsql:/etc/postfix/pgsql/pgsql-virtual-mailquotas.cf

virtual_create_maildirsize = yes
virtual_maildir_extended = yes

virtual_overquota_bounce = yes
virtual_maildir_limit_message = Sorry, the recipient's mailbox is currently full. Please try again later.

With the configuration complete all that remains is to instruct the Postfix daemon to reload its configuration so that our changes take effect. This can be performed using the command below.

lisa /etc/init.d/postfix reload
Warning:
Although every effort has been taken to ensure that the example configuration works correctly we strongly recommend that you test quota enforcement is functioning as expected before putting the system into a production environment and, as always, we take no responsibility for the accuracy or otherwise of any examples.