Skip to main content

3 Simple Steps to Send Email Alerts From a Linux Server

Pulblished:

Updated:

Comments: counting...

Set up outgoing Email alerts for your Linux server quickly and easily through Gmail, plus a bonus systemd monitoring script.

In this tutorial, you will configure a Linux server to send Email through Gmail. It’s much easier than setting up a full-featured Email server and is more appropriate if all you need is to get Email alerts out from your server or application.

I’ve also included a quick script at the end of this tutorial that will check the status of systemd periodically and send out Email alerts if any problems are detected.

This guide assumes you are using Debian/Ubuntu, some commands and package names may need to be adapted to your OS if you are not.

Step 1 - Set up an Email account

In this example I am using Gmail because it is a popular choice, other mail services will work in a similar manner. You will need to enable the “less secure apps” setting in Gmail to allow your server to log in and send mail without getting blocked by Google’s security measures, visit https://myaccount.google.com/lesssecureapps , make sure you have the correct account selected in the top right corner, and then turn the feature on.

Step 2 - Configure Postfix

We will install the following packages:

  • postfix: A mail transfer agent
  • mailutils: A set of command-line utilities for working with Email, most notably the mail command that is useful for sending an Email from command-line.
  • libsasl2-modules: A module used by postfix to authenticate to an external Email server like Gmail with a username and password.
apt install -y postfix mailutils libsasl2-modules

For CentOS, use yum install -y postfix mailx cyrus-sasl-plugin

Postfix will need to log in through Gmail to submit messages, you’ll need to create the sasl_passwd file and add your credentials to it.

/etc/postfix/sasl_passwd

[smtp.gmail.com]:587 username@gmail.com:password

The postmap command will convert our text file into a lookup table, which is a data format that postfix can quickly and efficiently parse for data.

postmap /etc/postfix/sasl_passwd

Since these two files contain your Gmail password, it is wise to lock down their permissions so only the root user can access their contents.

chown root. /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd
chown root. /etc/postfix/sasl_passwd.db
chmod 600 /etc/postfix/sasl_passwd.db

the chown command changes the owner user and group, and the chmod command will changes the access mode (permissions), more detailed information on ownership and permissions can be found here .

Using chown root. is the same as chown root:root or chown root.root, leaving the group name blank will use the default group for the user specified.

We need to set up aliases and virtual alias maps, aliases will redirect mail from one user to another on the same host, for example from postmaster@ServerHostName to root@ServerHostName, we will direct all Email to root here. Virtual alias maps complete the picture by redirecting mail from local users on this host to an external Email address.

/etc/aliases

You should run the command newaliases after changing this file so it will be parsed appropriately. You can add any other local users that may receive mail to this list.

postmaster: root
nobody: root
hostmaster: root
webmaster: root
www: root

/etc/postfix/virtual

The Email address here is where any mail will be directed.

root you@yourdomain.com

The virtual alias map file also needs to be post mapped.

postmap /etc/postfix/virtual

In the main configuration file for postfix, update the values for the following lines, if a line is missing from your configuration file you’ll just need to add the whole line.

/etc/postfix/main.cf

These settings tell postfix to use Gmail as a relay to send mail out, and then specify the parameters and credentials for connecting to Gmail.

relayhost = [smtp.gmail.com]:587
smtp_tls_security_level = may
smtp_sasl_auth_enable = yes
smtp_sasl_security_options =
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd

These settings are for aliasing as explained above

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual

I also remove all the values from mydestination, this tells postfix it is not to receive any mail on this system, it will only send it out the relay host or reject the message.

mydestination =

If you do not have IPv6 enabled, you will need to specify the following value in main.cf as well, often DNS queries for Gmail will return the IPv6 address first, and postfix will fail to send mail because the relay host is unreachable.

inet_protocols = ipv4

Restart postfix to apply the configuration.

systemctl restart postfix

Step 3 - Make sure it all works

Now you should be able to send a test Email with the command below, we will send the email to the root user and it should get re-routed to the final address specified in /etc/postfix/virtual.

echo "This is a test Email" | mail -s "Testing" root

Bring up the logs for postfix with the command below, then hold the shift key and press the letter g on your keyboard to jump to the bottom where the newest entries are.

less /var/log/mail.log

If everything went smoothly, you should see log entries similar to those below.

postfix/pickup[110202]: 4317C18E47: uid=0 from=<root>
postfix/cleanup[62865]: 4317C18E47: message-id=<20190805104206.4317C18E47@ServerHostName>
postfix/qmgr[5024]: 4317C18E47: from=<root@ServerHostName>, size=249104, nrcpt=1 (queue active)
postfix/smtp[62876]: 4317C18E47: to=<you@yourdomain.com>, relay=smtp.gmail.com[74.125.195.109]:587, delay=1.3, delays=0.04/0.01/0.02/1.2, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 5B6D12E007B)
postfix/qmgr[5024]: 4317C18E47: removed

If you are setting this up on a VPS, you may see an error message like the one below. In which case you just need to log in to the Gmail account from your web browser, you should see an alert there stating that a login attempt was blocked; click through and choose “This was me”, and test sending mail again after that.

postfix/smtp[19724]: E3C71A4D: to=<you@yourdomain.com>, orig_to=<root>, relay=smtp.gmail.com[108.177.9.108]:587, delay=202, delays=202/0.05/0.31/0, dsn=4.7.14, status=deferred (SASL authentication failed; server smtp.gmail.com[108.177.9.108] said: 534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbv6?534-5.7.14 Y_y6_l6lnq7awbD3g-kRUqe5uT5hbCPVkxC3L57wTzokPWquZVVw4B9Hk9dapPHmFWHhp5?534-5.7.14 9UOBPafiJZBzXH36l0MyenRtgeMtrMdv1Wxt1W2wEepiy1iB6thU3uuYsWqBzI> Please?534-5.7.14 log in via your web browser and then try again.?534-5.7.14  Learn more at?534 5.7.14  https://support.google.com/mail/answer/78754 q24sm27754378otl.31 - gsmtp)

Bonus - Systemd monitoring script

This script will check the status of systemd, if all is well it just quits, if not it will fire off an Email alert specifying which unit has failed, and re-check every minute until the issue is resolved (without sending additional Emails until all services are restored).

First, we need to create a file for the script and make it executable.

touch /usr/local/bin/systemd-failed-notifier.sh
chmod +x /usr/local/bin/systemd-failed-notifier.sh

Copy and paste the script below into that file.

/usr/local/bin/systemd-failed-notifier.sh

#!/bin/bash

emailAddress="root"
statusFile="/tmp/systemd-failed-notifier-status"
lockFile="/tmp/systemd-failed-notifier-lock"

# Check for lock file and create one or quit
if [ -f "$lockFile" ]; then
  exit 0
else
  touch "$lockFile"
fi

# Read status file if it exists or create it
if [ -f "$statusFile" ]; then
  source "$statusFile"
else
  touch "$statusFile"
  lastSystemStatus="unknown"
fi

doAlert () {
  # If system status has changed, update statusFile and send email
  if [ ! "$systemStatus" = "$lastSystemStatus" ]; then
    if [ "$systemStatus" = "degraded" ]; then
      failedUnits="$(systemctl --failed | grep failed | cut -f2 -d' ')"
    else
      failedUnits=""
    fi
    echo -e \
    "
    Current Status: $systemStatus
    Previous Status: $lastSystemStatus

    Failed Units:
    $failedUnits" | \
    mail -s "$(hostname) $systemStatus" $emailAddress
    sleep 5
    lastSystemStatus="$systemStatus"
  fi
}

# Run once
systemStatus=$(systemctl is-system-running)
doAlert

# Loop if system status is not running
while [ ! "$systemStatus" = "running" ]; do
  sleep 60
  systemStatus=$(systemctl is-system-running)
  doAlert
done

# Cleanup and exit
echo lastSystemStatus="$systemStatus" > "$statusFile"
rm "$lockFile"
exit 0

We just need to create the service and timer files for systemd to run the script periodically.

touch /etc/systemd/system/systemd-failed-notifier.service
touch /etc/systemd/system/systemd-failed-notifier.timer

/etc/systemd/system/systemd-failed-notifier.service

[Unit]
Description= Systemd status email alert service

[Service]
Type=simple
ExecStart=/usr/local/bin/systemd-failed-notifier.sh

/etc/systemd/system/systemd-failed-notifier.timer

The value OnBootSec sets the time to wait after the system boots up before running the script for the first time, and OnUnitActiveSec sets the time to wait in between each subsequent run of the script after that.

[Unit]
Description=Systemd status email alert timer

[Timer]
OnBootSec=5min
OnUnitActiveSec=60min
Unit=systemd-failed-notifier.service

[Install]
WantedBy=timers.target

The following commands will configure the system to start the timer every time it boots up, and to start the timer right now.

systemctl enable systemd-failed-notifier.timer
systemctl start systemd-failed-notifier.timer