Postfix + Courier IMAP + MySQL + SASL + TLS on Debian

Setting up Postfix on Debian Wheezy.

Credits

This article is heavily based on Ivar Abrahamsen’s tutorial http://flurdy.com/docs/postfix/.

Software

Software used in this article:

  1. Debian Wheezy
  2. Postfix 2.9.6-2
  3. Courier IMAP 4.10.0
  4. MySQL server 5.5.40
  5. MySQL client 5.5.40
  6. Cyrus SASL 2.1.25

Before We Begin

As mentioned in the credits section, this article is heavily based on Ivar Abrahamsen’s tutorial for Ubuntu. Not all configuration steps are explained in details on this page, it is supposed to serve more like a quick how-to rather than a proper step-by-step guide (assuming you know what you are doing here).

These are the details that will be used for configuration:

Domain: solutin.net (mail.solutin.net) – I owned this domain for a period of time
MX: mx1.solutin.net
Email account: [email protected]
MySQL database: postfix
MySQL user: mail
MySQL password: passwd

Replace solutin.net with example.com if it makes you feel better.

You may want this:

# apt-get install vim

MySQL

Install MySQL. You will be asked for MySQL root password. Make sure you remember it.

# apt-get install mysql-client mysql-server

Create mysql database and user for Postfix. Feel free to change the “passwd” password field:

# cat > ./create.sql << EOF
CREATE DATABASE postfix;
GRANT ALL PRIVILEGES ON postfix.* TO "mail"@"localhost" IDENTIFIED BY "passwd";
FLUSH PRIVILEGES;
EOF

Import:

# mysql -u root -p < ./create.sql

Create database tables for Postfix:

# cat > postfix-mysql.sql << EOL
# Based on http://flurdy.com/docs/postfix/#config-simple-database

USE postfix;

CREATE TABLE aliases (
 pkid smallint(3) NOT NULL auto_increment,
 mail varchar(120) NOT NULL default '',
 destination varchar(120) NOT NULL default '',
 enabled tinyint(1) NOT NULL default '1',
 PRIMARY KEY  (pkid),
 UNIQUE KEY mail (mail)
);

CREATE TABLE domains (
 pkid smallint(6) NOT NULL auto_increment,
 domain varchar(120) NOT NULL default '',
 transport varchar(120) NOT NULL default 'virtual:',
 enabled tinyint(1) NOT NULL default '1',
 PRIMARY KEY  (pkid)
);

CREATE TABLE users (
 id varchar(128) NOT NULL default '',
 name varchar(128) NOT NULL default '',
 uid smallint(5) unsigned NOT NULL default '5000',
 gid smallint(5) unsigned NOT NULL default '5000',
 home varchar(255) NOT NULL default '/var/spool/mail/virtual',
 maildir varchar(255) NOT NULL default 'blah/',
 enabled tinyint(1) NOT NULL default '1',
 change_password tinyint(1) NOT NULL default '1',
 clear varchar(128) NOT NULL default 'changemepls',
 crypt varchar(128) NOT NULL default 'V2VkIE9jdCAyOSAxMzo1MD',
 quota varchar(255) NOT NULL default '',
 PRIMARY KEY  (id),
 UNIQUE KEY id (id)
);
EOL
# mysql -u mail -p < ./postfix-mysql.sql

Enable MySQL logging for troubleshooting Postfix setup. Open /etc/mysql/my.cnf and uncomment the lines:

general_log_file = /var/log/mysql/mysql.log
general_log = 1

Restart MySQL:

# /etc/init.d/mysql restart

Postfix

Install Postfix. Select internet site when asked.

# apt-get install postfix postfix-mysql

Set up the folder for the virtual mail to store etc.

# cp /etc/aliases /etc/postfix/aliases
# postalias /etc/postfix/aliases
# mkdir /var/spool/mail/virtual
# groupadd --system virtual -g 5000
# useradd --system virtual -u 5000 -g 5000
# chown -R virtual:virtual /var/spool/mail/virtual

Here’s how our Postfix configuration looks like at the moment:

# cat /etc/postfix/main.cf
myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name
biff = no

relayhost = 

inet_interfaces = all
mynetworks_style = host
inet_protocols = ipv4

append_dot_mydomain = no

delay_warning_time = 4h

readme_directory = no

smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination

alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases
# this specifies where the virtual mailbox folders will be located
virtual_mailbox_base = /var/spool/mail/virtual
# this is for the mailbox location for each user
virtual_mailbox_maps = mysql:/etc/postfix/mysql_mailbox.cf
# and this is for aliases
virtual_alias_maps = mysql:/etc/postfix/mysql_alias.cf
# and this is for domain lookups
virtual_mailbox_domains = mysql:/etc/postfix/mysql_domains.cf

virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

# Will be using virtual domains
local_recipient_maps =
mydestination =

mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +

# will it be a permanent error or temporary
unknown_local_recipient_reject_code = 450
# how long to keep message on queue before return as failed.
# some have 3 days, I have 16 days as I am backup server for some people
# whom go on holiday with their server switched off.
maximal_queue_lifetime = 7d
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
# how long to wait when servers connect before receiving rest of data
smtp_helo_timeout = 60s
# how many address can be used in one message.
# effective stopper to mass spammers, accidental copy in whole address list
# but may restrict intentional mail shots.
smtpd_recipient_limit = 10
# how many error before back off.
smtpd_soft_error_limit = 3
# how many max errors before blocking it.
smtpd_hard_error_limit = 12

# Requirements for the HELO statement
smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit
# Requirements for the sender details
smtpd_sender_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit
# Requirements for the connecting server 
smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl
# Requirement for the recipient address
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, permit
smtpd_data_restrictions = reject_unauth_pipelining

# require proper helo at connections 
smtpd_helo_required = yes
# waste spammers time before rejecting them
smtpd_delay_reject = yes
disable_vrfy_command = yes

Postfix’s MySQL Configuration

Set up files to access the lookups via the database.

# cat > /etc/postfix/mysql_mailbox.cf << EOL
user=mail
password=passwd
dbname=postfix
table=users
select_field=maildir
where_field=id
hosts=127.0.0.1
additional_conditions = and enabled = 1
EOL

How to find the email alias.

# cat > /etc/postfix/mysql_alias.cf << EOL
user=mail
password=passwd
dbname=postfix
table=aliases
select_field=destination
where_field=mail
hosts=127.0.0.1
additional_conditions = and enabled = 1
EOL

How to find the domains.

# cat > /etc/postfix/mysql_domains.cf << EOL
user=mail
password=passwd
dbname=postfix
table=domains
select_field=domain
where_field=domain
hosts=127.0.0.1
additional_conditions = and enabled = 1
EOL

The below prevents the world from reading Postfix files which contain MySQL credentials.

# chown root:postfix /etc/postfix/mysql_*
# chmod 0640 /etc/postfix/mysql_*

Add Users to MySQL

Important domains and users.

# cat > ./required.sql << EOL
USE postfix;

INSERT INTO domains (domain) VALUES ('localhost'), ('localhost.localdomain');

INSERT INTO aliases (mail,destination) VALUES
 ('postmaster@localhost','root@localhost'),
 ('sysadmin@localhost','root@localhost'),
 ('webmaster@localhost','root@localhost'),
 ('abuse@localhost','root@localhost'),
 ('root@localhost','root@localhost'),
 ('@localhost','root@localhost'),
 ('@localhost.localdomain','@localhost');

INSERT INTO users (id,name,maildir,crypt) VALUES
 ('root@localhost','root','root/',encrypt('rootpasswd', CONCAT('$5$', MD5(RAND()))) );
EOL

Import:

$ mysql -u mail -p < ./required.sql

We need to add our domain:

mysql> INSERT INTO domains (domain) VALUES ('solutin.net');

And an email user (one long line):

mysql> INSERT INTO users (id,name,maildir,crypt) VALUES ('[email protected]','Tomas','tomas/',encrypt('passwd', CONCAT('$5$', MD5(RAND()))) );

To remove a record:

mysql> DELETE FROM users WHERE name="Tomas";

Restart Postfix.

# service postfix restart

Courier IMAP

Install:

# apt-get install courier-base courier-authdaemon courier-authlib-mysql \
courier-imap courier-imap-ssl courier-ssl

Open /etc/courier/imapd and change the following:

ADDRESS=0

to

ADDRESS=0.0.0.0

This will make Courier IMAP to listen on IPv4 only.

How /etc/courier/authdaemonrc file looks like:

# grep -ve "^#" -ve "^$" /etc/courier/authdaemonrc
authmodulelist="authmysql"
authmodulelistorig="authuserdb authpam authpgsql authldap authmysql authcustom authpipe"
daemons=5
authdaemonvar=/var/run/courier/authdaemon
DEBUG_LOGIN=2
DEFAULTOPTIONS=""
LOGGEROPTS=""

How /etc/courier/authmysqlrc file looks like:

# grep -ve "^#" -ve "^$" /etc/courier/authmysqlrc
MYSQL_SERVER		localhost
MYSQL_USERNAME		mail
MYSQL_PASSWORD		passwd
MYSQL_PORT		0
MYSQL_OPT		0
MYSQL_DATABASE		postfix
MYSQL_USER_TABLE	users
MYSQL_CRYPT_PWFIELD	crypt
MYSQL_UID_FIELD		uid
MYSQL_GID_FIELD		gid
MYSQL_LOGIN_FIELD	id
MYSQL_HOME_FIELD	home
MYSQL_NAME_FIELD	name
MYSQL_MAILDIR_FIELD	concat(home,'/',maildir)
MYSQL_WHERE_CLAUSE enabled=1

Iptables

Configure local firewall:

# iptables -A INPUT -p tcp -m multiport --dport 25,143 -j ACCEPT

Testing: Part 1

Ensure all services are restarted, just in case.

# /etc/init.d/mysql restart
# /etc/init.d/postfix restart
# /etc/init.d/courier-authdaemon restart
# /etc/init.d/courier-imap restart
# /etc/init.d/courier-imap-ssl restart

Make sure Postfix, CourierIMAP and MySQL Services are Running

# netstat -nltp | egrep '25|143|3306'
tcp   0   0 127.0.0.1:3306    0.0.0.0:*    LISTEN      10970/mysqld    
tcp   0   0 0.0.0.0:143       0.0.0.0:*    LISTEN      13872/couriertcpd
tcp   0   0 0.0.0.0:25        0.0.0.0:*    LISTEN      13116/master

Make Sure MX Records are Set

$ dig MX +short solutin.net
10 mx1.solutin.net.
$ dig A +short mx1.solutin.net
54.X.Y.Z

Make Sure Firewall Allows Access

$ nmap -Pn -p T:25,143 mx1.solutin.net | grep open
25/tcp  open  smtp
143/tcp open  imap

Check with Telnet if Postfix Can Receive Emails

$ telnet solutin.net 25
Trying 54.X.Y.Z..
Connected to solutin.net.
220 *************************
EHLO solutin.net
250-solutin.net
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-XXXXXXXA
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
MAIL FROM: [email protected]
250 2.1.0 Ok
RCPT TO: [email protected]
250 2.1.5 Ok
data
354 End data with .
this is a tets email
to check postfix installation from telnet
.
250 2.0.0 Ok: queued as 85E663061
quit
221 2.0.0 Bye
Connection closed by foreign host.

Check on the server for the newly received email:

# ls -l /var/spool/mail/virtual/tomas/new/
total 4
-rw------- 1 virtual virtual 338 Dec  1 15:39 1417448343.Vca01I310fM579863.solutin.net

Check logs if the above fails:

# tail /var/log/mail.log 
# tail /var/log/mysql/mysql.log

Retrieve Emails via IMAP

We use Icedove (aka Thunderbird on Debian) here. Below is a short excerpt from mail.log showing what happens when we connect with Icedove:

imapd: Connection, ip=[::ffff:1.2.3.X]
authdaemond: received auth request, service=imap, authtype=login
authdaemond: authmysql: trying this module
authdaemond: authmysqllib: connected. Versions: header 50524, client 50540, server 50540
authdaemond: SQL query: SELECT id, crypt, "", uid, gid, home, concat(home,'/',maildir), "", name, "" FROM users WHERE id = '[email protected]'  AND (enabled=1)
authdaemond: password matches successfully
authdaemond: authmysql: sysusername=, sysuserid=5000, sysgroupid=5000, homedir=/var/spool/mail/virtual, [email protected], fullname=Tomas, maildir=/var/spool/mail/virtual/tomas/, quota=, options=
authdaemond: authmysql: clearpasswd=, passwd=$5$2b10ed288afd8f90$9LLQe7/TKgrDbLcQlb8V11NTs28bDGPCU.KoVOWYuz7
authdaemond: Authenticated: sysusername=, sysuserid=5000, sysgroupid=5000, homedir=/var/spool/mail/virtual, [email protected], fullname=Tomas, maildir=/var/spool/mail/virtual/tomas/, quota=, options=
authdaemond: Authenticated: clearpasswd=passwd, passwd=$5$2b10ed288afd8f90$9LLQe7/TKgrDbLcQlb8V11NTs28bDGPCU.KoVOWYuz7
imapd: LOGIN, [email protected], ip=[::ffff:1.2.3.X], port=[17181], protocol=IMAP

Send a Test Email from localhost

$ echo "Test" | mail -v -s "Test from Postfix " [email protected]

Secure SMTP

SASL

Install SASL:

# apt-get install libsasl2-modules libsasl2-modules-sql libgsasl7 \
libauthen-sasl-cyrus-perl sasl2-bin libpam-mysql

Enable Postfix to access SASL files:

# adduser postfix sasl
# mkdir -p /var/spool/postfix/var/run/saslauthd

Add the following to /etc/postfix/main.cf:

smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = no
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
# Add permit_sasl_authenticated to you existing  smtpd_sender_restrictions
# Add permit_sasl_authenticated to you existing  smtpd_recipient_restrictions

Here is how /etc/default/saslauthd file looks like:

# grep -ve "^#" -ve "^$" /etc/default/saslauthd
START=yes
DESC="SASL Authentication Daemon"
NAME="saslauthd"
MECHANISMS="pam"
MECH_OPTIONS=""
THREADS=5
OPTIONS="-r -c -m /var/spool/postfix/var/run/saslauthd"

Tell Postfix how to interact with SASL:

# cat > /etc/postfix/sasl/smtpd.conf << EOL
pwcheck_method: saslauthd
mech_list: plain login cram-md5 digest-md5
log_level: 7
allow_plaintext: true
auxprop_plugin: sql
sql_engine: mysql
sql_hostnames: 127.0.0.1
sql_user: mail
sql_passwd: passwd
sql_database: postfix
sql_select: select crypt from users where id='%u@%r' and enabled = 1
EOL

Tell PAM how to to authenticate SMTP via MySQL:

# cat > /etc/pam.d/smtp << EOL
auth required pam_mysql.so user=mail passwd=passwd host=127.0.0.1 db=postfix table=users usercolumn=id passwdcolumn=crypt crypt=1
account sufficient pam_mysql.so user=mail passwd=passwd host=127.0.0.1 db=postfix table=users usercolumn=id passwdcolumn=crypt crypt=1
EOL

Restart services:

# /etc/init.d/saslauthd restart
# /etc/init.d/postfix restart

TLS: Postfix

Create an SSL certificate:

$ cd /etc/postfix
$ openssl req -new -outform PEM -out postfix.cert -newkey rsa:2048 -nodes \
-keyout postfix.key -keyform PEM -days 1825 -x509

Add the lines below to /etc/postfix/main.cf.

smtp_tls_security_level = may
smtpd_tls_security_level = may
smtp_tls_note_starttls_offer = yes
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
smtpd_tls_cert_file=/etc/postfix/postfix.cert
smtpd_tls_key_file=/etc/postfix/postfix.key
# smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
# smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

Here is how /etc/postfix/main.cf file looks like:

# grep -ve "^#" -ve "^$" /etc/postfix/main.cf
myorigin = /etc/mailname
smtpd_banner = $myorigin ESMTP $mail_name
biff = no
relayhost = 
inet_interfaces = all
mynetworks_style = host
inet_protocols = ipv4
append_dot_mydomain = no
delay_warning_time = 4h
readme_directory = no
smtp_tls_security_level = may
smtpd_tls_security_level = may
smtp_tls_note_starttls_offer = yes
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
smtpd_tls_cert_file=/etc/postfix/postfix.cert
smtpd_tls_key_file=/etc/postfix/postfix.key
alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases
virtual_mailbox_base = /var/spool/mail/virtual
virtual_mailbox_maps = mysql:/etc/postfix/mysql_mailbox.cf
virtual_alias_maps = mysql:/etc/postfix/mysql_alias.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql_domains.cf
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
local_recipient_maps =
mydestination =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
message_size_limit = 2097152
mailbox_size_limit = 1073741824
recipient_delimiter = +
unknown_local_recipient_reject_code = 450
maximal_queue_lifetime = 7d
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
smtp_helo_timeout = 60s
smtpd_recipient_limit = 10
smtpd_soft_error_limit = 3
smtpd_hard_error_limit = 12
smtpd_helo_restrictions = permit_mynetworks, 
 warn_if_reject,
 reject_non_fqdn_hostname,
 reject_invalid_hostname,
 permit
smtpd_sender_restrictions = permit_mynetworks,
 permit_sasl_authenticated,
 warn_if_reject,
 reject_non_fqdn_sender,
 reject_unknown_sender_domain,
 reject_unauth_pipelining,
 permit
smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, 
 reject_rbl_client blackholes.easynet.nl
smtpd_recipient_restrictions = reject_unauth_pipelining,
 permit_mynetworks,
 permit_sasl_authenticated,
 reject_non_fqdn_recipient,
 reject_unknown_recipient_domain,
 reject_unauth_destination,
 reject_rbl_client sbl.spamhaus.org,
 permit
smtpd_data_restrictions = reject_unauth_pipelining
smtpd_helo_required = yes
smtpd_delay_reject = yes
disable_vrfy_command = yes
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = no
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =

Here is how /etc/postfix/master.cf file looks like:

# grep -ve "^#" -ve "^$"  /etc/postfix/master.cf
smtp      inet  n       -       -       -       -       smtpd
submission inet n       -       n       -       -       smtpd 
 -o smtpd_sasl_auth_enable=yes 
 -o smtpd_tls_auth_only=yes
 -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
 -o smtpd_sasl_security_options=noanonymous,noplaintext
 -o smtpd_sasl_tls_security_options=noanonymous
smtps     inet  n       -       n       -       -       smtpd 
 -o smtpd_tls_wrappermode=yes 
 -o smtpd_sasl_auth_enable=yes
 -o smtpd_tls_auth_only=yes
 -o smtpd_client_restrictions=permit_sasl_authenticated,reject
 -o smtpd_sasl_security_options=noanonymous,noplaintext
 -o smtpd_sasl_tls_security_options=noanonymous
pickup    unix  n       -       -       60      1       pickup
cleanup   unix  n       -       -       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       -       1000?   1       tlsmgr
rewrite   unix  -       -       -       -       -       trivial-rewrite
bounce    unix  -       -       -       -       0       bounce
defer     unix  -       -       -       -       0       bounce
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
flush     unix  n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       -       -       -       smtp
relay     unix  -       -       -       -       -       smtp
showq     unix  n       -       -       -       -       showq
error     unix  -       -       -       -       -       error
retry     unix  -       -       -       -       -       error
discard   unix  -       -       -       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       -       -       -       lmtp
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix	-	n	n	-	2	pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}

Restart Postfix:

# service postfix restart

TLS: Courier IMAP

Create an SSL certificate:

# cd /etc/courier
$ openssl req -x509 -newkey rsa:2048 -keyout imapd.pem \
-out imapd.pem -nodes -days 1825

Here is how /etc/courier/imapd-ssl looks like:

# grep -ve "^#" -ve "^$" /etc/courier/imapd-ssl
SSLPORT=993
SSLADDRESS=0.0.0.0
SSLPIDFILE=/var/run/courier/imapd-ssl.pid
SSLLOGGEROPTS="-name=imapd-ssl"
IMAPDSSLSTART=YES
IMAPDSTARTTLS=YES
IMAP_TLS_REQUIRED=1
COURIERTLS=/usr/bin/couriertls
TLS_KX_LIST=ALL
TLS_COMPRESSION=ALL
TLS_CERTS=X509
TLS_CERTFILE=/etc/courier/imapd.pem
TLS_TRUSTCERTS=/etc/ssl/certs
TLS_VERIFYPEER=NONE
TLS_CACHEFILE=/var/lib/courier/couriersslcache
TLS_CACHESIZE=524288
MAILDIRPATH=Maildir

Restart service:

# service courier-imap-ssl restart

Iptables

Configure local firewall to allow via encrypted channels:

# iptables -A INPUT -p tcp -m multiport --dport 587,465,993 -j ACCEPT

Testing: Part 2

# /etc/init.d/mysql restart
# /etc/init.d/postfix restart
# /etc/init.d/courier-authdaemon restart
# /etc/init.d/courier-imap restart
# /etc/init.d/courier-imap-ssl restart
# /etc/init.d/saslauthd restart
# netstat -nltp | egrep '25|587|465|143|993|3306'
tcp   0   0 127.0.0.1:3306  0.0.0.0:*     LISTEN    18177/mysqld    
tcp   0   0 0.0.0.0:587     0.0.0.0:*     LISTEN    20534/master    
tcp   0   0 0.0.0.0:143     0.0.0.0:*     LISTEN    17434/couriertcpd
tcp   0   0 0.0.0.0:465     0.0.0.0:*     LISTEN    20534/master    
tcp   0   0 0.0.0.0:25      0.0.0.0:*     LISTEN    20534/master    
tcp   0   0 0.0.0.0:993     0.0.0.0:*     LISTEN    20710/couriertcpd
# nmap -Pn -p T:25,143,587,465,993 mx1.solutin.net | grep open
25/tcp  open  smtp
143/tcp open  imap
465/tcp open  smtps
587/tcp open  submission
993/tcp open  imaps

External tools that may become handy:

  1. http://mxtoolbox.com/SuperTool.aspx
  2. http://www.checktls.com/perl/TestReceiver.pl

When Everything is (Finally) Working

Disable logging in /etc/mysql/my.cnf and restart MySQL service:

# service mysql restart

Disable logging in /etc/courier/authdaemonrc and restart service:

# service courier-authdaemon restart

Troubleshooting

If you see this in /var/log/mail.log:

postfix/smtpd[10104]: warning: SASL authentication failure: cannot connect to saslauthd server: No such file or directory

You may need to do the following:

# rm /var/run/saslauthd/ -rf
# ln -sf /var/spool/postfix/var/run/saslauthd /var/run
# /etc/init.d/saslauthd restart

ThunderBird Email Client Setting

IMAPS:

  1. Server name: mail.solutin.net
  2. Port: 993
  3. Connection security: SSL/TLS
  4. Auth method: Normal password

Outgoing Server (SMTPS):

  1. Server name: mail.solutin.net
  2. Port: 465
  3. Connection security: SSL/TLS
  4. Auth method: Normal passwd

9 thoughts on “Postfix + Courier IMAP + MySQL + SASL + TLS on Debian

  1. Great tutorial thanks!
    The setup fails on Jessie (Debian 8). Biggest problems are the way sql statements are passed while initiating connection. However I am not sure if it is a version wheezy or jessie problem..

    This example is shown in my /var/log/mail.log:
    authdaemond: SQL query: SELECT id, crypt, “”, uid, gid, home, concat(home,’/’,maildir), “”, name, “” FROM users WHERE id = ‘[email protected]’ AND (enabled=1)

    I think the empty “” fields are causing trouble.

    Kind regards,
    Kees

  2. when i tried connecting to imap i got this error in mail.log:

    Oct 4 23:06:13 localhost authdaemond: Authenticated: sysusername=, sysuserid=1, sysgroupid=1, homedir=/var/spool/mail/virtual, [email protected], fullname=i, maildir=/var/spool/mail/virtual/i/, quota=, options=
    Oct 4 23:06:13 localhost authdaemond: Authenticated: clearpasswd=, passwd=
    Oct 4 23:06:13 localhost imapd: chdir /var/spool/mail/virtual/i/: Permission denied
    Oct 4 23:06:13 localhost imapd: [email protected]: Permission denied

    it seems that courier-imap have no permission to access the maildir. but when i check with “ps -aux | grep imapd” i found imapd is runnins as root.

    the owner and group of maildir is virtual (with which postfix run), and mode is -rw——-(600)

    how should I solve this problem?

  3. i check it again just now and find that the postfix doesn’t run as the user virtual:x:5000:5000.
    but, followed your guidelines, the main.cf has this two lines:
    virtual_uid_maps = static:5000
    virtual_gid_maps = static:5000
    i’ve tried change the ownership of /var/spool/mail/virtual to postfix:postfix or root:root but it doesn’t take effect .

  4. sorry, it’s my oversight. solved.
    the virtual mail user/group ‘s id is 5000, and courier-imap get the id via authdaemond from mysql database.
    and it’s defined in the column uid/gid in table ‘user’ . i change it by mistake.
    however it’s better to making it be static instead of read it from mysql:
    /etc/courier/authmysqlrc
    MYSQL_UID_FIELD 5000
    MYSQL_GID_FIELD 5000

    finally, quite thanks for your great tutorial !
    (and sorry for my terrible chinglish

Leave a Reply

Your email address will not be published. Required fields are marked *