Hello everyone!
As the title says, I am trying to set up email alerts on my server whenever there is a successful ssh connection (will also setup the same for failed connections with fail2ban later). I already have the email script created and it works (I use it to monitor the directories containing all of these security scripts for changes so that I also get notified if anything critical is modified or deleted in those directories).
I also created a very basic user called test for - you guessed it - testing purposes. This user doesn’t have a home directory or anything like that.
Here are the relevant scripts:
$ cat /usr/local/bin/login-alert.sh
#!/bin/bash
# Sends alerts only for real terminals not cron jobs
if [[ -n "$SSH_CONNECTION" ]]; then
USERNAME=$(whoami)
IP=$(echo $SSH_CONNECTION | awk '{print $1}')
HOST=$(hostname)
DATETIME=$(date)
/usr/local/bin/semail \
-s "[CRITICAL] SSH Login to $HOST" \
-b "Login detected:\n\nUser: $USERNAME\nIP: $IP\nTime: $DATETIME\nTTY: $SSH_TTY"
fi
$ cat /usr/local/bin/semail
#!/bin/bash
# Default values
TO="my_email@here.com"
FROM="notifications@my_server.com"
SUBJECT=""
BODY=""
BODY_FILE=""
# Help function
show_help() {
cat <<EOF
Usage: $0 [OPTIONS]
Send a test email using Postfix.
Options:
-t, --to EMAIL Recipient email address (default: $TO)
-s, --subject TEXT Subject of the email (required)
-b, --body TEXT Body text of the email
-f, --body-file FILE File to read body text from (overrides --body)
-h, --help Show this help message
If no body or body-file is provided, you will be prompted to enter the body interactively.
Examples:
$0 -s "Test subject" -b "Hello\nThis is a test"
$0 --subject "Test" --body-file message.txt
EOF
}
# Parse arguments
while [[ "$#" -gt 0 ]]; do
case "$1" in
-t|--to)
TO="$2"
shift 2
;;
-s|--subject)
SUBJECT="$2"
shift 2
;;
-b|--body)
BODY="$2"
shift 2
;;
-f|--body-file)
BODY_FILE="$2"
shift 2
;;
-h|--help)
show_help
exit 0
;;
*)
echo "Unknown option: $1"
show_help
exit 1
;;
esac
done
# Validate required parameters
if [[ -z "$SUBJECT" ]]; then
echo "Error: --subject is required."
show_help
exit 1
fi
# Handle body input
if [[ -n "$BODY_FILE" ]]; then
if [[ ! -f "$BODY_FILE" ]]; then
echo "Error: Body file '$BODY_FILE' does not exist."
exit 1
fi
BODY=$(<"$BODY_FILE")
elif [[ -z "$BODY" ]]; then
echo "Enter the body of the email (end with Ctrl-D):"
BODY=$(</dev/stdin)
fi
# Send email
{
echo "From: $FROM"
echo "To: $TO"
echo "Subject: $SUBJECT"
echo "Content-Type: text/plain; charset=UTF-8"
echo
printf "%b\n" "$BODY"
} | /usr/sbin/sendmail -t -f "$FROM"
# /usr/sbin/sendmail -f "$FROM" "$TO" <<EOF
# From: $FROM
# To: $TO
# Subject: $SUBJECT
# $BODY
# EOF
echo "Email sent to $TO"
And here is the output I see when I login as the test user:
ssh test@my_server.com
test@my_server.com's password:
dir=/ failed: exit code 2
dir=/ failed: exit code 2
Linux my_server 6.1.0-37-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.140-1 (2025-05-22) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Aug 15 07:08:24 2025 from my_ip_address
Could not chdir to home directory /home/test: No such file or directory
I don’t get email alerts for any user, neither the test user nor my regular admin user.
Here is my /etc/pam.d/sshd relevant lines:
# Standard Un*x session setup and teardown.
account optional pam_exec.so seteuid dir=/ /usr/local/bin/login_notify.sh
@include common-session
I also tried with session instead of account and without the dir=/ part.
Can anyone help me troubleshoot this please?
Thanks in advance. Of course if you need any more info I’ll do my best to provide it :)


Yep, its executable.
You have not shown login-notify.sh
You can also always do a cronjob parsing auth.log.
$ cat /usr/local/bin/login-alert.sh #!/bin/bash # Sends alerts only for real terminals not cron jobs if [[ -n "$SSH_CONNECTION" ]]; then USERNAME=$(whoami) IP=$(echo $SSH_CONNECTION | awk '{print $1}') HOST=$(hostname) DATETIME=$(date) /usr/local/bin/semail \ -s "[CRITICAL] SSH Login to $HOST" \ -b "Login detected:\n\nUser: $USERNAME\nIP: $IP\nTime: $DATETIME\nTTY: $SSH_TTY" fiI feel like since Im already using systemd to monitor the directories it would be best to have everything working with systemd, also because I will be adding several other such functionalities to monitor various things. For example something I already implemented is a systemd service + timer combination to periodically check the main branch of the git repo for changes to the servers local repo, and if there are any to pull them and restart any services necessary to reflect these changes on the web app, then once again email me that that happened. This way i dont need to actually connect to the server to update any changes, just push code to github.
This is my first time doing a project like this, so this might make you seasoned sysadmins yell out in horror, idk, but since Im the only one who can push code to the repo I feel its quite safe, and makes life a lot easier for me xD