I was slow to understand that it only sends messages in case of failure, so I set it to send in all cases.
Thank you for your help!
@bd8392 thanks for the instruction. Some additions:
apprise:
image: caronc/apprise:latest
container_name: apprise
ports:
- 8000:8000
volumes:
- /var/lib/apprise/config:/config
privileged: true
And you should grant the correct access rights for the config folder according to https://hub.docker.com/r/caronc/apprise
Welcome to the forum @aleksej.kuznecow and thanks for contributing the addition.
It’s wonderful to see the community helping to build what is truly a community effort.
good morning everyone, after working all day to make the script better for my needs I would like to share it with you, I created a script called “telegram.sh” and inserted it inside /opt/scripts which is mounted inside /script in the docker container (volumes: - /opt/duplicati/scripts:/scripts) then I ran sudo chmod +x ./telegram.sh to give execution permissions. Then I modified my backup in the Duplicati GUI and in the advanced options I selected “run-script-after” and in the text box I inserted the path of the sh file or “/scripts/telegram.sh”. You can change the text to your liking for your language in my case I am Italian and I will share it with the text in Italian but feel free to modify it, whoever decides to improve it would be a good thing if they shared it as I did so that it can help other people like you did it with me. Attached I leave the terminal.sh script:
#!/bin/bash
#
# Script Configuration.
DEBUG_MODE="0" # Impostalo su "1" per abilitare il debug
SCRIPT_FULLFN="$(basename "${0}")"
LOGFILE="/tmp/${SCRIPT_FULLFN%.*}.log"
LOG_MAX_LINES="1000"
SERVICE_NAME="Duplicati"
#
#
# -----------------
# --- Functions ---
# -----------------
logAdd ()
{
TMP_DATETIME="$(date '+%Y-%m-%d [%H-%M-%S]')"
TMP_LOGSTREAM="$(tail -n ${LOG_MAX_LINES} ${LOGFILE} 2>/dev/null)"
echo "${TMP_LOGSTREAM}" > "$LOGFILE"
if [ "$1" == "-q" ]; then
#
# Quiet mode.
#
echo "${TMP_DATETIME} ${@:2}" >> "${LOGFILE}"
else
#
# Loud mode.
#
echo "${TMP_DATETIME} $*" | tee -a "${LOGFILE}"
fi
return
}
sendTelegramNotification ()
{
#
# Usage: sendTelegramNotification "<PN_TEXT>"
# Example: sendTelegramNotification "Test push message"
#
# Returns:
#
# - "0" on FAILURE.
# - "1" on SUCCESS.
#
# Consts.
CURL_BIN="curl"
CURL_TIMEOUT="10"
#
# Telegram Bot
STN_TELEGRAM_BOT_ID="TO_FILL"
STN_TELEGRAM_BOT_APIKEY="TO_FILL"
#
# cf
STN_TELEGRAM_CHAT_ID="TO_FILL"
#
# Variables.
#
STN_TEXT="$1"
# Encode the text for URL
STN_TEXT=$(echo -n "$STN_TEXT" | sed 's/ /%20/g; s/\n/%0A/g; s/<b>/%3Cb%3E/g; s/<\/b>/%3C%2Fb%3E/g; s/<i>/%3Ci%3E/g; s/<\/i>/%3C%2Fi%3E/g')
#
# Log message.
#
if [ "${DEBUG_MODE}" == "1" ]; then
logAdd -q "${MY_SERVICE_NAME}::sendTelegramNotification() fired."
fi
CURL_COMMAND="${CURL_BIN} -s --max-time ${CURL_TIMEOUT} \"https://api.telegram.org/bot${STN_TELEGRAM_BOT_ID}:${STN_TELEGRAM_BOT_APIKEY}/sendMessage?chat_id=${STN_TELEGRAM_CHAT_ID}&parse_mode=HTML&text=${STN_TEXT}\""
# Log the CURL command for debugging
logAdd "[DEBUG] CURL command: ${CURL_COMMAND}"
RESPONSE=$(eval ${CURL_COMMAND})
logAdd "[DEBUG] CURL response: ${RESPONSE}"
if echo "${RESPONSE}" | grep -Fiq "\"ok\":true"; then
logAdd -q "${MY_SERVICE_NAME}::sendTelegramNotification: ... SUCCESS."
echo -n "1"
else
logAdd -q "${MY_SERVICE_NAME}::sendTelegramNotification: ... FAILED."
echo -n "0"
fi
return
}
# -----------------------------------------------------
# --------------- END OF FUNCTION BLOCK ---------------
# -----------------------------------------------------
#
# Script Main.
#
# Validate env vars we got from Duplicati.
if [ -z "${DUPLICATI__backup_name}" ]; then
export DUPLICATI__backup_name="API_ERR"
fi
#
if [ -z "${DUPLICATI__PARSED_RESULT}" ]; then
export DUPLICATI__PARSED_RESULT="API_ERR"
fi
#
if [ -z "${DUPLICATI__EVENTNAME}" ]; then
export DUPLICATI__EVENTNAME="API_ERR"
fi
#
if [ -z "${DUPLICATI__OPERATIONNAME}" ]; then
export DUPLICATI__OPERATIONNAME="API_ERR"
fi
#
if [ "${DEBUG_MODE}" == "1" ]; then
env | grep "DUPLICATI__"
fi
#
# Prepare chat message.
if [ "${DUPLICATI__PARSED_RESULT}" == "Success" ]; then
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A✅ Il backup è stato completato con successo alle ore $(date '+%H:%M')."
elif [ "${DUPLICATI__PARSED_RESULT}" == "Warning" ]; then
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A⚠️ Attenzione: Il backup ha completato con avvisi alle ore $(date '+%H:%M'). Verifica i log per ulteriori dettagli."
elif [ "${DUPLICATI__PARSED_RESULT}" == "Error" ]; then
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A❌ Errore: Il backup non è riuscito alle ore $(date '+%H:%M'). Controlla i log per identificare il problema."
elif [ "${DUPLICATI__PARSED_RESULT}" == "Fatal" ]; then
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A💥 Errore grave: Il backup è fallito irreparabilmente alle ore $(date '+%H:%M'). Intervieni subito per risolvere il problema!"
elif [ "${DUPLICATI__PARSED_RESULT}" == "Unknown" ]; then
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A🤔 Stato sconosciuto: Non è stato possibile determinare il risultato del backup alle ore $(date '+%H:%M'). Verifica manualmente."
fi
#
# Always send chat message.
logAdd "[INFO] Sending chat message [${CHAT_MESSAGE}] ..."
#
# Send chat message.
SEND_RESULT="$(sendTelegramNotification "${CHAT_MESSAGE}")"
if [ "${SEND_RESULT}" == "0" ]; then
logAdd "[ERROR] Failed to send telegram notification."
exit 99
fi
#
logAdd "[INFO] Successfully sent telegram notification."
exit 0
Great Work,Your script worked after some corrections.
For all those who are not fluent in Italian here is English version.
#!/bin/bash
#
# Script Configuration.
DEBUG_MODE="0" # Set to "1" to enable debugging
SCRIPT_FULLFN="$(basename "${0}")"
LOGFILE="/tmp/${SCRIPT_FULLFN%.*}.log"
LOG_MAX_LINES="1000"
SERVICE_NAME="Duplicati"
#
# -----------------
# --- Functions ---
# -----------------
logAdd ()
{
TMP_DATETIME="$(date '+%Y-%m-%d [%H-%M-%S]')"
TMP_LOGSTREAM="$(tail -n ${LOG_MAX_LINES} ${LOGFILE} 2>/dev/null)"
echo "${TMP_LOGSTREAM}" > "$LOGFILE"
if [ "$1" == "-q" ]; then
#
# Quiet mode.
#
echo "${TMP_DATETIME} ${@:2}" >> "${LOGFILE}"
else
#
# Loud mode.
#
echo "${TMP_DATETIME} $*" | tee -a "${LOGFILE}"
fi
return
}
sendTelegramNotification ()
{
#
# Usage: sendTelegramNotification "<MESSAGE_TEXT>"
# Example: sendTelegramNotification "Test push message"
#
# Returns:
#
# - "0" on FAILURE.
# - "1" on SUCCESS.
#
# Constants.
CURL_BIN="curl"
CURL_TIMEOUT="10"
#
# Telegram Bot
STN_TELEGRAM_BOT_ID="56834254534" # Replace with your bot ID Token Example - 56834254534:AAEBVSefdisfndi45345ifndis
STN_TELEGRAM_BOT_APIKEY="AAEBVSefdisfndi45345ifndis" # Replace with your bot API key
#
# Chat ID
STN_TELEGRAM_CHAT_ID="434346356" # Replace with your chat ID
#
# Variables.
#
STN_TEXT="$1"
# Encode the text for URL
STN_TEXT=$(echo -n "$STN_TEXT" | sed 's/ /%20/g; s/\n/%0A/g; s/<b>/%3Cb%3E/g; s/<\/b>/%3C%2Fb%3E/g; s/<i>/%3Ci%3E/g; s/<\/i>/%3C%2Fi%3E/g')
#
# Log message.
#
if [ "${DEBUG_MODE}" == "1" ]; then
logAdd -q "${SERVICE_NAME}::sendTelegramNotification() fired."
fi
CURL_COMMAND="${CURL_BIN} -s --max-time ${CURL_TIMEOUT} \"https://api.telegram.org/bot${STN_TELEGRAM_BOT_ID}:${STN_TELEGRAM_BOT_APIKEY}/sendMessage?chat_id=${STN_TELEGRAM_CHAT_ID}&parse_mode=HTML&text=${STN_TEXT}\""
# Log the CURL command for debugging
logAdd "[DEBUG] CURL command: ${CURL_COMMAND}"
RESPONSE=$(eval ${CURL_COMMAND})
logAdd "[DEBUG] CURL response: ${RESPONSE}"
if echo "${RESPONSE}" | grep -Fiq "\"ok\":true"; then
logAdd -q "${SERVICE_NAME}::sendTelegramNotification: ... SUCCESS."
echo -n "1"
else
logAdd -q "${SERVICE_NAME}::sendTelegramNotification: ... FAILED."
echo -n "0"
fi
return
}
# -----------------------------------------------------
# --------------- END OF FUNCTION BLOCK ---------------
# -----------------------------------------------------
#
# Script Main.
#
# Validate environment variables from Duplicati.
if [ -z "${DUPLICATI__backup_name}" ]; then
export DUPLICATI__backup_name="API_ERR"
fi
#
if [ -z "${DUPLICATI__PARSED_RESULT}" ]; then
export DUPLICATI__PARSED_RESULT="API_ERR"
fi
#
if [ -z "${DUPLICATI__EVENTNAME}" ]; then
export DUPLICATI__EVENTNAME="API_ERR"
fi
#
if [ -z "${DUPLICATI__OPERATIONNAME}" ]; then
export DUPLICATI__OPERATIONNAME="API_ERR"
fi
#
if [ "${DEBUG_MODE}" == "1" ]; then
env | grep "DUPLICATI__"
fi
#
# Prepare chat message.
case "${DUPLICATI__PARSED_RESULT}" in
"Success")
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A✅ The backup completed successfully at $(date '+%H:%M')."
;;
"Warning")
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A⚠️ Warning: The backup completed with warnings at $(date '+%H:%M'). Check the logs for more details."
;;
"Error")
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A❌ Error: The backup failed at $(date '+%H:%M'). Check the logs to identify the problem."
;;
"Fatal")
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A💥 Fatal Error: The backup failed irreparably at $(date '+%H:%M'). Take immediate action to resolve the issue!"
;;
"Unknown")
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A🤔 Unknown Status: The result of the backup could not be determined at $(date '+%H:%M'). Check manually."
;;
*)
CHAT_MESSAGE="<b>${SERVICE_NAME}</b>%0A<i>💾 ${DUPLICATI__backup_name}</i>%0A%0A❓ Unknown result at $(date '+%H:%M')."
;;
esac
#
# Always send chat message.
logAdd "[INFO] Sending chat message [${CHAT_MESSAGE}] ..."
#
# Send chat message.
SEND_RESULT="$(sendTelegramNotification "${CHAT_MESSAGE}")"
if [ "${SEND_RESULT}" == "0" ]; then
logAdd "[ERROR] Failed to send Telegram notification."
exit 99
fi
#
logAdd "[INFO] Successfully sent Telegram notification."
exit 0
Based on the script here I have implemented a Telegram reporting module.
It does not do the prettified HTML formatting, but that could be added.
Thanks @kenkendk for adding this! Working great.
For me there are two things that could be improved.
-
Telegram Messages on failing
run-script-before-required
Scripts. I guess that would be part of this Pull Request, that is currently marked as draft: Changed logic so all modules are loaded before any are started #5245. -
Option to send Messages to dedicated threads/topics. I think this would be a rather simple addition as it is one optional parameter more. I unfortunately don’t have the time for a Pull-Request but it should be something like this in SendTelegramMessage.cs + some Command-Line Parameter Updates.
...
var p = new
{
chat_id = Uri.EscapeDataString(m_channelId),
+ message_thread_id = string.IsNullOrEmpty(topicId) ? null : Uri.EscapeDataString(topicId)
parse_mode = "Markdown",
text = Uri.EscapeDataString(totalParts > 1
? $"Part {partNumber}/{totalParts}:\n{message}"
: message),
botId = Uri.EscapeDataString(m_botid),
apiKey = Uri.EscapeDataString(m_apikey)
};
var url = $"https://api.telegram.org/bot{p.botId}:{p.apiKey}/sendMessage?chat_id={p.chat_id}&parse_mode={p.parse_mode}&text={p.text}";
+ // Append message_thread_id only if it is not null or empty
+ if (!string.IsNullOrEmpty(p.message_thread_id))
+ {
+ url += $"&message_thread_id={p.message_thread_id}";
+ }
...
Thanks for suggesting it.
I have created an issue requesting improved Telegram support.
Hi @BoThomas FYI: I’ve implemented the suggestion on this PR: Added support for Topic ID on Telegram by marceloduplicati · Pull Request #5939 · duplicati/duplicati · GitHub