# fail2ban email notifications: setup and troubleshooting

> Set up fail2ban email alerts with action_mw or action_mwl, send via any SMTP server with msmtp, stop start/stop mails, and fix alerts that are not sending.
>
> Source: https://fail2ban.dev/config/email-alerts/ · Updated 2026-10-26 · Checked against fail2ban 1.1.1
> fail2ban.dev is an independent guide, not the official fail2ban project.

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.

```ini
[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 whois
```
sudo fail2ban-client -t && sudo fail2ban-client reload
```

## The email action shortcuts

`jail.conf` defines three ready-made combinations. They all ban with your [`banaction`](/config/banaction/) first.

| Shortcut | Ban | Email | 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](/actions/)). 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:

```ini
[DEFAULT]
destemail = admin@example.com
sender    = fail2ban@example.com

[sshd]
enabled = true
action  = %(action_mwl)s
```

`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:

```ini
enabled = true
backend = systemd
action  = %(action_)s
          sendmail-whois-matches[sender="%(sender)s", dest="%(destemail)s"]
```

| `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:


#### Ubuntu / Debian
```bash
```
```bash
sudo ln -s /usr/bin/msmtp /usr/sbin/sendmail   # only if no MTA provides it yet
```
defaults
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_PASSWORD
```
sudo chmod 600 /etc/msmtprc
```

## Python SMTP action (smtp.py)

fail2ban also ships `action.d/smtp.py`, which talks to an SMTP server directly, without any local mail software:

```ini
[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"]
```
- `ssl=true` enables STARTTLS (port 587). Any value counts as on, so remove the parameter instead of writing `ssl=false`. Implicit TLS on port 465 isn't supported.
- `matches` can be `matches`, `ipmatches` or `ipjailmatches` to include log lines.
- The password ends up in `jail.local`, so `chmod 600` it.

## 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:

```ini
[Definition]
actionstart =
actionstop =
```

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:

```ini
[DEFAULT]
action = %(action_)s
```

## Telegram, Discord, Slack and more with Apprise

fail2ban ships an `apprise` action that hands notifications to [Apprise](https://github.com/caronc/apprise), which supports Telegram, Discord, Slack, Matrix, ntfy, email and many more.

```bash
```
tgram://123456789:BOT_TOKEN/987654321
discord://WEBHOOK_ID/WEBHOOK_TOKEN
```
[DEFAULT]
action = %(action_)s
         apprise[config="/etc/fail2ban/apprise.conf"]
```

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](/actions/custom/).

## Test your alerts

Test the mail system on its own first, then through fail2ban. Manual bans run every action of the jail, including mail:

```bash
```
$ sudo fail2ban-client set sshd banip 192.0.2.15 192.0.2.16
2
```
sudo fail2ban-client set sshd unbanip 192.0.2.15 192.0.2.16
```

## 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:

```bash
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 | tail
```

### 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:

```text
$ sudo fail2ban-client get sshd actions
The jail sshd has the following actions:
nftables
```

### sendmail: not found (returned 127)

With `mta = sendmail`, the action runs `/usr/sbin/sendmail`. Without any mail software, [fail2ban's log](/logs/) shows:

```text
... -- returned 127
```

### 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`: install `whois`.
- `action_mwl` sends an empty log-lines section: the jail uses `backend = systemd`, so switch to `sendmail-whois-matches` as shown [above](#jails-reading-the-systemd-journal).

## 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`.
