Configuration
fail2ban email notifications: setup and troubleshooting
Get an email (or a Telegram or Discord message) when fail2ban bans an IP. This page covers the built-in mail actions, sending through an external SMTP server, silencing the start/stop emails, and what to check when no mail arrives.
To get fail2ban ban alerts by email, set destemail, sender and action = %(action_mw)s in the [DEFAULT] section of /etc/fail2ban/jail.local, and make sure the server can send mail through /usr/sbin/sendmail (Postfix, or msmtp for an external SMTP server). action_mw bans and emails a whois report; action_mwl also includes the matching log lines. The default action_ only bans, so no mail is sent.
[DEFAULT]
destemail = admin@example.com ; who receives the alerts
sender = fail2ban@example.com ; From: address
mta = sendmail ; use /usr/sbin/sendmail (default)
action = %(action_mw)s ; ban + email with whoissudo fail2ban-client -t && sudo fail2ban-client reloadThe defaults are destemail = root@localhost and sender = root@<fq-hostname>. Mail to root@localhost stays on the server, and a sender like root@vps123.localdomain is rejected by real mail servers or lands in spam, so always set both. sendername (default Fail2Ban) sets the display name.
The email action shortcuts#
jail.conf defines three ready-made combinations. They all ban with your banaction first.
| Shortcut | Ban | Email contains | |
|---|---|---|---|
%(action_)s |
yes | no | — (the default) |
%(action_mw)s |
yes | yes | IP, jail, number of failures, whois of the IP |
%(action_mwl)s |
yes | yes | Same plus the log lines containing the IP |
Behind the scenes action_mw expands to %(action_)s plus %(mta)s-whois[sender=…, dest=…], so with mta = sendmail it uses the sendmail-whois action and action_mwl uses sendmail-whois-lines (see the action list). The whois part needs the whois command (sudo apt install whois / sudo dnf install whois); without it the mail body says missing whois program.
You can enable email for one jail only. A jail with its own action = line (for example one using Cloudflare) ignores the [DEFAULT] value, so add the mail action there too:
[DEFAULT]
destemail = admin@example.com
sender = fail2ban@example.com
[sshd]
enabled = true
action = %(action_mwl)sJails reading the systemd journal#
action_mwl greps the jail's logpath for the IP. A jail with backend = systemd has no log file, so the "lines containing failures" section stays empty. Use sendmail-whois-matches instead, which sends the lines fail2ban matched in memory:
[sshd]
enabled = true
backend = systemd
action = %(action_)s
sendmail-whois-matches[sender="%(sender)s", dest="%(destemail)s"]sendmail vs mail (the mta option)#
mta = |
Actions used | Sends with |
|---|---|---|
sendmail (default) |
sendmail-whois, sendmail-whois-lines |
/usr/sbin/sendmail -f "<sender>" "<dest>" |
mail |
mail-whois, mail-whois-lines |
the mail command (mailutils / s-nail / bsd-mailx) |
Keep sendmail. "sendmail" here means the standard /usr/sbin/sendmail interface, which Postfix, Exim, msmtp-mta and ssmtp all provide; you don't need the actual Sendmail server. The mail-whois actions call mail -E 'set escape' -s …, options that not every mail implementation accepts.
Send through Gmail or another SMTP server with msmtp#
A fresh VPS usually has no mail software. You can install a full MTA (sudo apt install postfix, choose "Internet Site" or "Satellite system"; or exim4; sudo dnf install postfix on RHEL-family systems), but most providers block outgoing port 25, so Postfix accepts the message and still can't deliver it, and direct mail from a VPS often lands in spam. For alerts, relay through a real mailbox on port 587 instead. msmtp is a small SMTP client that installs a sendmail replacement:
sudo apt install msmtp msmtp-mtasudo dnf install msmtp
sudo ln -s /usr/bin/msmtp /usr/sbin/sendmail # only if no MTA provides it yetdefaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log
account default
host smtp.example.com
port 587
from fail2ban@example.com
user fail2ban@example.com
password YOUR_APP_PASSWORDsudo chmod 600 /etc/msmtprcOn RHEL-family systems the CA bundle is /etc/pki/tls/certs/ca-bundle.crt. For Gmail use host smtp.gmail.com with an app password (2-step verification must be on). fail2ban runs as root, so it uses this system-wide, root-owned file. Keep sender in jail.local the same as from and user here, because most providers reject mail whose sender doesn't match the authenticated account. ssmtp works the same way but is unmaintained; prefer msmtp.
Python SMTP action (smtp.py)#
fail2ban also ships action.d/smtp.py, which talks to an SMTP server directly, without any local mail software:
[sshd]
enabled = true
action = %(action_)s
smtp.py[host="smtp.example.com:587", ssl=true, user="fail2ban@example.com", password="YOUR_APP_PASSWORD", sender="fail2ban@example.com", dest="admin@example.com", matches="matches"]hostmust include the port (host:port).ssl=trueenables STARTTLS (port 587). Any value counts as on, so remove the parameter instead of writingssl=false. Implicit TLS on port 465 isn't supported.matchescan bematches,ipmatchesoripjailmatchesto include log lines.- The password ends up in
jail.local, sochmod 600it.
Stop the "jail started / stopped" emails#
The sendmail actions send a mail every time a jail starts or stops, so a server with ten jails sends twenty emails per restart. Turn them off with a .local override for the shared start/stop definitions:
[Definition]
actionstart =
actionstop =This silences start/stop mails for all sendmail-* actions and keeps the ban mails. If you use mta = mail, create action.d/mail-whois.local (and mail-whois-lines.local) with the same two empty lines.
Restored bans don't trigger mails: after a restart, fail2ban re-applies saved bans without re-sending notifications (the mail actions set norestored = 1).
Disable fail2ban email notifications completely#
Set the action back to ban-only and reload:
[DEFAULT]
action = %(action_)sThen check that no jail or jail.d/ file sets its own action: grep -rn "action" /etc/fail2ban/jail.local /etc/fail2ban/jail.d/.
Telegram, Discord, Slack and more with Apprise#
fail2ban ships an apprise action that hands notifications to Apprise, which supports Telegram, Discord, Slack, Matrix, ntfy, email and many more.
sudo apt install apprise # or: sudo pip install apprisetgram://123456789:BOT_TOKEN/987654321
discord://WEBHOOK_ID/WEBHOOK_TOKEN[DEFAULT]
action = %(action_)s
apprise[config="/etc/fail2ban/apprise.conf"]Each URL is one notification target; check the Apprise documentation for the exact format of your service. Test Apprise on its own first: apprise -c /etc/fail2ban/apprise.conf -b "test from fail2ban". Like the mail actions, apprise also notifies on jail start/stop; empty actionstart/actionstop in action.d/apprise.local to silence that.
For a plain webhook without Apprise (ntfy, Slack incoming webhook, your own API), write a small action with curl. Examples are in writing a custom action.
Test your alerts#
Test the mail system on its own first, then through fail2ban. Manual bans run every action of the jail, including mail:
printf 'To: admin@example.com\nSubject: MTA test\n\nhello\n' | sudo /usr/sbin/sendmail -t -f fail2ban@example.com$ sudo fail2ban-client set sshd banip 192.0.2.15 192.0.2.16
2sudo fail2ban-client set sshd unbanip 192.0.2.15 192.0.2.16You should get a "banned 192.0.2.15" email within a minute. If the first test arrives and the ban mail doesn't, the problem is the jail's action or addresses. If neither arrives, it's the MTA or relay.
Email alerts not sending? Troubleshooting#
Email alerts need three things to line up: a jail action that sends mail, a working sendmail command, and addresses your relay accepts. Check them in that order:
sudo fail2ban-client get sshd actions # is a mail action attached?
ls -l /usr/sbin/sendmail # is there an MTA?
sudo fail2ban-client -d | grep -i "dest\|sender" # which addresses are used?
sudo grep -E "returned|stderr|ERROR" /var/log/fail2ban.log | tailIf the jail never bans anyone in the first place, no mail can follow: fix that first with fail2ban not banning.
The jail's action doesn't send mail#
A jail that sends mail lists two actions. If you see only the firewall action, the jail never tries to send mail:
$ sudo fail2ban-client get sshd actions
The jail sshd has the following actions:
nftablesSet action = %(action_mw)s or %(action_mwl)s in [DEFAULT] or in the jail, then sudo fail2ban-client -t && sudo fail2ban-client reload. The list should now include sendmail-whois (or sendmail-whois-lines). Remember that jail-level action = lines override [DEFAULT].
sendmail: not found (returned 127)#
With mta = sendmail, the action runs /usr/sbin/sendmail. Without any mail software, fail2ban's log shows:
... -- stderr: '/bin/sh: 1: /usr/sbin/sendmail: not found'
... -- returned 127Install something that provides /usr/sbin/sendmail: msmtp with msmtp-mta (setup above), Postfix or Exim. Other returned 127 errors are covered on config errors.
The relay rejects the sender or recipient#
The message leaves fail2ban but never arrives. Check the MTA's log, not fail2ban's, for the rejection reason: /var/log/mail.log, journalctl -u postfix, or /var/log/msmtp.log. Typical causes are the default root@<fq-hostname> sender, a sender that doesn't match the authenticated SMTP account, or outbound port 25 blocked by the provider. Mail to the default root@localhost ends up in /var/mail/root.
whois or log lines missing from the email#
- The body says
missing whois program: installwhois. action_mwlsends an empty log-lines section: the jail usesbackend = systemd, so switch tosendmail-whois-matchesas shown above.
FAQ#
How do I set up email notifications in fail2ban?#
In /etc/fail2ban/jail.local under [DEFAULT], set destemail (recipient), sender (From address) and action = %(action_mw)s, or %(action_mwl)s to include log lines. Install a working /usr/sbin/sendmail (Postfix, or msmtp with msmtp-mta for an external SMTP server) and run sudo fail2ban-client reload.
Why is fail2ban not sending email?#
Usually the jail still uses the default action = %(action_)s, which only bans. Set action = %(action_mw)s and real destemail and sender addresses. If it still fails, check that /usr/sbin/sendmail exists, look for returned 127 in /var/log/fail2ban.log, and read the MTA's log for relay rejections.
What is the difference between action_mw and action_mwl?#
Both ban the IP and send an email with a whois report. action_mwl adds the log lines containing the banned IP, grepped from the jail's logpath. For journal-based jails that section is empty; use sendmail-whois-matches, which includes the lines fail2ban matched.
Does fail2ban need sendmail installed?#
Only for email alerts. With the default mta = sendmail, fail2ban pipes messages into /usr/sbin/sendmail, which Postfix, Exim, msmtp-mta and similar packages provide. Banning itself works without any mail software, and the smtp.py action can send without a local MTA.
How do I disable fail2ban email notifications?#
Set action = %(action_)s under [DEFAULT] in jail.local (and remove any jail-specific action lines that use mail), then reload. To keep ban emails but stop the start/stop messages, create action.d/sendmail-common.local with empty actionstart = and actionstop = under [Definition].
Can fail2ban send notifications to Telegram or Discord?#
Yes. Use the apprise action that ships with fail2ban, list your Telegram or Discord URLs in an Apprise config file, and add apprise[config="/etc/fail2ban/apprise.conf"] as a second line of action. Alternatively, write a custom action that calls the service's webhook with curl.
Spotted something wrong or out of date? Tell us — every page is checked against the current fail2ban release.