Single Bash script that sends one notification through email, Telegram, or both. Designed to be dropped onto Linux servers and called from cron jobs, systemd units, or fail2ban actions.
sendnotify.sh è uno script Bash a file singolo che invia una notifica via email,
Telegram o entrambi. È pensato per essere installato su un server Linux (tipicamente in
/opt/bin/sendnotify.sh) e richiamato da cron, unità systemd o azioni fail2ban.
- Invio via email, Telegram o entrambi (
-t mail|telegram|both). - Body da argomento, da file (
-m/-f) o da stdin (-). - Espansione delle sequenze
\n,\t,\rnel body. - Footer automatico con hostname, IP non locale e data (disattivabile con
--no-footer). - Telegram in HTML con escaping, troncamento sicuro a 4000 byte, encoding UTF-8 corretto.
- Email con header
Content-Type: text/plain; charset=UTF-8. - Modalità
--dry-run(non invia, mostra cosa farebbe) e--debug(log dettagliati). - In modalità
both, se un solo canale fallisce, l'altro invia un avviso di fallimento parziale. - Exit code documentati per l'integrazione con altri sistemi.
| Componente | Quando serve | Pacchetto Debian/Ubuntu |
|---|---|---|
bash (4+) |
sempre | bash |
curl |
sempre (Telegram) | curl |
sed |
sempre | sed (in coreutils/base) |
hostname |
sempre | hostname |
mail |
invio email (-t mail/both) |
mailutils oppure bsd-mailx |
ip (o hostname -I) |
footer host/IP | iproute2 |
Installazione delle dipendenze:
sudo apt install curl mailutils iproute2L'invio email richiede un MTA funzionante (es. Postfix/exim) o uno smarthost configurato:
sudo install -m 0755 sendnotify.sh /opt/bin/sendnotify.shLa configurazione ha tre livelli, in ordine di priorità (dal più forte al più debole):
- Variabili d'ambiente
SENDNOTIFY_* - File di configurazione esterno (default
/opt/etc/sendnotify.conf) - Valori predefiniti in cima allo script
Il path del file di config è a sua volta sovrascrivibile con la variabile SENDNOTIFY_CONF.
| Variabile | Default | Descrizione |
|---|---|---|
SENDNOTIFY_TELEGRAM_TOKEN |
(placeholder) | Token del bot Telegram |
SENDNOTIFY_TELEGRAM_CHAT_ID |
(placeholder) | ID della chat di destinazione |
SENDNOTIFY_DEFAULT_TYPE |
both |
Canale di default: mail, telegram, both |
SENDNOTIFY_DEFAULT_TO |
user@domain.com |
Destinatario email |
SENDNOTIFY_DEFAULT_FROM |
notify@otherdomain.com |
Mittente email |
SENDNOTIFY_DEFAULT_SUBJECT |
Notify from <hostname> |
Oggetto di default |
SENDNOTIFY_TIMEOUT |
15 |
Timeout (s) delle chiamate curl |
SENDNOTIFY_LOCALE |
C.UTF-8 |
Locale forzato per output coerente |
SENDNOTIFY_CONF |
/opt/etc/sendnotify.conf |
Path del file di config esterno |
Crea /opt/etc/sendnotify.conf (è uno script shell sourceato: usa righe KEY="value"):
# /opt/etc/sendnotify.conf
SENDNOTIFY_TELEGRAM_TOKEN="123456789:AAExampleTokenReplaceMe"
SENDNOTIFY_TELEGRAM_CHAT_ID="123456789"
SENDNOTIFY_DEFAULT_TYPE="both"
SENDNOTIFY_DEFAULT_TO="user@domain.com"
SENDNOTIFY_DEFAULT_FROM="notify@otherdomain.com"sudo install -d -m 0755 /opt/etc
sudo chmod 600 /opt/etc/sendnotify.conf # contiene il token: proteggiloUn esempio pronto è incluso nel repository: sendnotify.conf.example.
1. Token del bot
- Su Telegram apri una chat con @BotFather.
- Invia
/newbote segui le istruzioni (nome e username del bot). - BotFather ti restituisce il token, nella forma
123456789:AA...— è il valore diSENDNOTIFY_TELEGRAM_TOKEN.
2. Chat ID
- Invia un messaggio qualsiasi al tuo bot (o aggiungilo al gruppo desiderato e scrivi un messaggio).
- Apri nel browser:
https://api.telegram.org/bot<TOKEN>/getUpdates - Cerca il campo
"chat":{"id":...}: quel numero è ilSENDNOTIFY_TELEGRAM_CHAT_ID.- Per le chat private è un numero positivo (in alternativa, @userinfobot ti dà il tuo id).
- Per i gruppi l'id è negativo (es.
-1001234567890).
Verifica veloce del token:
curl -s "https://api.telegram.org/bot<TOKEN>/getMe"
# {"ok":true,...} -> token valido
# {"ok":false,"error_code":404,...} -> token erratosendnotify.sh "Messaggio" # canale di default (both)
sendnotify.sh "Solo Telegram" -t telegram
sendnotify.sh -t mail --to user@domain.com -s "Oggetto" "Corpo del messaggio"
sendnotify.sh -m /percorso/body.txt -s "Report" -t mail
echo "corpo via pipe" | sendnotify.sh - -t telegram
sendnotify.sh "Anteprima" --dry-run --debug # mostra tutto, non invia nulla
sendnotify.sh "Senza footer" --no-footer
sendnotify.sh --help -m, --message FILE Body letto da FILE
-f, --file FILE Alias di --message
-s, --subject TESTO Oggetto
-t, --type TIPO mail | telegram | both
--to EMAIL Destinatario email
--from EMAIL Mittente email
--debug Log dettagliati (payload, URL, comandi) su stderr
--dry-run Non invia: mostra solo cosa farebbe
--no-footer Disattiva il footer host/IP/data
-v, --version Stampa la versione
-h, --help Mostra l'aiuto
Eseguito senza argomenti, lo script stampa l'aiuto.
| Codice | Significato |
|---|---|
0 |
almeno un canale ha inviato |
1 |
tutti i canali hanno fallito |
2 |
errore di configurazione (flag/email/tipo non validi, token placeholder) |
3 |
dipendenza mancante |
4 |
body assente |
fail2ban/sendnotify.conf è una action fail2ban (non una jail) che invoca lo script su
actionban/actionunban con -t telegram. Copiala in /etc/fail2ban/action.d/sendnotify.conf
e referenziala nelle tue jail (es. action = %(action_)s\n sendnotify). L'invio avviene in
background e non blocca fail2ban.
Note:
- Token e chat_id vanno nel file di config
/opt/etc/sendnotify.conf: fail2ban gira come root con ambiente minimale e non eredita le variabiliSENDNOTIFY_*della tua shell. - Il percorso dello script è il parametro
[Init]sendnotify_path(default/opt/bin/sendnotify.sh), sovrascrivibile dalla jail consendnotify[sendnotify_path="/percorso/sendnotify.sh"].
./tests/test-sendnotify.sh # tutti i test
./tests/test-sendnotify.sh telegram # solo i test che contengono "telegram"I test non inviano nulla (usano --dry-run o richiamano direttamente le funzioni).
sendnotify.sh is a single-file Bash script that sends one notification via email,
Telegram, or both. It is meant to be installed on a Linux server (typically at
/opt/bin/sendnotify.sh) and called from cron, systemd units, or fail2ban actions.
- Delivery via email, Telegram, or both (
-t mail|telegram|both). - Body from an argument, a file (
-m/-f), or stdin (-). - Expansion of
\n,\t,\rescape sequences in the body. - Automatic footer with hostname, non-local IP, and date (disable with
--no-footer). - Telegram in HTML with escaping, safe truncation at 4000 bytes, correct UTF-8 encoding.
- Email with
Content-Type: text/plain; charset=UTF-8header. --dry-run(does not send, shows what it would do) and--debug(verbose logs).- In
bothmode, if a single channel fails, the other one sends a partial-failure alert. - Documented exit codes for integration with other systems.
| Component | When needed | Debian/Ubuntu package |
|---|---|---|
bash (4+) |
always | bash |
curl |
always (Telegram) | curl |
sed |
always | sed (base/coreutils) |
hostname |
always | hostname |
mail |
email delivery (-t mail/both) |
mailutils or bsd-mailx |
ip (or hostname -I) |
host/IP footer | iproute2 |
Install the dependencies:
sudo apt install curl mailutils iproute2Email delivery requires a working MTA (e.g. Postfix/exim) or a configured smarthost:
sudo install -m 0755 sendnotify.sh /opt/bin/sendnotify.shConfiguration has three layers, in priority order (strongest to weakest):
- Environment variables
SENDNOTIFY_* - External configuration file (default
/opt/etc/sendnotify.conf) - Built-in defaults at the top of the script
The config file path itself can be overridden with the SENDNOTIFY_CONF variable.
| Variable | Default | Description |
|---|---|---|
SENDNOTIFY_TELEGRAM_TOKEN |
(placeholder) | Telegram bot token |
SENDNOTIFY_TELEGRAM_CHAT_ID |
(placeholder) | Target chat ID |
SENDNOTIFY_DEFAULT_TYPE |
both |
Default channel: mail, telegram, both |
SENDNOTIFY_DEFAULT_TO |
user@domain.com |
Email recipient |
SENDNOTIFY_DEFAULT_FROM |
notify@otherdomain.com |
Email sender |
SENDNOTIFY_DEFAULT_SUBJECT |
Notify from <hostname> |
Default subject |
SENDNOTIFY_TIMEOUT |
15 |
curl call timeout (s) |
SENDNOTIFY_LOCALE |
C.UTF-8 |
Forced locale for consistent output |
SENDNOTIFY_CONF |
/opt/etc/sendnotify.conf |
External config file path |
Create /opt/etc/sendnotify.conf (it is a sourced shell script: use KEY="value" lines):
# /opt/etc/sendnotify.conf
SENDNOTIFY_TELEGRAM_TOKEN="123456789:AAExampleTokenReplaceMe"
SENDNOTIFY_TELEGRAM_CHAT_ID="123456789"
SENDNOTIFY_DEFAULT_TYPE="both"
SENDNOTIFY_DEFAULT_TO="user@domain.com"
SENDNOTIFY_DEFAULT_FROM="notify@otherdomain.com"sudo install -d -m 0755 /opt/etc
sudo chmod 600 /opt/etc/sendnotify.conf # it holds the token: protect itA ready-made example is included in the repository: sendnotify.conf.example.
1. Bot token
- On Telegram, open a chat with @BotFather.
- Send
/newbotand follow the prompts (bot name and username). - BotFather returns the token in the form
123456789:AA...— this isSENDNOTIFY_TELEGRAM_TOKEN.
2. Chat ID
- Send any message to your bot (or add it to the target group and post a message).
- Open in a browser:
https://api.telegram.org/bot<TOKEN>/getUpdates - Look for
"chat":{"id":...}: that number isSENDNOTIFY_TELEGRAM_CHAT_ID.- For private chats it is positive (alternatively, @userinfobot gives your id).
- For groups the id is negative (e.g.
-1001234567890).
Quick token check:
curl -s "https://api.telegram.org/bot<TOKEN>/getMe"
# {"ok":true,...} -> valid token
# {"ok":false,"error_code":404,...} -> wrong tokensendnotify.sh "Message" # default channel (both)
sendnotify.sh "Telegram only" -t telegram
sendnotify.sh -t mail --to user@domain.com -s "Subject" "Message body"
sendnotify.sh -m /path/to/body.txt -s "Report" -t mail
echo "body via pipe" | sendnotify.sh - -t telegram
sendnotify.sh "Preview" --dry-run --debug # shows everything, sends nothing
sendnotify.sh "No footer" --no-footer
sendnotify.sh --help -m, --message FILE Body read from FILE
-f, --file FILE Alias of --message
-s, --subject TEXT Subject
-t, --type TYPE mail | telegram | both
--to EMAIL Email recipient
--from EMAIL Email sender
--debug Verbose logs (payload, URL, commands) to stderr
--dry-run Do not send: only show what it would do
--no-footer Disable the host/IP/date footer
-v, --version Print the version
-h, --help Show help
Run with no arguments, the script prints the help.
| Code | Meaning |
|---|---|
0 |
at least one channel sent |
1 |
all channels failed |
2 |
configuration error (invalid flag/email/type, placeholder token) |
3 |
missing dependency |
4 |
missing body |
fail2ban/sendnotify.conf is a fail2ban action (not a jail) that invokes the script on
actionban/actionunban with -t telegram. Copy it to /etc/fail2ban/action.d/sendnotify.conf
and reference it from your jails (e.g. action = %(action_)s\n sendnotify). Delivery runs in
the background and does not block fail2ban.
Notes:
- Token and chat_id must be set in the config file
/opt/etc/sendnotify.conf: fail2ban runs as root with a minimal environment and does not inherit your shell'sSENDNOTIFY_*variables. - The script path is the
[Init]parametersendnotify_path(default/opt/bin/sendnotify.sh), overridable from a jail withsendnotify[sendnotify_path="/path/to/sendnotify.sh"].
./tests/test-sendnotify.sh # all tests
./tests/test-sendnotify.sh telegram # only tests containing "telegram"Tests send nothing (they use --dry-run or call the functions directly).