Quite often web applications need to send email notifications. For example Moodle needs to notify students and teachers about various events. Without being able to send notifications, Moodle and many other web applications loose half of their usefulness. On many web applications you cannot even finish the registration process and cannot login, unless you verify your email address (the application sends you an email with a link that you have to click).
To send emails, an application needs to contact by SMTP a local or remote mail server. Installing a mail server is not so easy because it needs also some DNS and other configurations, in order to do it properly, otherwise the mails that are sent will end up being classified as spam and most probably will not reach the recipient.
A relatively easy solution is to send emails from GMail SMTP servers, on behalf of the web application. For this you need a GMail account, which often needs to be different for each application. Managing lots of gmail accounts is a bit inconvenient. However the biggest problem is that gmail accounts have a limit on the number of messages that can be sent each month. For many applications this limit may be OK, but for some others it is not. For example Moodle typically needs to send a message for each course subscriber, for each event of the course. Even for a small Moodle site that does not have many active courses, the monthly limit can be reached very quickly.
Another alternative is to install your own mail server, and to configure it properly. This article describes how to do it. The aim of this mail server is not to be a full-fledged system, where users can have accounts and use it daily, but just to support web applications (like Moodle) with sending notifications.
Before starting with building a SMTP server, let's see first the easy solution, in case this is sufficient for your needs.
-
First install Simple SMTP:
apt install ssmtp
-
You can create a new GMail account or use an existing one. In both cases you need to enable the two-factor authentication on the google account, and then to create a new application-specific password on this account, as described here: https://www.lifewire.com/get-a-password-to-access-gmail-by-pop-imap-2-1171882
-
Edit
/etc/ssmtp/
and place a content like this:[email protected] mailhub=smtp.gmail.com:587 [email protected] AuthPass=xyzxyzxyzxyzxyzxyz UseTLS=YES UseSTARTTLS=YES rewriteDomain=gmail.com hostname=localhost FromLineOverride=YES
Here
AuthPass
is the app-specific password generated on the step above. -
Add this line on
/etc/ssmtp/revaliases
:root:[email protected]:smtp.gmail.com:587
To test that it works, create and execute a script called test-ssmtp.sh
with a content like this:
#!/bin/bash -x
recipient=${1:[email protected]}
cat <<EOF | sendmail -v $recipient
To: $recipient
Subject: Testing ssmtp
Line 1
Line 2
EOF
Note: Replace [email protected]
with your email address or call
the script with your email address as an argument.
In order to build a mail server you need to own a domain (say
example.org
) and be able to customize its DNS records.
For each email domain you need something like this on the DNS configuration:
; mail for example.org
smtp.example.org. IN A 10.11.12.13
example.org. IN MX 1 smtp.example.org.
example.org. IN TXT "v=spf1 mx -all"
The first line shows the IP of the server smtp.example.org
. The
second line shows that the mail server (MX
) for the domain
example.org
is smtp.example.org
. Number 1
shows the priority of
the mail server (since there may be more than one mail servers for the
same domain).
The third line basically tells to the other SMTP servers that only
this server is allowed to send emails on behalf of this domain, and no
other servers. This is done to prevent spammers from faking your email
addresses. If a spammer tries to send a mail as if it is coming from
your domain, the SMTP server that is getting this email will consult
this DNS record, will figure out that the server of the spammer is not
allowed to send emails on behalf of example.org
, and will
immediately classify that email as spam or reject it at all.
Note: The configuration lines above are suitable for bind9
(they
should normally go to example.org.db
). If you use some other system
for managing your domain records, you should figure out how to do them
properly on it. If you are starting from scratch and don't have yet a
domain for the mail server, I would suggest trying this for managing
its DNS configuration: https://github.com/docker-scripts/bind9
Note: On bind9
, make sure to change the serial number on the
configuration file and then restart the service: systemctl restart bind9
. It may take a few hours or a couple of days for the DNS
changes to propagate on the internet.
You can use dig
to verify that these settings have already been
activated:
$ dig MX example.org +short
1 smtp.example.org.
$ dig A smtp.example.org +short
10.11.12.13
$ dig TXT example.org +short
"v=spf1 mx -all"
It is easy to build a postfix container with docker-scripts.
sudo su
apt install m4
git clone https://github.com/docker-scripts/ds /opt/docker-scripts/ds
cd /opt/docker-scripts/ds/
make install
- Get the scripts:
ds pull wsproxy
- Create a container directory:
ds init wsproxy @wsproxy
- Fix the settings:
cd /var/ds/wsproxy/; vim settings.sh
- Build image, create the container and configure it:
ds make
We need wsproxy
to get and manage letsencrypt SSL certificates for
the postfix
container.
- Get the scripts:
ds pull postfix
- Create a container directory:
ds init postfix @smtp.example.org
- Fix the settings:
cd /var/ds/smtp.example.org/ ; vim settings.sh
- Build image, create the container and configure it:
ds make
- Get a letsencrypt SSL certificate:
ds get-ssl-cert
DKIM keys are used by mail servers to sign the emails that they send, so that they cannot be changed in transit, and so that it can be verified that they were sent by them. It is an important tool against spams and faked emails. If a smtp server signs the messages that it sends, it is less likely that they will be classified as spam.
Installation scripts generate a DKIM key as well, which is on
config/dkim-keys/example.org/
. To activate it you need to add a
record like this on the DNS configuration of the domain:
mail._domainkey.example.org. IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQE....kMJdAwIDAQAB"
You can find the content of the public key on the file:
config/dkim-keys/example.org/mail.txt
.
Don't forget to update the serial number of the DNS domain and to
restart or reload the service (systemctl restart bind9
). It may take
a couple of hours or days until these changes are propagated on the
internet.
To check whether it has been activated or not, try the command:
dig TXT mail._domainkey.example.org +short
DMARC is a standard that allows you to set policies on who can send email for your domain based on DKIM and SPF. For more details see this: https://postmarkapp.com/support/article/892-what-is-dmarc
You can add a DMARC Record on DNS that will allow you to get weekly reports from major ISPs about the usage of your email domain.
-
Go to http://dmarc.postmarkapp.com/ and add your email address where you want to receive reports, and email domain name (
example.org
). -
On the DNS configuration of the domain add a TXT record like this:
_dmarc.example.org. IN TXT "v=DMARC1; p=none; pct=100; rua=mailto:[email protected]; sp=none; aspf=r;"
The value of this TXT record is the one generated by the website above.
-
To check that it has been activated, try the command:
dig TXT _dmarc.example.org. +short
-
Install
swaks
:cd /var/ds/smtp.example.org/ ds shell apt install swaks
-
Send a test email and check the logs:
swaks --from [email protected] --to [email protected] -tlso tail /var/log/mail.log
The option
-tlso
tells it to use TLS if possible. -
Send a test email to a gmail account:
swaks --from [email protected] --to [email protected] -tlso tail /var/log/mail.log
On gmail use "Show original" from the menu, to see the source of the received email.
-
Try to send a test email from the host (outside the container):
cd /var/ds/smtp.example.org/ swaks --from [email protected] --to [email protected] -tlso tail /var/log/mail.log
It may fail, because the IP of the host may not be on the list of the trusted hosts (that are allowed to send email for the domain
example.org
). Add it onconfig/trusted_hosts
and then runds inject update.sh
. Verify that now you can send emails. -
Try to send email to
[email protected]
:swaks --from [email protected] --to [email protected] -tlso ... <** 550 5.1.1 <[email protected]>: Recipient address rejected: User unknown in virtual alias table ...
It may fail because the recipient does not exist on the alias table. On
config/virtual_alias_maps.cf
add a line like this:Then update the alias db:
ds exec postmap /host/config/virtual_alias_maps.cf
(ords inject update.sh
). Verify that now you can send emails to this address. -
Send an email to
[email protected]
:swaks --from [email protected] --to [email protected] \ --server smtp.example.org -tlso
The automatic reply will give you important information about the status and health of your email server (for example whether the mails sent from it pass the SPF and DKIM checks, whether they are considered spam or not, etc.)
-
Go to https://www.mail-tester.com/ and send a message to the email address displayed there, like this:
swaks --from [email protected] --to [email protected] \ --server smtp.example.org -tlso
Then click the button for checking the score.
Note: Another way to send test emails (instead of swaks
) is by
using curl
and a script testmail.sh
with a content like this:
#!/bin/bash
from_address='[email protected]'
to_address='[email protected]'
cat << EOF | curl -v --ssl --upload-file - \
--url 'smtp://smtp.example.org' \
--mail-from $from_address \
--mail-rcpt $to_address
From: $from_address
To: $to_address
Subject: test $(date)
Test message.
EOF
There are lots of tools and websites that help to check the configuration of a mail server (DNS settings, configuration, security features, etc.) These are some of them:
-
https://github.com/drwetter/testssl.sh/
git clone --depth 1 https://github.com/drwetter/testssl.sh.git cd testssl.sh/ ./testssl.sh -t smtp smtp.example.org:25
The same smtp server can support more than one mail domains. If we
want to add another mail domain, for example example.com
, we have to
do these:
-
Edit
config/virtual_alias_domains
and add the domain on a new line. -
Edit
config/virtual_alias_maps.cf
and add new email aliases (for[email protected]
,[email protected]
,[email protected]
,[email protected]
, etc.) -
Update server configuration with
ds inject update.sh
, or:ds exec postmap /host/config/virtual_alias_maps.cf ds exec postfix reload
-
Generate a DKIM key for the domain:
ds dkimkey add example.com
-
Go to http://dmarc.postmarkapp.com/ and generate a DMARC record for the new domain.
-
Update the DNS configuration with records like these:
; mail for example.com example.com. IN MX 1 smtp.example.org. example.com. IN TXT "v=spf1 mx -all" mail._domainkey.example.com. IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQE....kMJdAwIDAQAB" _dmarc.example.com. IN TXT "v=DMARC1; p=none; pct=100; rua=mailto:[email protected]; sp=none; aspf=r;"
Note that:
- The MX record has the same SMTP server as the primary domain:
smtp.example.org
(not the new domainsmtp.example.com
). - The value of the key for the DKIM record can be found on the file:
config/dkim-keys/example.com/mail.txt
- The value of the DMARC record is the one obtained on the previous step. You can check these DNS configurations like this:
dig mx example.com. +short dig txt example.com. +short dig txt mail._domainkey.example.com. +short dig txt _dmarc.example.com. +short
- The MX record has the same SMTP server as the primary domain:
Different applications have different methods for configuring the SMTP server. Let's see how to send emails from cron jobs and from Moodle.
Important: For this to work, the IP of the application server
should be on the list config/trusted_hosts
on the smtp server,
otherwise it will refuse to accept and send emails. After adding it on
this list, run ds inject update.sh
to update the configuration of
the mail server.
Cron jobs (for example logwatch
) send emails to root
through
sendmail
. We can make it work with ssmtp
. First install it with:
apt install ssmtp
. Then edit /etc/ssmtp/ssmtp.conf
like this:
mailhub=smtp.example.org
rewriteDomain=example.org
UseSTARTTLS=YES
FromLineOverride=YES
Test it with: echo test | sendmail -v root
If we search for smtp
on the GUI menu for administration, we will
find that the place for SMTP configuration is on Dashboard > Site administration > Server > Email > Outgoing mail configuration
(or on
the location: /admin/settings.php?section=outgoingmailconfig
).
But we can also configure Moodle from command line, like this:
moosh config-set smtphosts smtp.example.org
moosh config-set smtpsecure TLS
moosh config-set smtpauthtype PLAIN
moosh config-set smtpuser ''
moosh config-set smtppass ''
moosh config-set smtpmaxbulk 100
- https://www.linux.com/learn/how-set-virtual-domains-and-virtual-users-postfix
- https://tecadmin.net/send-email-smtp-server-linux-command-line-ssmtp/
- https://blog.kruyt.org/postfix-and-tls-encryption/
- https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf
- https://tecadmin.net/setup-dkim-with-postfix-on-ubuntu-debian/
- https://www.skelleton.net/2015/03/21/how-to-eliminate-spam-and-protect-your-name-with-dmarc/