Setting Up Your Own Mail Server on Ubuntu

It is far more professional to have an email address with your own domain name, e.g. firstname@surname.tld, rather than one offered by a free email provider. Sure, you could buy a custom email address from one of the several hosting companies out there, but how about setting up your own email server?

Whether you feel you're spending too much for your custom email address, or you're worried about your privacy, or just for the sake of it, it is worth considering having your own email server. You just need to either have an unused computer at home/office with a static IP address, or buy a cheap VPS from your favorite hosting provider.

In this tutorial, you will learn how to set up an email server on Ubuntu. The email server will be based on the following programs:

  • Postfix
    • A popular MTA (Mail Transfer Agent) used for sending and receiving emails.
  • Dovecot
    • An IMAP and POP3 server used by email clients, e.g. Mozilla Thunderbird, for transferring emails.
  • SQLite
    • A database system used for storing user mailbox accounts and other settings.

If you are planning to set up your mail server on a new VPS, I recommend that you read my post, Your First Steps with Your Brand New VPS Server, before following this tutorial. Also, you will probably notice that for encryption I use the default snakeoil SSL certificate. If you want to create a custom self-signed certificate, you can find my tutorial here.

The steps below have been successfully tested on Ubuntu 14.04.

Installation

Either start a root session with sudo -s, or add sudo before all the following commands.

Install Postfix, SQLite, and Dovecot:

$ apt-get install postfix sqlite3 dovecot-imapd dovecot-sqlite

SQLite

Open a new SQLite database at /etc/postfix/vmail.sqlite:

$ sqlite3 /etc/postfix/vmail.sqlite

The sqlite3 command allows you to manually execute SQL statements against the specified SQLite database. If the database does not exist, it will be created.

  1. First, create tables for the users that have a mailbox account, the domains that the mail server will handle, and the email aliases. Copy-paste the following commands in the SQLite shell, and press Enter:

    CREATE TABLE users (email TEXT PRIMARY KEY, password TEXT, quota INTEGER DEFAULT 0);
    CREATE TABLE domains (id INTEGER PRIMARY KEY, domain TEXT UNIQUE);
    CREATE TABLE aliases (id INTEGER PRIMARY KEY, email TEXT UNIQUE, alias TEXT);
    
  2. Assuming that your registered domain is DOMAIN.TLD, insert a new row in the domains table by copy-pasting the command below, and press Enter:

    INSERT INTO domains (domain) VALUES ('DOMAIN.TLD');
    
  3. Each user must have a password. It is always a good practice to hash passwords stored in a database, in case the database is compromised. If a user's password is MYPASSWORD, you can hash it using Dovecot's password hash generator:

    $ doveadm pw -s SSHA512 -p MYPASSWORD
    
  4. Assuming that you want to create a new mailbox account with email address USER@DOMAIN.TLD and a 2000000 KB quota, you should insert a new row in the users table as shown below. The user's password must be hashed, so make sure to replace HASHED_PASSWORD with the exact output of the command in Step 3:

    INSERT INTO users (email,password,quota) VALUES ('USER@DOMAIN.TLD','HASHED_PASSWORD', 2000000);
    
  5. You can also create aliases to forward messages from an email address to a mailbox account. The postmaster@DOMAIN.TLD alias is required for all email servers, but you can add your own aliases as well:

    INSERT INTO aliases (email,alias) VALUES ('postmaster@DOMAIN.TLD','USER@DOMAIN.TLD');
    

Press Ctrl+D to exit the SQLite shell, and then change your database permissions so that it is only accessible by root:

$ chown root:root /etc/postfix/vmail.sqlite && chmod 600 /etc/postfix/vmail.sqlite

Postfix

Before proceeding to configuring Postfix, create a new Unix user account for Postfix to use when writing to virtual mailbox files:

$ groupadd vmail -g 5000
$ useradd -r -u 5000 -g vmail -d /var/spool/mail/vmail -s /sbin/nologin -c "virtual mailbox handler" vmail
$ mkdir /var/spool/mail/vmail
$ chown -R vmail:vmail /var/spool/mail/vmail && chmod 770 /var/spool/mail/vmail

In the following configuration, it is assumed that your mail server hostname is MAIL.DOMAIN.TLD, so replace as appropriate. To avoid problems, you should make sure that the hostname matches the one in /etc/hostname.

  1. Edit /etc/postfix/main.cf:

    $ nano /etc/postfix/main.cf
    

    Replace contents with:

    # General host and delivery info
    myhostname = MAIL.DOMAIN.TLD
    myorigin = $mydomain
    mydestination =
    append_dot_mydomain = no
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
    mailbox_size_limit = 0
    recipient_delimiter = +
    relayhost =
    inet_interfaces = all
    mynetworks_style = host
    local_recipient_maps =
    message_size_limit = 26214400
    
    
    # SMTPD parameters
    smtpd_banner = $myhostname ESMTP $mail_name
    biff = no
    delay_warning_time = 4h
    unknown_local_recipient_reject_code = 450
    maximal_queue_lifetime = 3d
    minimal_backoff_time = 1000s
    maximal_backoff_time = 8000s
    smtp_helo_timeout = 60s
    smtpd_soft_error_limit = 3
    smtpd_hard_error_limit = 12
    
    
    smtpd_helo_required = yes
    smtpd_delay_reject = yes
    disable_vrfy_command = yes
    strict_rfc821_envelopes = yes
    
    
    smtpd_client_restrictions =
     permit_mynetworks
     permit_sasl_authenticated
     reject_unknown_client_hostname
     reject_rbl_client zen.spamhaus.org
     reject_rbl_client bl.spamcop.net
    smtpd_helo_restrictions =
     permit_mynetworks
     permit_sasl_authenticated
     reject_invalid_helo_hostname
     reject_non_fqdn_helo_hostname
     reject_unknown_helo_hostname
    smtpd_sender_restrictions =
     permit_mynetworks
     permit_sasl_authenticated
     reject_non_fqdn_sender
     reject_unknown_sender_domain
    smtpd_recipient_restrictions =
     permit_mynetworks
     permit_sasl_authenticated
     reject_unauth_destination
     reject_non_fqdn_recipient
     reject_unknown_recipient_domain
    smtpd_data_restrictions =
     reject_unauth_pipelining
    
    
    # Virtual domains setup
    alias_maps = hash:/etc/postfix/aliases
    alias_database = hash:/etc/postfix/aliases
    virtual_mailbox_base = /var/spool/mail/vmail
    virtual_mailbox_maps = sqlite:/etc/postfix/sqlite_mailbox.cf
    virtual_alias_maps = sqlite:/etc/postfix/sqlite_alias.cf
    virtual_mailbox_domains = sqlite:/etc/postfix/sqlite_domains.cf
    virtual_uid_maps = static:5000
    virtual_gid_maps = static:5000
    
    
    # SASL parameters
    smtpd_sasl_type = dovecot
    smtpd_sasl_path = private/auth
    smtpd_sasl_auth_enable = yes
    broken_sasl_auth_clients = no
    smtpd_sasl_security_options = noanonymous
    smtpd_sasl_local_domain =
    smtpd_sasl_authenticated_header = yes
    
    
    # TLS parameters
    tls_random_source = dev:/dev/urandom
    smtp_tls_security_level = may
    smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
    smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
    smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
    smtpd_tls_security_level = may
    smtpd_tls_auth_only = yes
    smtpd_tls_loglevel = 1
    smtpd_tls_received_header = yes
    smtpd_tls_session_cache_timeout = 3600s
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    
    
    # Integration with other packages
    virtual_transport = dovecot
    dovecot_destination_recipient_limit = 1
    
  2. Edit /etc/postfix/master.cf:

    $ nano /etc/postfix/master.cf
    

    Insert or edit as appropriate:

    submission inet n - - - - smtpd
     -o syslog_name=postfix/submission
     -o smtpd_tls_security_level=encrypt
     -o smtpd_sasl_auth_enable=yes
     -o smtpd_client_restrictions=permit_sasl_authenticated,reject
    
    
    smtps inet n - - - - smtpd
     -o syslog_name=postfix/smtps
     -o smtpd_tls_wrappermode=yes
     -o smtpd_tls_security_level=encrypt
     -o smtpd_sasl_auth_enable=yes
     -o smtpd_client_restrictions=permit_sasl_authenticated,reject
    
    
    dovecot unix - n n - - pipe
     flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -d $(recipient)
    
  3. Edit Postfix aliases:

    $ cp /etc/aliases /etc/postfix/aliases
    $ nano /etc/postfix/aliases
    

    Insert:

    root: USER@DOMAIN.TLD
    postmaster: USER@DOMAIN.TLD
    

    Create Postfix database:

    $ postalias /etc/postfix/aliases
    
  4. Create lookup file for the virtual mailboxes:

    $ nano /etc/postfix/sqlite_mailbox.cf

    Insert:

    dbpath = /etc/postfix/vmail.sqlite
    query = SELECT email FROM users WHERE email = '%s'
    result_format = %d/%u/
    
  5. Create lookup file for the virtual domains:

    $ nano /etc/postfix/sqlite_domains.cf

    Insert:

    dbpath = /etc/postfix/vmail.sqlite
    query = SELECT domain FROM domains WHERE domain = '%s'
    
  6. Create lookup file for the virtual aliases:

    nano /etc/postfix/sqlite_alias.cf

    Insert:

    dbpath = /etc/postfix/vmail.sqlite
    query = SELECT alias FROM aliases WHERE email = '%s'
    

Restart Postfix for changes to take effect:

$ service postfix restart

Dovecot

  1. Edit /etc/dovecot/conf.d/auth-sql.conf.ext:

    $ nano /etc/dovecot/conf.d/auth-sql.conf.ext
    

    Insert or edit as appropriate:

    passdb {
     driver = sql
     args = /etc/dovecot/dovecot-sql.conf.ext
    }
    userdb {
     driver = sql
     args = /etc/dovecot/dovecot-sql.conf.ext
    }
    
  2. Edit /etc/dovecot/dovecot-sql.conf.ext:

    $ nano /etc/dovecot/dovecot-sql.conf.ext
    

    Insert at the end of file:

    driver = sqlite
    connect = /etc/postfix/vmail.sqlite
    default_pass_scheme = SSHA512
    password_query = SELECT password FROM users WHERE email = '%u'
    user_query = SELECT '/var/spool/mail/vmail/%d/%n' AS home, \
    5000 AS uid, 5000 AS gid, '*:storage=' || quota AS quota_rule \
    FROM users WHERE email = '%u'
    
  3. Edit /etc/dovecot/conf.d/10-auth.conf:

    $ nano /etc/dovecot/conf.d/10-auth.conf
    

    Comment (#) all lines starting with !include, and then insert at the end of file:

    disable_plaintext_auth = yes
    auth_mechanisms = plain login
    !include auth-sql.conf.ext
    
  4. Edit /etc/dovecot/conf.d/10-mail.conf:

    $ nano /etc/dovecot/conf.d/10-mail.conf
    

    Insert or edit as appropriate:

    mail_location = maildir:/var/spool/mail/vmail/%d/%n/Maildir
    mail_uid = vmail
    mail_gid = vmail
    first_valid_uid = 5000
    last_valid_uid = 5000
    
  5. Edit /etc/dovecot/conf.d/10-ssl.conf:

    $ nano /etc/dovecot/conf.d/10-ssl.conf
    

    Insert or edit as appropriate:

    ssl = required
    ssl_cert = </etc/ssl/certs/ssl-cert-snakeoil.pem
    ssl_key = </etc/ssl/private/ssl-cert-snakeoil.key
    
  6. Edit /etc/dovecot/conf.d/10-master.conf:

    $ nano /etc/dovecot/conf.d/10-master.conf
    

    Insert or edit as appropriate:

    service auth {
     unix_listener auth-userdb {
      mode = 0600
      user = vmail
      group = vmail
     }
     unix_listener /var/spool/postfix/private/auth {
      mode = 0660
      user = postfix
      group = postfix
     }
    }
    
  7. Edit /etc/dovecot/conf.d/20-imap.conf:

    $ nano /etc/dovecot/conf.d/20-imap.conf
    

    Insert or edit as appropriate:

    protocol imap {
     mail_plugins = quota imap_quota
    }
    
  8. Edit /etc/dovecot/conf.d/90-quota.conf:

    $ nano /etc/dovecot/conf.d/90-quota.conf
    

    Insert or edit as appropriate:

    plugin {
     quota = maildir:User quota
    }
    
  9. Edit /etc/dovecot/conf.d/15-lda.conf:

    $ nano /etc/dovecot/conf.d/15-lda.conf
    

    Insert or edit as appropriate:

    postmaster_address = postmaster@DOMAIN.TLD
    

Modify user permissions, and restart Dovecot for changes to take effect:

$ chown -R vmail:dovecot /etc/dovecot && chmod -R o-rwx /etc/dovecot
$ service dovecot restart

Mozilla Thunderbird

You should now be able to read and send emails from your server using an email client, such as Thunderbird. Create a new mail account using the settings below:

Incoming server

Server type: IMAP
Server name: MAIL.DOMAIN.TLD
Port: 993
User name: USER@DOMAIN.TLD
Connection security: SSL/TLS
Authentication method: Normal password

Outgoing server

Server name: MAIL.DOMAIN.TLD
Port: 587
User name: USER@DOMAIN.TLD
Connection security: STARTTLS
Authentication method: Normal password

In case of troubleshooting, you should check the log file at /var/log/mail.log to see if any errors have been reported by Postfix/Dovecot.

That's it! You are now a postmaster! If you feel adventurous and you want to further customize your mail server, you can have a look at the Postfix and Dovecot documentations.