msmtp and failure alerts
One outbound mail account for Forgejo, Uptime Kuma, and an email whenever a systemd job fails.
Names and addresses are placeholders. The list says what each one stands for.
What it does here
Three things send mail: Forgejo, Uptime Kuma and a failed backup. They share one SMTP account. A shell script can't speak SMTP, so msmtp sits between systemd and the relay.
Canonical setup
msmtp as the system's sendmail, configured in /etc/msmtprc, and a systemd template unit that OnFailure= can call.
Upstream: msmtp documentation, systemd.unit.
In this build
- One relay accountForwardEmail's outbound SMTP,
smtp.forwardemail.neton port 465 with implicit TLS, sending asnoreply@tailnet.example. - Forgejo's mailer set by environment variables
- Uptime Kuma's SMTP notification on the same account
- A notify-email@ template unitAttached to the backup service with an
OnFailure=drop-in, and reusable for any other unit.
Enable outbound SMTP for the domain at the provider first, add the DNS records it lists (SPF, DKIM, DMARC, return path), create the sending alias and generate its password.
- FORGEJO__mailer__ENABLED=true
- FORGEJO__mailer__PROTOCOL=smtps
- FORGEJO__mailer__SMTP_ADDR=smtp.forwardemail.net
- FORGEJO__mailer__SMTP_PORT=465
- FORGEJO__mailer__FROM=Forgejo <noreply@tailnet.example>
- FORGEJO__mailer__USER=noreply@tailnet.example
- FORGEJO__mailer__PASSWD=the-generated-passwordTest from Site Administration, then Configuration, then Send Test Email. In Uptime Kuma, add an Email (SMTP) notification with the same host, port and account, TLS on, and attach it to every monitor.
sudo apt install -y msmtp msmtp-mta
sudo install -m 600 /dev/null /etc/msmtprc
sudo tee /etc/msmtprc >/dev/null <<'EOF'
defaults
auth on
tls on
tls_starttls off
account forwardemail
host smtp.forwardemail.net
port 465
from noreply@tailnet.example
user noreply@tailnet.example
password the-generated-password
account default : forwardemail
EOF
printf 'Subject: msmtp test\n\nhello\n' | sudo msmtp you@tailnet.examplesudo tee /usr/local/bin/notify-failure.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
UNIT="$1"
{ echo "Subject: [devbox] ${UNIT} FAILED"; echo "To: you@tailnet.example"; echo;
echo "${UNIT} failed on $(hostname) at $(date)."; echo;
journalctl -u "$UNIT" -n 40 --no-pager; } | msmtp you@tailnet.example
EOF
sudo chmod 700 /usr/local/bin/notify-failure.sh
sudo tee /etc/systemd/system/notify-email@.service >/dev/null <<'EOF'
[Unit]
Description=Send failure email for %i
[Service]
Type=oneshot
ExecStart=/usr/local/bin/notify-failure.sh %i
EOF
sudo mkdir -p /etc/systemd/system/devbox-backup.service.d
sudo tee /etc/systemd/system/devbox-backup.service.d/onfailure.conf >/dev/null <<'EOF'
[Unit]
OnFailure=notify-email@%n.service
EOF
sudo systemctl daemon-reloadSeams
Where this meets the rest of the build. Each one leads with what you will actually see.
Symptomno configuration file available
The file holds the password, so it's root-only and a normal user can't read it. Test with sudo msmtp, which matches how the failure hook runs.
SymptomForgejo's test email can't resolve smtp.forwardemail.net
Forgejo runs on a bridge network and needs the pinned DNS in the host's daemon.json. See the Docker card.
Symptommail is refused before the provider has enabled outbound SMTP
Outbound SMTP is enabled per domain and can take up to a day to approve. Wait for it before testing anything else.
Verify
Point SFTP_REPO at a host that doesn't exist, run sudo systemctl start devbox-backup.service, and check the failure email arrives with the journal lines in it. Then put SFTP_REPO back.
- 17 Oct 2026First written.