IMAP Email Server on AWS

Written by bobnoxious | Published 2022/12/07
Tech Story Tags: email | imap | postfix | dovecot | aws | ubuntu | tutorial | guide

TLDRAmazon Web Services (AWS) has determined that it is in their interest to block outgoing traffic on Port 25, the traditional SMTP port used for Internet Email. All other outbound ports are open for use. Amazon SES is the designated AWS workaround. For use only as an email server our instance does not require the other ordinarily present LAMP stack components, so Apache and PHP are not required. For example, we assume that you have a working basic install of Ubuntu 22 Server with the hostname set to a value similar to this template: mailyourdomain.tldvia the TL;DR App

Let me explain how to use Amazon Web Services (AWS) Simple Email Services (SES) to support an SMTP IMAP Email Server running on an AWS Lightsail virtual server using Ubuntu 22 with Postfix/Dovecot along with the AWS Route53 DNS services. The basic email server is set up to support only the system’s users, those individuals with a system user account, it is not a publicly available server.

Why use SES anyway? The Amazon pitch deck says that Amazon SES is an email platform that provides an easy, cost-effective way for you to send and receive email using your own email addresses and domains. My plain and simple answer is rather more blunt; because it is the only way you can do it on AWS Lightsail instances. AWS has determined that it is in their interest to block outgoing traffic on Port 25, the traditional SMTP port used for Internet Email. Close control of Email traffic allows them to defeat spam mailers for example. All other outbound ports are open for use. SES is the designated AWS workaround. Meanwhile all inbound ports are blocked with an exception rules firewall.

Initial Settings

In the AWS Lightsail console under Networking duplicate the exclusion settings shown here (except for Port 443 which is unnecessary for email). In particular you want to add those three settings labeled as “Custom” in the Application column. For my setup I duplicated the firewall rules for IPv6 and I also chose to use a static IP address.

Note the article assumes that you have a working basic install of Ubuntu 22 Server on your AWS virtual server instance with the hostname set to a value similar to this template: mail.yourdomain.tld. For use only as an email server the instance does not require the other ordinarily present LAMP stack components, so Apache and MySQL and PHP are not required.

Some AWS SES Document Links

Amazon provides a wealth of documentation about how to use the services they market and I am not going to repeat it unnecessarily. The introductory landing page for SES contains a menu of links to detailed sections following. Here is a “short list” collection of some particular links within the AWS documentation on SES that I found useful:

"Integrating Amazon SES with Postfix - Amazon Simple Email Service"

"Managing identities in Amazon SES - Amazon Simple Email Service"

"Testing your connection to the Amazon SES SMTP interface using the command line - Amazon Simple Email Service"

"Amazon SES email sending errors - Amazon Simple Email Service"

"Using the Amazon SES SMTP interface to send email - Amazon Simple Email Service"

"What is Amazon SES? - Amazon Simple Email Service"

Integrating Amazon SES with Postfix - Amazon Simple Email Service Classic"

"Receiving email with Amazon SES - Amazon Simple Email Service Classic"

"Sending email using the Amazon SES SMTP Interface - Amazon Simple Email Service Classic"

"Set Up and Connect to SMTP Using Amazon SES"

DNS Zone Records

Besides the SES service, another area that requires some setup is the DNS Zone Records for your domain to include some additions for your mail server. You will need to add two A records, one IPv4 and one IPv6, and an MX record for mail.yourdomain.tld. You will also need to add several DKIM records used to identify your sender as legitimate.

Amazon says that Domain Keys Identified Mail (DKIM) is an email security standard designed to make sure that an email that claims to have come from a specific domain was indeed authorized by the owner of that domain. It uses public-key cryptography to sign an email with a private key. Recipient servers can then use a public key published to a domain’s DNS to verify that parts of the email have not been modified during the transit.

There is also a record used by the SES service to identify our domain. To add these various records we will look at the Amazon documents for the DKIM setup, and at EasyDMARC for the DMARC setup, along with the SES basic setup link at the AWS SES landing page mentioned earlier. Using this information we can model our DNS Zone Records on this example here below.

Install Postfix

Assuming that you are successful thus far the next thing you will need to do is to install the Postfix mail server. As it happens the Ubuntu 22 GNU/Linux Server uses both Postfix and Dovecot for its default Mail handling services. Install Postfix with the terminal console command of sudo apt install Postfix. This will result in the series of dialog screens below wherein you will provide necessary information for Postfix’s configuration as shown. This first screen sets us up to use our SES service for outgoing mail.

Notice the second screen above which shows the SMTP endpoint and Port number for the AWS SES service as our relay host.

You will probably want to enter some reasonable size limit on the last screen above specifying the mailbox size.

If all of these settings are entered correctly you should get a console screen that looks something like this:

setting synchronous mail queue updates: false
setting myorigin
setting destinations: mail.isoblock.com, mail.isoblock.com, localhost, isoblock.com
setting relayhost: email-smtp.us-east-1.amazonaws.com:587
setting mynetworks: 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
setting mailbox_command
setting mailbox_size_limit: 0
setting recipient_delimiter: +
setting inet_interfaces: all
setting inet_protocols: all
Postfix (main.cf) is now set up with the changes above.  If you need to make
changes, edit /etc/postfix/main.cf (and others) as needed.  To view Postfix
configuration values, see postconf(1).
After modifying main.cf, be sure to run 'systemctl reload postfix'.

AWS SES Setup

Amazon offers a summary of these following actions for the SES setup which I have slightly modified as shown next.

Follow these steps to set up SMTP with Amazon SES and then connect to the Amazon SES SMTP endpoint to send email:

  1. Open the Amazon SES console.
  2. From the navigation pane, choose Account dashboard.
  3. Under Simple Mail Transfer Protocol (SMTP) settings, note the values for SMTP endpoints and Ports. Use the SMTP endpoint and ports to connect to SMTP. For example, if you’re in the eu-west-1 AWS Region, note the following:

SMTP endpoint: email-smtp.eu-west-1.amazonaws.com Port: 25, 587

  1. Choose Create My SMTP Credentials. Then, proceed with the steps to generate your SMTP credentials along with the following actions.

In a text editor, open the file /etc/postfix/sasl_passwd. If the file doesn't already exist, create it.

Add the following line, replacing SMTPUSERNAME and SMTPPASSWORD with your SMTP user name and password, and editing the SMTP endpoint AWS zone URL, respectively.

[email-smtp.us-west-2.amazonaws.com]:587 SMTPUSERNAME:SMTPPASSWORD Save and close sasl_passwd. For more information about credentials, see Obtaining Amazon SES SMTP credentials.

At a command prompt, type the following command to create a hashmap database file containing your SMTP credentials:

sudo postmap hash:/etc/postfix/sasl_passwd The /etc/postfix/sasl_passwd and /etc/postfix/sasl_passwd.db files created in the previous steps are not encrypted. Because these files contain your SMTP credentials, modify the files' ownership and permissions in order to restrict access to them. To restrict access to these files:

At a command prompt, type the following command to change the ownership of the files:

sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db At a command prompt, type the following command to change the permissions of the files so that only the root user can read or write to them:

sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db 5. Select the Amazon SES SMTP port that you’ll send email from based on the connection method that you want to use (STARTTLS). In our case this will be Port 587. Connect to the Amazon SES SMTP endpoint to test the connection over the port that you want to send email from. For example, you can run this telnet command (substitute your endpoint value) to confirm your connection:

$ telnet email-smtp.eu-west-1.amazonaws.com 587

email-smtp.eu-west-1.amazonaws.com. 6. After you confirm that the connection to the port is successful, you can start using your operating system’s command line to start sending email using the Amazon SES SMTP interface.

Postfix Configuration Files Setup

Next you have some edits to the /etc/postfix/main.cf configuration file. Carefully edit this file using your favorite editor so that it duplicates this content shown here next.

# See /usr/share/postfix/main.cf.dist for a commented, more complete version
myhostname = mail.isoblock.com
mydomain = isoblock.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases.db
myorigin = /etc/mailname
mydestination = $myhostname, mail.isoblock.com, localhost, isoblock.com
relayhost =  [email-smtp.us-east-1.amazonaws.com]:587
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +

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
# default to 2 on fresh installs.
compatibility_level = 3.6

# TLS parameters
smtp_tls_cert_file=/etc/letsencrypt/live/isoblock.com/fullchain.pem
smtp_tls_key_file=/etc/letsencrypt/live/isoblock.com/privkey.pem
smtp_tls_CAfile=/etc/ssl/certs/ca-certificates.crt
smtpd_tls_cert_file=/etc/letsencrypt/live/isoblock.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/isoblock.com/privkey.pem
smtpd_tls_CAfile=/etc/ssl/certs/ca-certificates.crt
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_use_tls=yes
smtpd_use_tls=yes

# SMTP
#smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
#smtpd_relay_restrictions = permit_mynetworks,permit_sasl_authenticated,reject
inet_interfaces = all
inet_protocols = all
#smtp_tls_security_level = may
smtp_tls_security_level = encrypt
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_auth_enable = yes
smtp_tls_note_starttls_offer = yes
virtual_alias_maps = hash:/etc/postfix/virtual
virtual_alias_maps_database = hash:/etc/postfix/virtual.db

#smtpd_tls_protocols = !SSLv2, !SSLv3
 smtp_sasl_type = dovecot
 smtpd_sasl_path = private/auth
queue_directory = /var/spool/postfix
mailbox_command = procmail -a "$EXTENSION"
smtpd_tls_loglevel = 1

Next you will want to edit the /etc/postfix/master.cf configuration file so that the submission section duplicates this content shown here next.

#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================
smtp      inet  n       -       y       -       -       smtpd
#smtp      inet  n       -       y       -       1       postscreen
#smtpd     pass  -       -       y       -       -       smtpd
#dnsblog   unix  -       -       y       -       0       dnsblog
#tlsproxy  unix  -       -       y       -       0       tlsproxy
# Choose one: enable submission for loopback clients only, or for any client.
#127.0.0.1:submission inet n -   y       -       -       smtpd
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_wrappermode=no
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_tls_auth_only=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
  -o smtpd_relay_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
 -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
# Choose one: enable smtps for loopback clients only, or for any client.
#127.0.0.1:smtps inet n  -       y       -       -       smtpd
#smtps     inet  n       -       y       -       -       smtpd
#  -o syslog_name=postfix/smtps
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#628       inet  n       -       y       -       -       qmqpd
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
#qmgr     unix  n       -       n       300     1       oqmgr
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
#
# ====================================================================

There are two files that contain information about mail redirection and delivery. One contains a table of aliases which are used for local mail redirection and the other contains a table of virtual address redirects. Here next are examples for these two files, the first one named aliases and the second one named virtual. Use your favorite text editor to generate your own files in the /etc/postfix directory using these next two examples as templates.

postmaster: ubuntu
nobody: ubuntu
hostmaster: ubuntu
usenet: ubuntu
news: ubuntu
webmaster: ubuntu
www: ubuntu
ftp: ubuntu
abuse: ubuntu
root: ubuntu
wright: wright
bobwright: wright
microsoftbob: wright
bob_wright: wright
bwright: wright
rwright: wright
[email protected] wright
[email protected] wright
[email protected] ubuntu
[email protected] ubuntu
@mail.isoblock.com wright
@isoblock.com wright

After you have created these two files use the console terminal commands sudo postmap aliases and sudo postmap virtual to create the aliases.db and virtual.db files used by Postfix. Also copy the aliases.db file to /etc/aliases.db. Once you have made these changes you will need to restart (reload) Postfix to reflect these modifications. This is done with a sudo systemctl reload postfix command.

Postfix is possessed of its own daemons, so we can also run sudo postfix reload instead of using systemctl. If you run this command Postfix will tell you that it is running in compatibility mode to support earlier versions and gives you a quick fix command line to force the current version. Here next is the result from a status command using the inbuilt Postfix daemon. Run the suggested commands to disable backwards compatibility.

:~$ sudo postfix status
postfix: Postfix is running with backwards-compatible default settings
postfix: See http://www.postfix.org/COMPATIBILITY_README.html for details
postfix: To disable backwards compatibility use "postconf compatibility_level=3.6" and "postfix reload"
postfix/postfix-script: the Postfix mail system is running: PID: 971

PHP Send Email Snippet

If you have PHP installed, as all good stacks do (I crack me up), you can run this little snippet to send a quick test email.

<?php
/*
* This is mailtest.php
*/
// Start session
session_name("Storybook");
 @session_start();
//require("/var/www/session2DB/Zebra.php");
// Create the Verify Request Mail
$email = '[email protected]';
$from    = '[email protected]';
$subject = 'Email Test';
$headers = 'From: ' . $from . "\r\n" . 'Reply-To: ' . $from . "\r\n" . 'X-Mailer: PHP/' . phpversion() . "\r\n" . 'MIME-Version: 1.0' . "\r\n" . 'Content-Type: text/html; charset=UTF-8' . "\r\n";
// Update the activation variable below
$message = '<p>Hello.<br>Please use the activation link.</p>';
mail($email, $subject, $message, $headers);
echo '<div class="alert alert-success">
  <h2>task complete.</h2></div>';
?>

Dovecot Setup

By using an agent such as MUTT or Alpine with the Postfix Mail Transfer Agent (MTA) you can now easily send and receive email. But these console Mail User Agents (MUAs) limit us to text only emails which aren’t very exciting. Or at least, mine aren’t very exciting. For the next part of the email server setup we will add Dovecot as a Mail Delivery Agent (MDA) in the form of an IMAP email server. As we observed earlier, Dovecot is the default on Ubuntu 22 Server.

Install Dovecot with the command sudo apt install dovecot-core dovecot-imapd to include the basic components, or use sudo apt install dovecot-common to install the entire package, perhaps with more features than will be used.

Once the installation completes go to the /etc/dovecot directory and open the dovecot.conf file with your favorite text editor. Empty the entire file and insert this following content instead, substituting the appropriate values for the SSL certification files.

disable_plaintext_auth = no
mail_privileged_group = mail
mail_location = mbox:~/mail:INBOX=/var/mail/%u
userdb {
  driver = passwd
}
passdb {
  args = %s
  driver = pam
}
protocols = " imap"
namespace inbox {
  inbox = yes

  mailbox Trash {
    auto = subscribe # autocreate and autosubscribe the Trash mailbox
    special_use = \Trash
  }
  mailbox Sent {
    auto = subscribe # autocreate and autosubscribe the Sent mailbox
    special_use = \Sent
  }
}
listen = *, ::
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
}
ssl = yes

# PEM encoded X.509 SSL/TLS certificate and private key.
ssl_cert = </etc/letsencrypt/live/isoblock.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/isoblock.com/privkey.pem

Now restart the Dovecot Service to incorporate these changes with the console command sudo systemctl reload dovecot.

Email Client Setup

Our Email Server uses the IMAP protocol so an appropriate Email Client to connect with it needs to be selected. A client that works well at a zero price is the Thunderbird Email Client. Thunderbird is soliciting donations, it is their sole support mechanism. A similar for pay Email Client is Postbox. I use both of these.

Let’s use Postbox for part of this example. So from the Postbox main page select the menu entry for New Mail Account which will result in the second screen from this pair shown below.

If you Continue from here on autopilot you may obtain some inaccurate results so you will want to ensure that your client settings reflect these two screens here next below, the first showing the settings for incoming mail and the second showing settings for outgoing mail.

If you have been living right, at this point you should be rewarded with a functioning IMAP Email Server that you can connect to with a client like Postbox or Thunderbird through an interface resembling this one next below from the Thunderbird client.

Here are some links to a pair of additional articles that I found informative or useful in getting this setup.

How To Set Up a Postfix E-Mail Server with Dovecot

This tutorial will tell you how to setup a basic mail server and teach you a bit about the Postfix MTA (Mail Transfer Agent)

How To Install and Configure Postfix on Ubuntu 20.04

Postfix is a popular open-source Mail Transfer Agent (MTA) that can be used to route and deliver email on a GNU/Linux server.

Conclusion

One of the pieces I read while doing this said that getting an Email Server running on Linux with Postfix and Dovecot would by no means qualify you as an email professional. Now while all that may well be true, at this point I have my own IMAP Email Server which was my immediate and primary goal. My secondary goal was to write up what I learned and share it in hope others might benefit. Working on Moksha.

Thanks be to my family and friends and God for all the excellent support!

Comments, Criticisms, Corrections are always welcome.

An earlier version of this article appears here.


Written by bobnoxious | Bob has been designing hardware and coding software for decades. He likes to draw and write. He’s a web cadet wannabe.
Published by HackerNoon on 2022/12/07