Mail Server Setup

This is how I set up my mail server on

  • Ubuntu 12.04 Precise Pangolin
  • Dovecot 2.0.19
  • Postfix 2.9.6
  • Postfix Admin 2.3.6
  • Squirrel Mail 1.4.22
  • MySQL 5.5.34
  • PHP 5.3.10

Supporting Packages to Install

  • postfix-mysql
  • dovecot-core
  • dovecot-postfix
  • dovecot-mysql
  • dovecot-imapd
  • php5-mysql

Server configuration

vmail user configuration

uid=5000(vmail) gid=5000(vmail) groups=5000(vmail)

Postfix configuration

/etc/postfix/main.cf

main.cf
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
 
 
# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
myorigin = /etc/mailname
 
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
 
# appending .domain is the MUA's job.
append_dot_mydomain = no
 
# Uncomment the next line to generate "delayed mail" warnings
delay_warning_time = 4h
 
readme_directory = no
 
# TLS parameters
smtpd_tls_cert_file = /etc/ssl/certs/ssl-mail.pem
smtpd_tls_key_file = /etc/ssl/private/ssl-mail.key
smtpd_tls_loglevel = 1
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
tls_random_source = dev:/dev/urandom
tls_random_bytes = 32
tls_random_reseed_period = 3600s
#
home_mailbox = Maildir/
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/dovecot-auth
smtpd_sasl_authenticated_header = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
broken_sasl_auth_clients = yes
smtpd_use_tls = yes
smtpd_tls_received_header = yes
smtpd_tls_mandatory_protocols = SSLv3, TLSv1
smtpd_tls_mandatory_ciphers = medium
#smtpd_tls_auth_only = yes
#
smtp_tls_cert_file=/etc/postfix/ssl/smtpd.pem
smtp_tls_key_file=$smtp_tls_cert_file
smtp_tls_loglevel = 1
smtp_tls_security_level = may
smtp_tls_note_starttls_offer = yes
smtp_use_tls = yes
#
 
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
 
myhostname = example.org
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
#mydestination = example.org, www.example.org, example.cc, www.example.cc, myserverhostname, localhost.localdomain, localhost
mydestination =
relayhost = smtp-server.example.com
# This was commented out as it gives a "unused parameter" warning on Precise - works on Hardy
#relay_domain = $mydestination
mynetworks_style = subnet
#mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_command = /usr/lib/dovecot/deliver -c /etc/dovecot/conf.d/01-mail-stack-delivery.conf -m "${EXTENSION}"
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
owner_request_special = no
message_size_limit = 32768000
#
# Virtual Mailbox Domain Settings
virtual_alias_maps = mysql:/etc/postfix/mysql/alias_maps.cf, mysql:/etc/postfix/mysql/alias_alias_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql/domains_maps.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql/mailbox_maps.cf, mysql:/etc/postfix/mysql/mailbox_alias_maps.cf
virtual_mailbox_limit = 51200000
virtual_minimum_uid = 5000
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_mailbox_base = /home/vmail
virtual_transport = virtual
# Additional for quota support
# This was commented out as it gives a "unused parameter" warning on Precise - works on Hardy
#virtual_create_maildirsize = yes
#virtual_mailbox_extended = yes
#virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql/mailbox_limit_maps.cf
#virtual_mailbox_limit_override = yes
#virtual_maildir_limit_message = Sorry, the your maildir has overdrawn your diskspace quota, please free up some of spaces of your mailbox try again.
#virtual_overquota_bounce = yes
#
# Spam reduction parameters. May be aggresive for some, but seems to work well.
access_map_reject_code = 554
invalid_hostname_reject_code = 554
maps_rbl_reject_code = 554
multi_recipient_bounce_reject_code = 554
non_fqdn_reject_code = 554
plaintext_reject_code = 554
reject_code = 554
relay_domains_reject_code = 554
unknown_local_recipient_reject_code = 550
unknown_address_reject_code = 550
unknown_client_reject_code = 550
unknown_hostname_reject_code = 550
unknown_relay_recipient_reject_code = 550
unknown_virtual_alias_reject_code = 550
unknown_virtual_mailbox_reject_code = 550
unverified_recipient_reject_code = 550
unverified_sender_reject_code = 550
#
default_process_limit = 20
smtpd_client_connection_count_limit = 10
# Value of 60 should translate to 1 per second limit
smtpd_client_connection_rate_limit = 60
smtpd_client_message_rate_limit = 60
smtpd_client_new_tls_session_rate_limit = 60
#
smtpd_helo_required = yes
smtpd_delay_reject = yes
address_verify_map = btree:${data_directory}/verify_cache
smtpd_reject_unlisted_sender=yes
#
smtpd_recipient_restrictions =
    check_client_access hash:/etc/postfix/white_lists,
    permit_sasl_authenticated,
    permit_mynetworks,
#   permit_tls_clientcerts,
    reject_invalid_hostname,
    reject_non_fqdn_hostname,
    reject_non_fqdn_sender,
    reject_non_fqdn_recipient,
    reject_unknown_sender_domain,
    reject_unknown_recipient_domain,
    reject_unverified_sender,
    reject_unauth_destination,
    reject_rbl_client zen.spamhaus.org,
    reject_rbl_client cbl.abuseat.org,
    permit
smtpd_data_restrictions =
    permit_sasl_authenticated,
    permit_mynetworks,
    reject_unauth_pipelining,
    permit
# Added for trying to send email from PDA
smtpd_client_restrictions =
    permit_sasl_authenticated
smtpd_helo_restrictions = permit_mynetworks,
    permit_sasl_authenticated,
    reject_non_fqdn_hostname,
    reject_invalid_hostname,
    permit
#

/etc/postfix/mailname

mailname
example.org

Client TLS Support

Follow this for Postfix Client TLS Support setup

Postfix MySql (maps) configuration

  • Create directory /etc/postfix/mysql
  • Please the following files under /etc/postfix/mysql
mysql_uid.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=mailbox
select_field=username
where_field=username
hosts=127.0.0.1:<mysql_db_port>
mysql_gid.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=mailbox
select_field=username
where_field=username
hosts=127.0.0.1:<mysql_db_port>
mailbox_maps.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=mailbox
select_field=maildir
where_field=username
hosts=127.0.0.1:<mysql_db_port>
additional_conditions = and active = 1
mailbox_limit_maps.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=mailbox
select_field=quota
where_field=username
hosts=127.0.0.1:<mysql_db_port>
additional_conditions = and active = 1
alias_maps.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=alias
select_field=goto
where_field=address
hosts=127.0.0.1:<mysql_db_port>
additional_conditions = and active = 1
domains_maps.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=domain
select_field=domain
where_field=domain
hosts=127.0.0.1:<mysql_db_port>
additional_conditions = and backupmx = 0 and active = 1
relay_domains.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
table=domain
select_field=domain
where_field=domain
hosts=127.0.0.1:<mysql_db_port>
additional_conditions = and active = 1 and backupmx = 1

The below two settings (alias_alias_maps.cf & mailbox_alias_maps.cf) are for alias domains:

alias_alias_maps.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
hosts=127.0.0.1:<mysql_db_port>
query = SELECT goto FROM alias,alias_domain
  WHERE alias_domain.alias_domain = '%d'
  AND alias.address=concat('%u', '@', alias_domain.target_domain)
  AND alias.active = 1 AND alias_domain.active = 1
mailbox_alias_maps.cf
user=<mysql_db_user>
password=<mysql_db_password>
dbname=<mysql_db_name>
hosts=127.0.0.1:<mysql_db_port>
query = SELECT maildir FROM mailbox, alias_domain
  WHERE alias_domain.alias_domain = '%d'
  AND mailbox.username=concat('%u', '@', alias_domain.target_domain )
  AND mailbox.active = 1 AND alias_domain.active = 1

Dovecot Configuration

Change the following files at /etc/dovecot & /etc/dovecot/conf.d

The files in /etc/dovecot need NO changes from default

  • dovecot.conf
  • dovecot-db.conf.ext
  • dovecot-dict-sql.conf.ext
  • dovecot-sql.conf.ext

File(s) requiring change

dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 port=3306 user=root password=rootpassword dbname=postfixadmindbname
default_pass_scheme = CRAM-MD5
user_query = \
 SELECT \
        concat('/home/vmail/', maildir) as home, \
        5000 as uid, 5000 as gid \
        FROM mailbox \
        WHERE username = '%u' AND active = '1'
password_query = \
 SELECT username as user, password, \
        concat('/home/vmail/', maildir) as userdb_home, \
        concat('maildir:/home/vmail/', maildir) as userdb_mail, \
        5000 as userdb_uid, 5000 as userdb_gid \
        FROM mailbox \
        WHERE username = '%u' AND active = '1'

The following files in /etc/dovecot/conf.d do NOT require change as well

  • 01-mail-stack-delivery.conf
  • 10-director.conf
  • 10-master.conf
  • 10-ssl.conf
  • 15-lda.conf
  • 20-imap.conf
  • 20-managesieve.conf
  • 20-pop3.conf
  • 90-acl.conf
  • 90-plugin.conf
  • 90-quota.conf
  • 90-sieve.conf
  • auth-deny.conf.ext
  • auth-master.conf.ext
  • auth-passwdfile.conf.ext
  • auth-static.conf.ext
  • auth-vpopmail.conf.ext

File(s) requiring change

10-logging.conf
auth_verbose = yes
auth_debug = yes
plugin {
  # Events to log. Also available: flag_change append
  #mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename
  # Available fields: uid, box, msgid, from, subject, size, vsize, flags
  # size and vsize are available only for expunge and copy events.
  #mail_log_fields = uid box msgid size
}
10-auth.conf
auth_mechanisms = plain cram-md5
!include auth-system.conf.ext
auth-system.conf.ext
passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
  # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=<n>]
  # [cache_key=<key>] [<service name>]
  #args = dovecot
}
userdb {
  # <doc/wiki/AuthDatabase.Passwd.txt>
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
  # [blocking=no]
  #args =
}
10-mail.conf
mail_location = maildir:/home/vmail/%d/%u
mail_uid = vmail
mail_gid = vmail
maildir_copy_with_hardlinks = yes

Postfix Admin

All changes from the default go in config.local.php

config.local.php
$CONF['postfix_admin_url'] = 'http://pfa.example.org';
 
$CONF['domain_path'] = 'YES';
 
$CONF['database_type'] = 'mysql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'upostfixadmin';
$CONF['database_password'] = 'somepassword';
$CONF['database_name'] = 'postfixadmin';
 
$CONF['admin_email'] = 'postmaster@example.com';
 
$CONF['smtp_server'] = 'smtp-server.example.com';
 
$CONF['encrypt'] = 'dovecot:CRAM-MD5';
 
$CONF['dovecotpw'] = "/usr/bin/doveadm pw";
 
$CONF['page_size'] = '100';
 
$CONF['default_aliases'] = array (
    'abuse' => 'abuse@example.com',
    'hostmaster' => 'hostmaster@example.com',
    'postmaster' => 'postmaster@example.com',
    'webmaster' => 'webmaster@example.com'
);
 
$CONF['aliases'] = '10000';
$CONF['mailboxes'] = '10000';
$CONF['maxquota'] = '10000';
 
$CONF['transport'] = 'YES';
 
$CONF['vacation_domain'] = 'autoreply.example.com';
 
$CONF['user_footer_link'] = "http://example.com/";
$CONF['footer_text'] = 'Return to example.com'; 
$CONF['footer_link'] = 'http://example.com';
 
$CONF['create_mailbox_subdirs_prefix']='';
$CONF['new_quota_table'] = 'YES';

Migration from Courier to Postfix

If you are moving to a new machine make sure that you tar and untar files to preserver permissions and most importantly timestamps. Or all your old mail will have the same date/time!

Resource

Command

/home/vmail/courier-dovecot-migrate.pl --to-dovecot --recursive --convert --overwrite /home/vmail/example.org/

Sample output:

Converting to Dovecot format
Finding maildirs under /home/vmail/example.org/

Total: 70 mailboxes / 38 users
       0 errors
46 dovecot-uidlist files written

WARNING: Badly done migration will cause your IMAP and/or POP3 clients to re-download all mails. Read http://wiki.dovecot.org/Migration carefully.

Folder between courier and dovecot

One way to get the courier subfolders to show up in dovecot is to add this to the configuration:

10-mail.conf
namespace private {
  prefix = INBOX.
  separator = .
  inbox = yes
}

Alternatively, I created the subfolders (from squirrel mail) and then delete the newly created folders from the Linux file folders and renamed the existing file folders to the name I just deleted. So here goes for example:

mv .INBOX.SomeSubFolder/ junk
mv .SomeSubFolder .INBOX.SomeSubFolder

Here I moved the newly created folder to a “junk” location (an alternative to just deleting it). Then renamed the original folder to the new folder name.

Squirrel Mail configuration

Follow this link.

Some dovecot commands

dovecot --build-options
find /usr/lib/dovecot/modules/
doveconf -a

Post Configuration Steps

white_lists file

To avoid error that there is no white list file

cd /etc/postfix
touch white_lists
postmap white_lists

Restart

service postfix restart
service dovecot restart

Related

Discussion

Alex, 2012/11/27 11:21

Hi ;-)

Now I have a problem:

When running a mail server using MySql in Ubuntu 12.04 LTS, this interfers with other installation that also uses MySql, namely GlobalSight.

How can I resolve this problem?

They use following syntax:

” Installing the MySQL Database Server

If you want to install the MySQL Database Server and GlobalSight application on separate servers, you need to install either the MySQL server or MySQL client on same server as the GlobalSight application.

The instructions below apply to MySQL Database Server version 5.1.25. Instructions for other versions may vary. Installing MySQL from tar.gz Packages

Pre-requisites:

  The current user needs read/write privileges to the /usr/local directory
  The current user needs the sudo privilege
  Uninstall any versions of MySQL previously installed
  Type: sudo /etc/init.d/mysql stop
  Type: sudo apt-get remove mysql-server
  Type: sudo apt-get purge mysql-server
  Type: sudo apt-get remove mysql-client
  Type: sudo rm -f /etc/mysql/my.cnf 

To install MySQL:

  Go to the 3rd_party_software directory and find the mysql-5.1.25-rc-linux-i686-icc-glibc23.tar.gz file
  Unpack the tar.gz file
  Type: tar zxvf mysql-5.1.25-rc-linux-i686-icc-glibc23.tar.gz
  Copy the directory extracted to /usr/local and create a symbolic link for the MySQL directory
  Type: sudo cp -R mysql-5.1.25-rc-linux-i686-icc-glibc23 /usr/local
  Type: cd /usr/local
  Type: sudo ln -s mysql-5.1.25-rc-linux-i686-icc-glibc23 mysql
  Create a user and a group for MySQL
  Type: sudo useradd mysql
  Type: sudo usermod -a -G mysql mysql
  Change the owner and group attributes of the files to the MySQL user
  Type: sudo chown -R mysql:mysql /usr/local/mysql-5.1.25-rc-linux-i686-icc-glibc23
  Go to the MySQL directory
  Type: cd mysql
  Set up the MySQL internal database by running the script
  Type: sudo ./scripts/mysql_install_db --user=mysql
  The information below pops up when the script is imported successfully
  3rdubuntu1.jpg
  Change the ownership of the MySQL directories and data files
  Type: sudo chown -R root .
  Type: sudo chown -R mysql data
  Create a new start script for MySQL
  Type: sudo cp ./support-files/mysql.server /etc/init.d/
  Type: sudo update-rc.d -f mysql remove
  Type: sudo update-rc.d -f mysql.server remove
  Type: sudo update-rc.d mysql.server defaults 98
  Set the path by adding the following to /etc/profile file
  PATH=$PATH:/usr/local/mysql/bin
  export PATH
  Note: you need to log in again for the PATH to take effect 

Configuring the database

  Create the /etc/mysql directory, if it does not already exist
  Type: sudo mkdir /etc/mysql
  Copy the default configuration file for the expected size of the database
  Type: sudo cp /usr/local/mysql/support-files/my-medium.cnf /etc/mysql/my.cnf
  Type: sudo chown mysql:mysql /etc/mysql/my.cnf
  Add or update the following under the [mysqld] section in /etc/mysql/my.cnf
  Update:
  max_allowed_packet = 16M
  Add:
  default-storage-engine=INNODB
  lower_case_table_names=1
  log-bin-trust-function-creators=1
  default-character-set=utf8
  default-collation=utf8_general_ci
  character-set-server=utf8
  collation-server=utf8_general_ci
  init-connect='SET NAMES utf8'
  innodb_data_home_dir = /usr/local/mysql/data/
  innodb_data_file_path = ibdata1:10M:autoextend
  innodb_log_group_home_dir = /usr/local/mysql/data/
  innodb_buffer_pool_size = 50M
  innodb_additional_mem_pool_size = 2M
  innodb_log_file_size = 5M
  innodb_log_buffer_size = 8M
  innodb_flush_log_at_trx_commit = 1
  innodb_lock_wait_timeout = 500
  max_connections = 500
  Add the following under the [client] section in /etc/mysql/my.cnf
  default-character-set=utf8
  You can now start the MySQL server
  Type: sudo /etc/init.d/mysql.server start 

Creating the GlobalSight database and user using the MySQL command line

  Login to MySQL as root
  Type: mysql -uroot -p<mysql_root_password> -h<mysql_hostname_or_ip_ address>
  If the MySQL root user password is not set, you can login to MySQL by
  Type: mysql -uroot -h<mysql_hostname_or_ip_ address>
  Grant the privileges and change the password for the root user
  Type: grant all privileges on *.* to 'root'@'localhost' identified by '<mysql_root_password>';
  Create the GlobalSight database
  Type: create database <GlobalSight Database Name>;
  Example: create database globalsight;
  Create a database user for GlobalSight
  Type: create user '<User Name>'’@'%' identified by ‘<Password>’;
  Example: create user 'globalsight'@'%' identified by 'password';
  Grant all privileges of the GlobalSight database created above) to the database user created above
  Type: grant all privileges on <GlobalSight Database Name>.* to '<User Name>'@'%' identified by '<password>';
  Type: flush privileges;
  Assume that your have created a database named “globalsight”, the user name is “globalsight”, and the password is “password”. Then, the command should be:
  Example: grant all privileges on globalsight.* to 'globalsight'@'%' identified by 'password';
  Example: flush privileges;
  Note:If you want to connect to the MySQL server from other network ip, you need to grant privileges to the network ip address.
  Type: grant all privileges on globalsight.* to 'globalsight'@’192.168.29.29’ identified by ‘password’;
  you can also use '%' instead of the specific network ip address to add all the network ips.
  Type: grant all privileges on globalsight.* to 'globalsight'@’%’ identified by ‘password’;
  Also need to use command flush privileges
  Type: flush privileges;
  Commit the change
  Type: commit;
  Exit Mysql
  Type: exit 

Senthil, 2012/11/27 16:16

Not sure why this is a problem. You can have multiple databases on MySQL and one will not “interfere” with the other.

Daniel R, 2013/03/17 08:16

You have MySQL instructions, yet do not have a Postfix MySQL Maps Section, just wondering how you did it? So far your HowTo is the best out there as it describes where to put entries in each file.

Senthil Nathan, 2013/03/17 15:58

Thanks Daniel for pointing it out. I have included the MySQL configuration as well now. I am glad it is helping folks as it did take me a bit to get all this together.

Ed, 2013/08/14 07:15

Hi,

Thank you for your page. Recently I setup a homemade e-mail server and wrote a full detailed tutorial that you can find in

http://cosmolinux.no-ip.org/raconetlinux2/mail.html

using Debian Squeeze, Postfix, Dovecot, SASL, Spamassassin and Squirrel (and a Google account for SMTP relay).

I wish it is helpful to someone.

Enter your comment
CVQOH
 
 
tech/linux/mail_server_setup.txt · Last modified: 2013/12/03 07:54 (external edit)
 
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki Sitemap