Victor is a full stack software engineer who loves travelling and building things. Most recently created Ewolo, a cross-platform workout logger.

    Setting up a mail server and client on Ubuntu using postfix and mutt

    In this tutorial we will setup a mail server using postfix and an email client using mutt on a Ubuntu system. Initially we will only configure postfix to deliver mail locally and then enhance it to allow sending mails externally via a gmail account.

    Mutt is an powerful email client and can be used to receive, read and sent emails directly from the console. Mutt is higly configurable and a sample setup is provided to get started. Mutt can also be used directly in conjuction with gmail to send and receive messages but in this setup we will hand-off the sending of email to postfix so that other applications can also easily send mails to the outside.

    Update September 30, 2016

    Instructions on setting up mutt as a gmail client can be found here

    Update February 27, 2018

    Added debugging and ssl certificate information

    Install postfix

    The first order of business is to install postfix:

    sudo apt-get install postfix
    Under General type of mail configuration select Local only. Also, for the system mail name, you can put in localhost (presuming that you are sending email to @localhost).

    By default, your mailbox is located at /var/mail/<username>.

    Install mutt

    Mutt can be installed via the following command:

    sudo apt-get install mutt

    We will now configure mutt by overwriting the contents of ~/.muttrc. The most important is the mailboxes property where we have set the inbox to be the one where postfix will deliver mail to.

    set from = "Victor Parmar <>"
    set edit_headers = yes
    set folder = ~/Mail                        # mailbox location
    set tmpdir = "/tmp"
    set record = "+sent"
    set mbox = "+mbox"
    set postponed = "+postponed"
    set wait_key = no                          # shut up, mutt
    set mbox_type = Maildir                    # mailbox type
    set timeout = 3                            # idle time before scanning
    set mail_check = 0                         # minimum time between scans
    unset move                                 # gmail does that
    set delete                                 # don't ask, just do
    unset confirmappend                        # don't ask, just do!
    set quit                                   # don't ask, just do!!
    unset mark_old                             # read/new is good enough for me
    set beep_new                               # bell on new mails
    set pipe_decode                            # strip headers and eval mimes when piping
    set thorough_search                        # strip headers and eval mimes before searching
    ignore *                                   # ignore all headers
    unignore from: to: cc: date: subject:      # show only these
    unhdr_order *                              # some distros order things by default
    hdr_order from: to: cc: date: subject:     # and in this order
    set date_format = "%m/%d"
    set index_format = "[%Z]  %D  %-20.20F  %s"
    set sort = threads                         # like gmail
    set sort_aux = reverse-last-date-received  # like gmail
    set uncollapse_jump                        # don't collapse on an unread message
    set sort_re                                # thread based on regex
    set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"set date_format = "%m/%d"
    set index_format = "[%Z]  %D  %-20.20F  %s"
    set sort = threads                         # like gmail
    set sort_aux = reverse-last-date-received  # like gmail
    set uncollapse_jump                        # don't collapse on an unread message
    set sort_re                                # thread based on regex
    set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"
    set sidebar_delim   = '  │'
    set sidebar_visible = yes
    set sidebar_width   = 24
    set status_chars  = " *%A"
    set status_format = "───[ Folder: %f ]───[%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]───%>─%?p?( %p postponed )?───"
    mailboxes /var/mail/vic \
              ~/Mail/sent \
    set pager_index_lines = 10                 # number of index lines to show
    set pager_context = 3                      # number of context lines to show
    set pager_stop                             # don't go to next message automatically
    set menu_scroll                            # scroll in menus
    set tilde                                  # show tildes like in vim
    unset markers                              # no ugly plus signs
    push <show-version>

    If you are feeling adventurous and already have some experience with mutt you can check out various other configurations such as this, this and this. There's also a web application which allows you to build your own muttrc:!

    Fire up mutt via mutt and voila, you have a fresh new email client!

    A few mutt commands

    For the most part, ? will open up a help window with the available commands and the top bar also indicates common actions, but nevertheless here are some useful commands:

    Changing folders
    c, ? to open the list of folders, tab to switch between mailboxes
    Sync mailbox

    Test local mail setup

    At this point sending and receiving local mail should be working and can be tested via the following python script:

    import smtplib
    import string
    SUBJECT = "Test email"
    TO = "vic@localhost" # change to your username
    FROM = "python@localhost"
    text = "blah blah blah"
    BODY = string.join((
            "From: %s" % FROM,
            "To: %s" % TO,
            "Subject: %s" % SUBJECT,
    server = smtplib.SMTP('localhost')
    server.sendmail(FROM, TO,BODY)
    Running mutt after executing the above script should show an email from python@localhost in your inbox.

    Configure postfix to use gmail relay

    We will now configure postfix to use gmail's SMTP service to send emails. Note that you will need a gmail account and will also be storing the password for this account as cleartext in a root protected file.

    Assuming postfix has already been installed, we will need to install the other required modules:

    sudo apt-get install mailutils libsasl2-2 ca-certificates libsasl2-modules

    Edit /etc/postfix/ and add the following configuration:

    relayhost = []:587
    smtp_sasl_auth_enable = yes
    smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
    smtp_sasl_security_options = noanonymous
    smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
    smtp_use_tls = yes

    Make sure that the the following settings are also correctly set:

    #inet_interfaces = loopback-only
    inet_interfaces = all
    #default_transport = error

    For additional logging add the following lines:

    Add your gmail credentials in /etc/postfix/sasl_passwd:


    Fix permissions and update postfix config to use sasl_passwd file:

    sudo chmod 400 /etc/postfix/sasl_passwd
    sudo postmap /etc/postfix/sasl_passwd

    Restart postfix for the changes to take effect: sudo service postfix restart

    By default, only the most secure sign-ins, such as logging in to Gmail on the web, are allowed for your Gmail account. To permit relay requests, log in to your Gmail account and turn on Allow less secure apps.

    Testing the relay service can be done via the following: mail -s "Test subject" Login to gmail and verify that the test email is present in the sent folder. Note that the sender email always overwritten with the account email whose credentials were provided in sasl_passwd no matter what is provided in the header.


    • postfix logs can be found at /var/log/mail.log
    • If you make any changes to the password file, make sure to rehash the new password file and restart Postfix
    • If you see any TLS errors, double check the configuration in
    • If you make any configuration changes, don't forget to restart Postfix for the changes to take effect
    • If you get an error "SASL authentication failed; server", you need to unlock the captcha by visiting this page

    HackerNews submission / discussion

    Back to the article list.

    SmallData newsletter

    Subscribe to get articles as they are published direct to your inbox!