Basic Mailserver
1. Introduction
We want a mail server that:
-
Allows you to send email if you authenticate with a valid username and password, which are stored on an LDAP server.
-
If someone sends email to one of the mail domains supported by the server, the recipient address will be checked on the LDAP directory whether it is valid, before the mail is accepted.
-
The received emails are not stored locally, but are forwarded instead to an external email address that belongs to the user (and is recorded in the LDAP directory).
These are called "forward-only" or "no-mailbox" email accounts.
This kind of mail server could be useful for small organizations or companies. It allows them to have branded email addresses and to use their own mail server for sending emails. However it spares their users from having multiple email accounts, allowing them to receive all the emails in a single mailbox, on their preferred mail provider (for example gmail.com, mailbox.org, proton.me, etc).
At the same time, it relieves the postmaster of the organization from having to manage mailboxes and backups, scanning emails for viruses and spam, having to deal with legal issues (like GDPR), etc. These are not easy tasks and they can be done much more professionally from the dedicated email providers.
2. Requirements
2.1 Simple SMTP server
This mail server is based on the Simple and minimal SMTP server, so make sure to install and test it first.
Once you have it installed, you already have a "forward-only" mail server. To add a forwarding address (or alias):
-
Add a line like this to
config/virtual_alias_maps
:dashamir.hoxha@user1.fs.al dashohoxha@gmail.com
-
Then update the
virtual_alias_maps.db
:ds exec postmap /host/config/virtual_alias_maps
#or:
#ds inject update.sh
2.2 LDAP server
The default setup of the Simple SMTP
Server allows us to send emails only from
the "trusted hosts" (whose IPs are listed on
config/trusted_hosts
). This prevents any spammers from abusing the
mail server.
If some users need to send emails from anywhere (any random IP), they should be able to authenticate themselves to the SMTP server, for example with a username and password. The SMTP server should be able to check their username and password in a database (which may be an LDAP directory or a relational DB like MariaDB, PostgreSQL, etc.)
In our case we are going to use an OpenLDAP server for storing the needed user details (username, password and forward email).
3. Setup
3.1 Add data to LDAP
Let's populate LDAP with some data. We need app credentials, so that the mail server is allowed to check the data stored in LDAP. We also need a couple of user entities, that we can use for testing.
-
First, let’s make sure that we have the organizational units
apps
andusers
:ds ou
ds ou add apps
ds ou add users
ds ou ls
ds search "(objectClass=organizationalUnit)"OU-s are like branches or subdirectories in LDAP. The unit
apps
is for the mail server and other applications that need to check the user data on LDAP. The unitusers
is for the user entities. -
Let's also add a couple of test users:
ds user
ds user add users test1@user1.fs.al dashohoxha@gmail.com pass123
ds user add users test2@user1.fs.al dashohoxha@gmail.com
ds set-passwd pass234 uid=test2@user1.fs.al,ou=users,dc=user1,dc=fs,dc=al
ds user ls
ds search "(objectClass=inetOrgPerson)"The users can change or recover their password with a web interface at https://ldap.user1.fs.al/
-
Create app credentials for the SMTP server:
ds app
ds app add smtp pass-smtp
ds app ls
ds search "(objectClass=organizationalRole)" -
Let's also check that we are able to read data from the LDAP server, using the credentials of
cn=smtp,ou=apps,dc=user1,dc=fs,dc=al
:apt install ldap-utils
ldapsearch -xLLL \
-H ldap://ldap.user1.fs.al/ \
-D cn=smtp,ou=apps,dc=user1,dc=fs,dc=al \
-w pass-smtp \
-b ou=users,dc=user1,dc=fs,dc=al \
"(uid=test1@user1.fs.al)"
ldapsearch -xLLL -ZZ \
-H ldap://ldap.user1.fs.al/ \
-D cn=smtp,ou=apps,dc=user1,dc=fs,dc=al \
-w pass-smtp \
-b ou=users,dc=user1,dc=fs,dc=al \
"(uid=test1@user1.fs.al)" \
uid mailNote: In case of any problem, add the option
-d9
for debugging.
3.2 Enable LDAP authentication on the SMTP server
We need to uncomment the LDAP_
variables on settings.sh
, and
remake the container.
-
Go to the directory of the SMTP server:
cd /var/ds/smtp.user1.fs.al/
-
Edit
settings.sh
and uncomment the LDAP settings, giving them proper values, like these:LDAP_SERVER_HOST="ldap.user1.fs.al"
LDAP_SEARCH_BASE="ou=users,dc=user1,dc=fs,dc=al"
LDAP_BIND_DN="cn=smtp,ou=apps,dc=user1,dc=fs,dc=al"
LDAP_BIND_PW="pass-smtp" -
Re-make the container:
ds make
When the LDAP_
settings are available, the
scripts
will setup some additional configurations that instruct the SMTP
server to lookup on the given LDAP server, or to authenticate users
there, when needed.
4. Testing
Add users
The instructions in this section assume that these test users exist on the LDAP database:
- (
test1@user1.fs.al
,pass123
) - (
test2@user1.fs.al
,pass234
)
They can be added like this:
cd /var/ds/ldap.user1.fs.al/
ds ou add users
ds user add users test1@user1.fs.al dashohoxha@gmail.com pass123
ds user add users test2@user1.fs.al dashohoxha@gmail.com pass234
ds user ls
For a quick automated test of the basic functionality of the server
try: ds test2
4.1 Test the LDAP queries
cat config/smtpd_sender_login_maps.ldap
cat config/virtual_alias_maps.ldap
ds shell
postconf -f virtual_alias_maps
postconf -f smtpd_sender_login_maps
postmap -q test1@user1.fs.al \
ldap:/host/config/virtual_alias_maps.ldap
postmap -q test1@user1.fs.al \
ldap:/host/config/smtpd_sender_login_maps.ldap
If the postmap queries don't return the expected result, append the
line debuglevel = -1
on smtpd_sender_login_maps.ldap
and
virtual_alias_maps.ldap
and try to identify the problem.
You can also try with ldapsearch
, like this:
### on the host, outside the container
apt install ldap-utils
ldapsearch -x -LLL -ZZ \
-H ldap://ldap.user1.fs.al/ \
-D cn=smtp,ou=apps,dc=user1,dc=fs,dc=al \
-w pass-smtp \
-b ou=users,dc=user1,dc=fs,dc=al \
"(uid=test1@user1.fs.al)"
4.2 Test SASL authentication
ds shell
cat /etc/saslauthd.conf
cat /etc/postfix/sasl/smtpd.conf
cat /etc/default/saslauthd | grep MECHANISMS
systemctl status saslauthd
testsaslauthd \
-f /var/spool/postfix/var/run/saslauthd/mux \
-u test1 -r user1.fs.al -p pass123
postconf smtpd_sasl_auth_enable
4.3 Test sending and forwarding emails
These test commands are supposed to run on a computer other than the
server, which has a public IP that is NOT on the list of trusted hosts
(config/trusted_hosts
). While running them, it may be useful to
check the logs on the mail server, on a separate tab/terminal:
cd /var/ds/smtp.user1.fs.al/
ds exec tail /var/log/mail.log -f
4.3.1 Try to send message without authentication
Send a test message from test1@user1.fs.al
to a gmail account:
swaks --server smtp.user1.fs.al \
--from test1@user1.fs.al \
--to dashohoxha@gmail.com
swaks --server smtp.user1.fs.al \
--from test1@user1.fs.al \
--to dashohoxha@gmail.com
We are trying it twice. The first time you try to send an email from a new client the service is automatically refused (in order to confuse spam bots). The second time the connection is accepted, however it fails because the sender is not authenticated.
The test above should fail (sending email without authentication).
If it succeeds, make sure that your public IP is not on
config/trusted_hosts
.
If you modify this file you should also run ds inject update.sh
.
If you fail a few times, eventually you may get an error message
Connection refused
, like this:
=== Trying smtp.user1.fs.al:25...
*** Error connecting to smtp.user1.fs.al:25:
*** IO::Socket::INET6: connect: Connection refused
The reason is fail2ban
that runs inside the SMTP container. If a
client fails several times, it blocks its IP on the firewall. This is
a temporary block, but if you want to continue testing, you can
unblock it like this:
ds shell
fail2ban-client status postfix
fail2ban-client set postfix unbanip 188.245.242.143
fail2ban-client status postfix
4.3.2 Send a message with authentication
swaks --server smtp.user1.fs.al \
--from test1@user1.fs.al \
--to dashohoxha@gmail.com \
--auth-user test1@user1.fs.al \
--auth-password pass123
[. . .]
*** Host did not advertise authentication
[. . .]
The message Host did not advertise authentication
indicates that the
SMTP server does not accept authentication on the port 25
. Let's
try with the ports 587
and 465
:
swaks --server smtp.user1.fs.al:587 \
--from test1@user1.fs.al \
--to dashohoxha@gmail.com \
--auth-user test1@user1.fs.al \
--auth-password pass123
[. . .]
<- 235 2.7.0 Authentication successful
[. . .]
swaks --server smtp.user1.fs.al:465 \
--from test1@user1.fs.al \
--to dashohoxha@gmail.com \
--auth-user test1@user1.fs.al \
--auth-password pass123
[. . .]
<- 235 2.7.0 Authentication successful
[. . .]
It should succeed, if the password is correct.
Notice that as username we are using the whole email address
(test1@user1.fs.al
) instead of the uid (test1
).
4.3.3 Send a message from the wrong address
Let's try to send a message from the same user as before, but with
--from test2@user1.fs.al
:
swaks --server smtp.user1.fs.al \
--from test2@user1.fs.al \
--to dashohoxha@gmail.com \
--auth-user test1@user1.fs.al \
--auth-password pass123
[. . .]
<- 235 2.7.0 Authentication successful
[. . .]
<** 553 5.7.1 <test2@user1.fs.al>: Sender address rejected:
not owned by user test1@user1.fs.al
[. . .]
This --from
address does not belong to the authenticated user, so
the server refuses to send the mail.
4.3.4 Test forwarding emails
Let's send an email from test1
to test2
. It should be forwarded to
the external email address of test2
:
swaks --server smtp.user1.fs.al \
--auth-user test1@user1.fs.al \
--auth-password pass123 \
--from test1@user1.fs.al \
--to test2@user1.fs.al
Try also to send an email from an external email address to
test1@user1.fs.al
and test2@user1.fs.al
.
5. Using
5.1 Create account
The forward-only email address assumes that you already have a primary email account (on the provider of your choice) where the incoming emails are forwarded. We can create it like this:
-
Add a new user entity on the LDAP server:
cd /var/ds/ldap.user1.fs.al/
ds user add users \
dashamir.hoxha@user1.fs.al \
dashohoxha@gmail.com \
pass1234 -
Go to https://ldap.user1.fs.al/ and make sure that you can reset the password. Users can either change the password, if they know the current one (
pass1234
), or reset the password with the help of the primary email address (dashohoxha@gmail.com
).
5.2 Receive messages
All the emails that are sent to the forward-only email address
(dashamir.hoxha@user1.fs.al
) will end up in the inbox of the primary
email account (dashohoxha@gmail.com
).
To be more organized, I use filtering to automatically move all the
emails that come to dashamir.hoxha@user1.fs.al
to their own folder.
5.3 Send messages
So far so good, but what if you want to send emails from your forward-only email address, or to reply to an incoming message?
The answer lies on the SMTP settings of your mail client. Ideally, you should use a mail client that supports multiple SMTP servers, or at least multiple email accounts (one for the primary address, and one for the forward-only one). Thunderbird, for example, is a suitable email client.
The setup on Thunderbird would be like this:
-
First of all, make sure to add in Thunderbird an account for the primary email address. (Probably you already have it.)
-
Add also an additional SMTP server, with settings like this:
- Description:
dashamir.hoxha@user1.fs.al
(it can actually be anything). - Server Name:
smtp.user1.fs.al
- Port:
587
- Connection security:
STARTTLS
- Authentication method:
Normal password
- User Name:
dashamir.hoxha@user1.fs.al
- Description:
-
On the settings of the primary account, add an additional identity, with the forward-only email address (
dashamir.hoxha@user1.fs.al
). -
Make sure that the "Sending Mail Server SMTP" for this new identity is the SMTP server created above.
-
On the settings of this new identity, also make sure that the sent emails are saved on the local "Sent" directory, and archived emails on the local "Archive" directory. Do the same for "Drafts" and "Templates".
(Probably you have to create these local directories first.)
-
When you send a new email (or reply to an email) switch the identity to the one for
dashamir.hoxha@user1.fs.al
.