fetch mail via SSH from a remote server and send them via a mail account to someone

suppose you have a server somewhere in a very restricted network. there is no way for you to send emails to your regular mail account in order to receive alerts such as Disk failures, backup reports etc… BUT: you have ssh access :)

you could setup a reverse tunnel to an smtp server somehwere, but your restricted network might not like long lasting ssh connections and kick you out all the time.. so here is a solution, where a linux machine with SSH access to your cut-off server can collect mails on that server and then forward it to a smtp server for delivery.

in my example, i deliberately change the FROM and TO header fields to always point to my own mail addres, as i want to be the sole recipient of all mails from this server and my SMTP allows only my own email address as a sender address.. you can adjust that to be a full blown mail realyer .. but be carefule what you wish for ;)

besides ssh we also need msmtp and formail. the latter is part of the procmail package in ubuntu:

sudo apt install procmail msmtp

setup password less ssh access as the user who's mail you want to fetch from the target server

create a directory tree for our mail fetcher app

├── mailfetcher.sh
├── .msmtprc
└── outbox

write that .msmtprc config file.. here is an exmaple:

account default
host my.mail.server 
port 587
tls on 
tls_starttls on 
tls_trust_file /etc/ssl/certs/ca-certificates.crt
tls_certcheck on
auth on
user my_Mail_user
password "Super$ecretPassw0rd"
from "my_email@address.fake"

make sure to put the right values in there for your mail account :)

the script below will connect to your server, fetch all mails from /var/mail/<user> and create a file for each mail in a local outbox path. once the mails are downloaded, it will erase them from the server as to not download them again in the future. it will then start a loop where it goes through all downloaded messages and sends them via msmtp.

MYPATH=$(dirname "$(readlink -f $0))")
ssh ${user}@${server} cat /var/mail/${user} | \
    FILENO=$(date +%s001) \
    formail -i "To: $mail" -k -R From: Old-From: -X Subject: -X Date: -X To: -X Old-To: -ds sh -c \
    'cat > outbox/msg.$FILENO' && \
    ssh ${user}@${server} 'echo "" > /var/mail/${user}'
for msg in outbox/msg.*; do
    cat $msg | msmtp -C .msmtprc -t -v && rm -f $msg
    sleep 15

fill the first variables with the right content ;)

make the script executable:

chmod 755 mailfetcher.sh 

to test the script, simply run it from a shell, it will print verbose output from the smtp sessions. if you run into message rate limit issues, increase the time for the sleep 15 command on the second to last line of the script.

once you are satisfied, set up a cron job..

crontab -e 

here is an example where we run the script once per hour to fetch mail and deliver it.. Headline

00 * * * *  /home/psuter/mailfetcher/mailfetcher.sh >& /dev/null
  • fetch_mail_via_ssh_from_a_remote_server_and_send_them_via_a_mail_account_to_someone.txt
  • Last modified: 26.05.2021 19:07
  • by Pascal Suter