Postfix
Install packages
The setup needs a whole load of packages to work. Either install them separately, or do it in a single command line.
Postfix
apt-get install postfix postfix-mysql postfix-doc
Configuration options:
General type of configuration? <-- Internet site
System mail name: <-- hostname.domain.tld
OpenSSL
apt-get install openssl
General Setup
vmail user
There’s an entry for it in master.cf, but it seems the vmail user doesn’t actually get created.
useradd vmail -d /var/vmail -m -s /bin/false
Which will create the root folder under which all the mail will be stored as well as setting its ownership appropriately.
MySQL tables
User to access the Postfix tables:
CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'password';
CREATE DATABASE 'postfix';
GRANT SELECT , INSERT , UPDATE , DELETE ON `postfix` . * TO 'postfix'@'localhost';
FLUSH PRIVILEGES;
MySQL queries to create required tables for Postfix:
USE postfix;
CREATE TABLE postfix_alias (
id int(11) unsigned NOT NULL auto_increment,
alias varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id)
UNIQUE KEY alias (alias)
) TYPE=MyISAM;
CREATE TABLE postfix_relocated (
id int(11) unsigned NOT NULL auto_increment,
email varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id)
) TYPE=MyISAM;
CREATE TABLE postfix_transport (
id int(11) unsigned NOT NULL auto_increment,
domain varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY domain (domain)
) TYPE=MyISAM;
CREATE TABLE postfix_users (
id int(11) unsigned NOT NULL auto_increment,
email varchar(128) NOT NULL default '',
clear varchar(128) NOT NULL default '',
crypt varchar(128) NOT NULL default '',
name tinytext NOT NULL,
uid int(11) unsigned NOT NULL default '1001',
gid int(11) unsigned NOT NULL default '1001',
homedir tinytext NOT NULL,
maildir tinytext NOT NULL,
quota tinytext NOT NULL,
access enum('Y','N') NOT NULL default 'Y',
postfix enum('Y','N') NOT NULL default 'Y',
PRIMARY KEY (id),
UNIQUE KEY email (email)
) TYPE=MyISAM;
CREATE TABLE postfix_virtual (
id int(11) unsigned NOT NULL auto_increment,
email varchar(128) NOT NULL default '',
destination varchar(128) NOT NULL default '',
PRIMARY KEY (id)
) TYPE=MyISAM;
CREATE TABLE postfix_access (
id int(10) unsigned NOT NULL auto_increment,
source varchar(128) NOT NULL default '',
access varchar(128) NOT NULL default '',
type enum('recipient','sender','client') NOT NULL default 'recipient',
PRIMARY KEY (id)
) TYPE=MyISAM;
The purposes of the tables used here is explained in postfix SQL tables.
Postfix
/etc/postfix/main.cf:
mydestination = hostname.domain.tld, localhost.domain.tld, localhost, $transport_maps
local_recipient_maps = $virtual_alias_maps $virtual_mailbox_maps
transport_maps = mysql:/etc/postfix/mysql-transport.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-aliases.cf
virtual_mailbox_base = /var/vmail
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-maps.cf
virtual_transport = virtual
virtual_uid_maps = static:1001
virtual_gid_maps = static:1001
virtual_minimum_uid = 1001
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_hostname
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_security_options = noanonymous
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/postfix/smtpd.cert
smtpd_tls_key_file = /etc/postfix/smtpd.key
[http://www.postfix.org/postconf.5.html#virtual_maps virtual_maps] is deprecated in favour of separate virtual_alias_domains and virtual_alias_maps controls.
Mysql files
Create the following in /etc/postfix:
mysql-aliases.cf
# mysql-aliases.cf
user = postfix
password = password
dbname = postfix
table = postfix_alias
select_field = destination
where_field = alias
hosts = 127.0.0.1
mysql-relocated.cf
# mysql-relocated.cf
user = postfix
password = password
dbname = postfix
table = postfix_relocated
select_field = destination
where_field = email
hosts = 127.0.0.1
mysql-transport.cf
# mysql-transport.cf
user = postfix
password = password
dbname = postfix
table = postfix_transport
select_field = destination
where_field = domain
hosts = 127.0.0.1
mysql-virtual.cf
# mysql-virtual.cf
user = postfix
password = password
dbname = postfix
table = postfix_virtual
select_field = destination
where_field = email
hosts = 127.0.0.1
mysql-recipient.cf
# mysql-recipient.cf
user = postfix
password = password
dbname = postfix
table = postfix_access
select_field = access
where_field = source
additional_conditions = and type = 'recipient'
hosts = 127.0.0.1
mysql-sender.cf
# mysql-sender.cf
user = postfix
password = password
dbname = postfix
table = postfix_access
select_field = access
where_field = source
additional_conditions = and type = 'sender'
hosts = 127.0.0.1
mysql-client.cf
# mysql-client.cf
user = postfix
password = password
dbname = postfix
table = postfix_access
select_field = access
where_field = source
additional_conditions = and type = 'client'
hosts = 127.0.0.1
mysql-virtual-maps.cf
# mysql-virtual-maps.cf
user = postfix
password = password
dbname = postfix
table = postfix_users
select_field = maildir
where_field = email
additional_conditions = and postfix = 'y'
hosts = 127.0.0.1
mysql-virtual-uid.cf
# mysql-virtual-uid.cf
user = postfix
password = password
dbname = postfix
table = postfix_users
select_field = uid
where_field = email
additional_conditions = and postfix = 'y'
hosts = 127.0.0.1
mysql-virtual-gid.cf
# mysql-virtual-gid.cf
user = postfix
password = password
dbname = postfix
table = postfix_users
select_field = gid
where_field = email
additional_conditions = and postfix = 'y'
hosts = 127.0.0.1
Create a user
INSERT INTO postfix_transport (domain,destination) VALUES ("domain.tld", "virtual:");
INSERT INTO postfix_users (email, clear, homedir, maildir) VALUES ("user@domain.tld", "password", "/var/vmail", "domain.tld/user/Maildir/");
The maildir record in postfix_users must end with a forward slash to make Postfix work with a Maildir.
Testing
SMTP
Valid user:
telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 example.domain.tld ESMTP Postfix (Debian/GNU) EHLO localhost 250-example.domain.tld 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH PLAIN CRAM-MD5 LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN MAIL FROM: test@localhost 250 2.1.0 Ok rcpt to: user@domain.tld 250 2.1.5 Ok DATA 354 End data with <CR><LF>.<CR><LF> This is a test . 250 2.0.0 Ok: queued as 720554B082 quit 221 2.0.0 Bye
Invalid user:
telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 example.domain.tld ESMTP Postfix (Debian/GNU) EHLO localhost 250-example.domain.tld 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH PLAIN CRAM-MD5 LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN MAIL FROM: root@localhost 250 2.1.0 Ok RCPT TO: nonexistanttestuser@domain.tld 550 5.1.1 <nonexistanttestuser@domain.tld>: Recipient address rejected: User unknown in local recipient table quit 221 2.0.0 Bye
IMAP
telnet localhost 143 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. * OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION STARTTLS] Courier-IMAP ready. Copyright 1998-2005 Double Precision, Inc. See COPYING for distribution information. a login user@domain.tld password a OK LOGIN Ok. a examine inbox * FLAGS (\Draft \Answered \Flagged \Deleted \Seen \Recent) * OK [PERMANENTFLAGS ()] No permanent flags permitted * 1 EXISTS * 1 RECENT * OK [UIDVALIDITY 1200873832] Ok * OK [MYRIGHTS "acdilrsw"] ACL a OK [READ-ONLY] Ok a logout * BYE Courier-IMAP server shutting down a OK LOGOUT completed
Troubleshooting
The Courier-MTA site has commands required to manually perform a login with IMAP/POP3, with and without SSL.