Automatic Email and Text Notifications
These tutorials describe my method of automatic messaging via email and text (SMS) from my Linux servers.
Contents
Required Packages
These packages are necessary for the all the following sections of this tutorial. In Debain, install them with apt-get
:
apt-get install ssmtp procmail fetchmail
Directory Structure
Just for reference, here are the locations of the relevant files:
/
├── etc
│ └── ssmtp
│ └── ssmtp.conf
└── scripts
├── config
│ ├── accounts.conf
│ ├── ddns-fetchmailrc
│ └── ddns-mailprocess.sh
├── ddns.sh
├── email.sh
├── external-ip.sh
├── notifications.sh
└── sms.sh
And permissions:
ls -l /scripts
drwxr-xr-x 4 root config 4096 Jun 20 08:52 config -rwxr-xr-- 1 root root 260 Jun 20 08:40 ddns.sh -rwxr-xr-- 1 root mailers 564 Apr 23 12:18 email.sh -rwxr-xr-- 1 root root 529 Apr 27 07:56 external-ip.sh -rwxr-xr-- 1 root root 3834 May 15 08:32 notifications.sh -rwxr-xr-- 1 root texters 545 Apr 23 12:24 sms.sh
ls -l /scripts/config
-rwxr-x--- 1 root mailers 147 May 1 13:01 accounts.conf -rwx------ 1 root root 246 May 21 09:49 ddns-fetchmailrc -rwxr-x--- 1 root config 604 Jun 20 08:52 ddns-mailprocess.sh
Create Security Groups
I use group membership to control read access to certain files. You don't have to do this, but it was useful for me.
Create the groups:
groupadd texters #allowed to sent text messages
groupadd mailers #allowed to send email messages
groupadd config #allowed to read other config files
You can add a user to all three groups like this:
usermod -aG texters,mailers,config username
Email and Text Messaging with SSMTP
First set up the /etc/ssmtp/ssmtp.conf
. I use a dedicated Gmail account (named serveraccount@gmail.com in the example below) for all of my server messaging. When I receive an email from my server, it will look like it's coming from that Gmail.
Make a backup copy of the original config:
cp /etc/ssmtp/ssmtp.conf /etc/ssmtp/ssmtp.conf.orig
Here are the contents of my modified /etc/ssmtp/ssmtp.conf
. Replace the relevant values.
#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=serveraccount
# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
#mailhub=mail
# Where will the mail seem to come from?
rewriteDomain=gmail.com
# The full hostname
# This can be left as 'localhost'
hostname=localhost
# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
FromLineOverride=YES
mailhub=smtp.gmail.com:587
UseStartTLS=YES
UseTLS=YES
AuthMethod=LOGIN
AuthUser=serveraccount@gmail.com
AuthPass=InsertPasswordHere
TLS_CA_File=/etc/pki/tls/certs/ca-bundle.crt
FromLineOverride=YES
Since the file contains a password, make sure the file is not readable to normal users.
chown root:mail /etc/ssmtp/ssmtp.conf
chmod 640 /etc/ssmtp/ssmtp.conf
And because you don't have to remember this password, it would be a good idea to make it very long and complex (16+ characters; uppercase, lowercase, numbers, and special characters; no dictionary words).
You now need to log onto the serveraccount Gmail account and enable "less secure apps" at https://myaccount.google.com/lesssecureapps?pli=1
Here is more info about less secure apps: https://support.google.com/cloudidentity/answer/6260879?hl=en
You should now be able use the ssmtp
command line tool from your server. Most of the time, you will need to include a subject line. It's important that it follows the format below (capital 'S' on Subject, colon, space, YourSubject, two newlines):
echo -e "Subject: Hi\n\nHello, world!" | ssmtp myaccount@yahoo.com
Create a Secure Accounts File
For some of the automatic messaging, you need to store text and email accounts in a file. To figure out the destination address to send text (SMS) messages to your cell, look on your cell provider's website for the proper account/domain name. It will probably be something like "<your-phone-number>@<provider-domain>". List of provider addresses
Contents of my /scripts/config/accounts.conf
file:
#!/bin/bash
#
# Secure account information
# Permissions must be 750 root:mailers
smsto="17775551234@myprovider.net"
mailto="myaccount@yahoo.com"
Change the permissions on the file:
chown root:mailers /scripts/config/accounts.conf
chmod 750 /scripts/config/accounts.conf
Email Script
This script can be used to send an email message.
Contents of the file /scripts/email.sh
:
#!/bin/bash
# Send email message:
# Usage: $0 "<Subject>" "<Message>"
default_subject="Alert from Server (`date`)"
subject=""
message=""
case $# in
2)
subject="$1"
message="$2"
;;
1)
subject="$default_subject"
message="$1"
;;
*)
echo "Send Email Message:"
echo " Usage: `basename $0` \"Message\""
echo " `basename $0` \"Subject\" \"Message\""
exit 1
;;
esac
dir="$(cd $(dirname ${BASH_SOURCE[0]})&&pwd)"
. $dir/config/accounts.conf
echo -e "Subject: $subject\n\n$message" | /usr/sbin/ssmtp $mailto
Set up permissions:
chown root:mailers /scripts/email.sh
chmod 754 /scripts/email.sh
You can create an alias so you can quickly run this from the command line:
echo "alias email='/scripts/email.sh'" >>~/.bashrc
source ~/.bashrc
Usage:
# Send message with default subject
email "This is a test message."
# Send message with a subject
email "Test Subject" "This is a test message."
Text Script
This script can be used to send a text (SMS) message.
Contents of the file /scripts/sms.sh
:
#!/bin/bash
# Send SMS message:
# Usage: $0 "<Subject>" "<Message>"
default_subject="Alert"
subject=""
message=""
case $# in
2)
subject="$1"
message="$2"
;;
1)
subject="$default_subject"
message="$1"
;;
*)
echo "Send SMS Message:"
echo " Usage: `basename $0` \"Message\""
echo " `basename $0` \"Subject\" \"Message\""
exit 1
;;
esac
dir="$(cd $(dirname ${BASH_SOURCE[0]})&&pwd)"
. $dir/config/accounts.conf
echo -e "To: $smsto\nSubject: $subject\n\n$message" | /usr/sbin/ssmtp $smsto
Set up permissions:
chown root:texters /scripts/sms.sh
chmod 754 /scripts/sms.sh
You can create an alias so you can quickly run this from the command line:
echo "alias sms='/scripts/sms.sh'" >>~/.bashrc
source ~/.bashrc
Usage:
# Send message with default subject
sms "This is a test message."
# Send message with a subject
sms "Test Subject" "This is a test message."
Scheduled Notifications Script
One of my life improvement tasks was to organize chores into scheduled chore days and rely on text/email notification to remind me to do them.
This dramatically reduced the amount of time I spend working on chores, and the amount of effort I spend thinking about what needs to be done. I could barely get projects done because every day I was loading my task list with chores. Now I don't think about chores until I'm notified. When I think of new chores, new items for my inventory, or other things I need to be reminded of, I update my checklists. When I feel I can improve scheduling or consolidate chores, I update my notifications script.
This utilizes the Email Script and Text Script from the previous sections.
Contents of the file /scripts/notifications.sh
:
#!/bin/bash
#
# Send regular notifications.
# Currently set to run daily at NOON.
#
# Get current datetime values
dt=(`date +%Y\ %m\ %d\ %H\ %M\ %S\ %a\ %s\ %I\ %p\ %Z`)
y=$((10#${dt[0]})) #year
M=$((10#${dt[1]})) #month
d=$((10#${dt[2]})) #day
h=$((10#${dt[3]})) #hour(24)
m=$((10#${dt[4]})) #minute
s=$((10#${dt[5]})) #second
w=${dt[6]} #day of week (eg. Sun)
e=$((10#${dt[7]})) #epoch
t=$((10#${dt[8]})) #hour(12)
p=${dt[9]} #meridian (AM/PM)
z=${dt[10]} #timezone (eg. PDT)
# Schedule command when date ($1) matched regex ($2) with extra grep parameters ($3)
# Use parameter -P at $3 for perl regex: in case you need to use (str1|str2).
# Example: schedule $M$d "(115|21)" -P && sms "Subject" "Message"
# Don't use -P when you want a range of numbers including 2 or more digit numbers (ie. [1-15]).
schedule(){ echo "$1" | grep -wq $3 "$2";}
sms(){ /scripts/sms.sh "$1" "$2";}
eml(){ /scripts/email.sh "$1" "$2";}
notify(){ sms "$1" "$2";eml "$1" "$2";}
# =================================
# ==== Temporary Notifications ====
# =================================
# Dentist appointment
#schedule $M$d "58" && notify "Dentist" "Appointment 4:00pm 10/31/2017"
# =================================
# ====== Chore Notifications ======
# =================================
# LAUNDRY DAY
# Day before
schedule $w$d "Mon[1-7]" && notify "LAUNDRY DAY" "WORK: Check gas. HOME: Do laundry, put laundry away."
schedule $w$d "Mon(15|16|17|18|19|20|21)" -P && notify "LAUNDRY DAY" "WORK: Check gas. HOME: Do laundry, put laundry away."
# WEEKLY CLEANING DAY
schedule $w "Tue" && notify "WEEKLY CLEANING DAY" "WORK: Fill gas, shopping. HOME: Clean, litter, sweep/vac, fridge, trash, check meds."
# Day after
schedule $w "Wed" && notify "WEEKLY REMINDER" "Order meds if necessary."
# MONTHLY CLEANING DAY
schedule $w$d "Tue[1-7]" && notify "MONTHLY CLEANING DAY" "WORK: Car stuff. HOME: Dishes, kitchen, bathroom, dust, inventory."
# BUSINESS DAY
schedule $d "[1-4]" && notify "BUSINESS DAY" "Rent due before 5th (\$720). Fedloan, budgeting, donations, next-buy."
# TECH DAY
schedule $w$d "Mon[1-7]" && notify "TECH DAY" "WORK: Updates, phone, healthcheck, security scan, organize files. HOME: Organize Workstation/Laptop, USB drives."
# SHOPPING DAY
schedule $w$d "Wed[1-7]" && notify "SHOPPING DAY" "Shopping, carwash. Maybe do during lunch."
# GROOMING DAY
schedule $w$d "Sun[1-7]" && notify "GROOMING DAY" "Shave/trim, clip nails."
schedule $w$d "Sun(15|16|17|18|19|20|21)" -P && notify "GROOMING DAY" "Shave/trim, clip nails."
# ELIMINATION DAY
schedule $w$d "Sun(15|16|17|18|19|20|21)" -P && notify "ELIMINATION DAY" "Do at least one item on TO_ELIMINATE list."
# INVENTORY DAY
# Disabled. Inventory is now included in monthly cleaning day.
# schedule $w$d "Tue[1-7]" && notify "INVENTORY DAY" "Do home, car, and office inventory."
# =================================
# = Other Permanent Notifications =
# =================================
# Air filter replacement notifications
schedule $M$d "71" && notify "Air Filter" "Holmes HAP726: Replace HEPA filters (model:HAPF600,qty:2)"
schedule $M$d "[1|7]1" && notify "Air Filter" "Holmes HAP726: Replace Carbon filters (model:HAPF600,qty:2)"
Now set the permissions:
chown root:root /scripts/external-ip.sh
chmod 754 /scripts/external-ip.sh
Reporting External IP Address
My home server does not have a static IP address, so I use dynamic DNS. With my free DDNS service, I have to renew the domain name every 30 days. So if I forget to renew it, it will expire and I won't be able to access my server unless I know the IP address. As a contingency, I created a script that sends my external IP address to an email account every 6 hours. Then at least I would be able find out what my last IP was and use that to access my server.
Contents of the file /scripts/external-ip.sh
:
#!/bin/bash
log="/var/log/external-ip.log"
ipsrc="http://checkip.dyndns.org"
date="`date`"
addr="myaccount@yahoo.com"
ip=`curl -s --connect-timeout 3 $ipsrc 2>/dev/null|grep -Po "Current IP Address: .*?\<"|tr '<' '\0'`
echo "IP: $ip"
if [ -z "$ip" ];then
echo "$date ERROR: Could not get external IP from $ipsrc" >>$log
else
echo -e "Subject:[`hostname`] $date $ip" | /usr/sbin/ssmtp $addr
if [ "$?" = "0" ];then
echo "$date SUCCESS: $ip sent to $addr" >>$log
else
echo "$date ERROR: Could not send to $addr" >>$log
fi
fi
Now set the permissions:
chown root:root /scripts/external-ip.sh
chmod 754 /scripts/external-ip.sh
This script appends to a log file /var/log/external-ip.log
:
touch /var/log/external-ip.log
chown root:root /var/log/external-ip.log
chmod 644 /var/log/external-ip.log
Automatic Email Download
As mentioned in a previous section, I use free dynamic DNS which requires that I renew it manually every 30 days. I need to remind myself to do this. My provider sends an email notification a few days before it expires, but I hate email and I don't want it in my face all the time, certainly not in my phone.
The best solution I found was to retrieve the email automatically and send me a text message with only the subject line in the message. I eventually created a second method of notification: it generates a file in a place that I regularly go, the folder that contains all of my to-do lists.
Contents of the file /scripts/ddns.sh
:
#!/bin/bash
#
# This script is run by a cron job.
/usr/bin/fetchmail -N -d0 -f "/scripts/config/ddns-fetchmailrc" -m "/scripts/config/ddns-mailprocess.sh"
alertfile="/shares/Private/000__DDNS-ALERT__.txt"
if [ -e $alertfile ];then
chown root:root $alertfile
chmod 777 $alertfile
fi
Contents of the file /scripts/config/ddns-mailprocess.sh
:
#!/bin/bash
#
# This script is run by /scripts/ddns.sh
mailto="17775551234@myprovider.net"
date="`date`"
log="/var/log/ddns.log"
alertfile="/shares/Private/000__DDNS-ALERT__.txt"
sms="/scripts/sms.sh"
cat /dev/stdin | grep -i "^Subject:" | sed 's/Subject\://g' | $sms "DDNS" "`cat /dev/stdin` ( $date )" &&\
echo "$date - DDNS notification sent to $mailto" | tee -a $log | sed "s/$mailto/cell\ phone/g" >$alertfile &&\
chmod 777 $alertfile
Contents of the file /scripts/config/ddns-fetchmailrc
:
#
# This rc file is run by /scripts/ddns.sh
# This file MUST have root:root and chmod 700
set postmaster "username";
poll "imap.mail.yahoo.com" protocol IMAP username "myaccount@yahoo.com" password "InsertPasswordHere" is "username" here keep folder "DDNS-Mailbox" ssl
You'll notice that it creates a file /shares/Private/000__DDNS-ALERT__.txt
. The "000" is just to put it at the top of the directory listing. Also notice that I make it read-write for everyone so I can delete it from my webapp.
Set up permissions on all three files, and create the log file:
touch /var/log/ddns.log
chown root:root /var/log/ddns.log
chmod 640 /var/log/ddns.log
chown root:root /scripts/ddns.sh
chmod 754 /scripts/ddns.sh
chown root:config /scripts/config/ddns-mailprocess.sh
chmod 750 /scripts/config/ddns-mailprocess.sh
chown root:root /scripts/config/ddns-fetchmailrc
chmod 700 /scripts/config/ddns-fetchmailrc
UPDATE February 2021: Yahoo now requires you to create a secure app password. See this section.
When you run ddns.sh
as root it gives you a warning about running as root. This is okay.
fetchmail: WARNING: Running as root is discouraged.
If permissions on ddns-fetchmailrc
are not correct, you will get this failure message:
File /scripts/config/ddns-fetchmailrc must have no more than -rwx------ (0700) permissions.
Set Up Cron
Just for reference, here are the entries I made in my /etc/crontab
file:
# Crontabs to be run without 'run-parts'
#
# RUN AT NOON
0 12 * * * root /scripts/ddns.sh
0 12 * * * root /scripts/notifications.sh
# RUN EVERY 6 HOURS
1 0,6,12,18 * * * root /scripts/external-ip.sh
Yahoo App Password
As of February 2021, Yahoo changed that way third party apps can access it. Instead of using your normal password, you need to generate an app password.
- Login to Yahoo, click you user icon, and click Account Info.
- Click Account Security.
- Click Manage app passwords.
- Click the Select your app drop-down and select Other app.
- Type a name for the app then click Generate.
- Now you can copy the password and use it in your app. Once you navigate away from this page, you will not be able to retrieve the password again. You will have to generate another password.