📘 Handleiding: Dead Man’s Switch met Python, Gmail & Telegram
Met deze handleiding zet je een Dead Man’s Switch op: een systeem dat automatisch e-mails verstuurt als je een bepaalde tijd niet meer reageert. Dit werkt met een Python-script, Gmail SMTP en een Telegram-bot.
Hoe werkt het?
- Het script draait op een Linux-server.
- Via een Telegram-bot moet ik regelmatig bevestigen dat ik nog actief ben.
- Doe ik dit niet → eerst een waarschuwing via Telegram daarna via e-mail.
- Reageer ik nog steeds niet → dan worden mijn vooraf ingestelde berichten automatisch gemaild naar de ontvangers die ik heb ingesteld.
Waarom handig?
- Je kunt hiermee belangrijke informatie, berichten of instructies automatisch doorgeven als jou iets overkomt.
- Denk bijvoorbeeld aan: persoonlijke boodschappen, digitale accounts of toegangsinformatie die veilig bij iemand terecht moet komen.

🔹 Stap 1. Server voorbereiden
Log in op je Linux server (bijv. Contabo, Ubuntu/Debian):
ssh user@jouwserverip
Werk je systeem bij:
sudo apt update && sudo apt upgrade -y
Installeer Python en pip:
sudo apt install -y python3 python3-pip python3-venv git
🔹 Stap 2. Telegram Bot aanmaken
- Open Telegram en zoek naar @BotFather.
- Typ
/newbot
en volg de instructies.- Kies een naam → bv.
MijnDeadmanBot
- Kies een gebruikersnaam die eindigt op
bot
→ bv.mijndeadman_bot
- Kies een naam → bv.
- Je krijgt een API Token, bijvoorbeeld:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Chat ID achterhalen
- Stuur een bericht naar je bot (bijv.
Hallo
). - Ga naar je browser en open:
https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates
- In de JSON-output zie je
"chat":{"id":123456789}
→ dat is je CHAT ID.
🔹 Stap 3. Gmail App Password aanmaken
- Ga naar https://myaccount.google.com/
- Zet 2-stapsverificatie aan (Beveiliging → Inloggen bij Google).
- Klik op App-wachtwoorden.
- Kies “Mail” + “Ander apparaat” → geef bv. de naam
DeadmanSwitch
. - Je krijgt een 16-cijferig wachtwoord.
👉 Dit gebruik je als EMAIL_PASS.
🔹 Stap 4. Scriptmap maken
Maak een map aan en ga erin:
mkdir ~/deadmanswitch
cd ~/deadmanswitch
Plaats hier:
deadmanswitch.py
(zie onderaan deze handleiding).env
bestand- map
messages/
🔹 Stap 5. .env
bestand
Maak een .env
bestand met je gegevens:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
TELEGRAM_CHAT_ID=123456789
EMAIL_USER=jouweigenemail@gmail.com
EMAIL_PASS=xxxxxxxxxxxxxxxx
MY_EMAIL=jouweigenemail@gmail.com
🔹 Stap 6. Python omgeving + pakketten
Maak een virtuele omgeving en installeer de benodigde pakketten:
python3 -m venv venv
source venv/bin/activate
pip install python-telegram-bot python-dotenv
🔹 Stap 7. Berichten aanmaken
Maak een map:
mkdir messages
📂 Structuur van een berichtbestand
- Eerste regel = ontvangers (meerdere mogelijk, gescheiden door komma’s).
- Tweede regel = onderwerp van de mail (
Onderwerp:
ofSubject:
). - Derde regel en verder = het bericht (meerdere regels toegestaan).
Voorbeeld 1 – één ontvanger
messages/bericht1.txt
mijnadres@gmail.com
Onderwerp: TEST – Dead Man’s Switch
Hallo,
Dit is een testbericht.
Voorbeeld 2 – meerdere ontvangers
messages/bericht2.txt
vriend1@example.com, vriend2@example.com, vriend3@example.com
Onderwerp: Belangrijk bericht
Hallo allemaal,
Dit bericht gaat naar meerdere ontvangers tegelijk.
Voorbeeld 3 – meerdere bestanden
messages/
├─ bericht1.txt
├─ bericht2.txt
├─ bericht3.txt
👉 Elk bestand wordt als apart bericht verstuurd bij de finale trigger.
⚠️ Belangrijk: eerst testen
💡 Test altijd eerst met je eigen e-mailadres.
- Maak een bestand in
messages/
met alleen jouw adres. - Controleer of je het bericht ontvangt.
- Pas daarna vul je de echte ontvangers in.
🔹 Stap 8. Script starten
Activeer de virtuele omgeving en start het script:
source venv/bin/activate
python3 deadmanswitch.py
Telegram commando’s
/status
→ toont volgende controle/reset
→ reset timer/setcheck 1d
→ check-interval instellen (bv. 1 dag)/setwarning 3d
→ waarschuwing via mail na 3 dagen/setfinal 7d
→ finale e-mail na 7 dagen
🔹 Stap 9. Automatisch starten na reboot
Maak een systemd service:
sudo nano /etc/systemd/system/deadmanswitch.service
Inhoud:
[Unit]
Description=Dead Man's Switch
After=network.target
[Service]
User=USERNAME
WorkingDirectory=/home/USERNAME/deadmanswitch
ExecStart=/home/USERNAME/deadmanswitch/venv/bin/python3 /home/USERNAME/deadmanswitch/deadmanswitch.py
Restart=always
StandardOutput=append:/home/USERNAME/deadmanswitch/deadmanswitch.log
StandardError=append:/home/USERNAME/deadmanswitch/deadmanswitch.log
[Install]
WantedBy=multi-user.target
➡️ Vervang USERNAME
door je servergebruikersnaam.
Opslaan en afsluiten.
Service activeren:
sudo systemctl daemon-reload
sudo systemctl enable deadmanswitch
sudo systemctl start deadmanswitch
Status bekijken:
sudo systemctl status deadmanswitch
🔹 Stap 10. Logs bekijken
Het script logt naar:
deadmanswitch.log
Bekijk live:
tail -f ~/deadmanswitch/deadmanswitch.log
🐍 Laatste versie deadmanswitch.py
import os
import time
import smtplib
import logging
import telegram
from dotenv import load_dotenv
from email.mime.text import MIMEText
from telegram import Update
from telegram.ext import Application, CommandHandler, CallbackContext
import threading
import sys
import asyncio
import glob
# Logging instellen
logging.basicConfig(
filename="deadmanswitch.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
logging.getLogger("telegram").setLevel(logging.WARNING)
load_dotenv()
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_USER = os.getenv("EMAIL_USER")
EMAIL_PASS = os.getenv("EMAIL_PASS")
MY_EMAIL = os.getenv("MY_EMAIL")
FINAL_MAIL_FLAG = "final_mail_sent.txt"
MESSAGES_DIR = "messages"
bot = telegram.Bot(token=TELEGRAM_BOT_TOKEN)
last_response_time = time.time()
check_interval = 7 * 86400
warning_interval = 14 * 86400
final_interval = 21 * 86400
lock = threading.Lock()
check_sent = False
warning_sent = False
final_sent = False
loop = asyncio.new_event_loop()
def send_telegram_message(message):
async def async_send_message():
try:
await bot.send_message(chat_id=TELEGRAM_CHAT_ID, text=message)
except Exception as e:
logging.error(f"Fout bij verzenden Telegram bericht: {e}")
asyncio.run_coroutine_threadsafe(async_send_message(), loop)
def send_email(subject, body, recipients):
msg = MIMEText(body, "plain")
msg["Subject"] = subject
msg["From"] = EMAIL_USER
msg["To"] = ", ".join(recipients)
try:
with smtplib.SMTP(EMAIL_HOST, EMAIL_PORT) as server:
server.starttls()
server.login(EMAIL_USER, EMAIL_PASS)
server.sendmail(EMAIL_USER, recipients, msg.as_string())
except Exception as e:
logging.error(f"Fout bij verzenden e-mail: {e}")
def load_messages_from_files():
messages = []
try:
for file_path in glob.glob(f"{MESSAGES_DIR}/*.txt"):
with open(file_path, "r", encoding="utf-8") as f:
lines = f.read().splitlines()
if len(lines) < 3:
continue
recipients = [r.strip() for r in lines[0].split(",") if r.strip()]
subject_line = lines[1].strip()
if subject_line.lower().startswith("onderwerp:"):
subject = subject_line[len("onderwerp:"):].strip()
elif subject_line.lower().startswith("subject:"):
subject = subject_line[len("subject:"):].strip()
else:
subject = "Een laatste brief"
message = "\n".join(lines[2:]).strip()
if recipients and message:
messages.append((recipients, subject, message))
return messages
except Exception as e:
logging.error(f"Fout bij inlezen berichten: {e}")
return []
def send_warning_mail():
send_email("⚠️ Waarschuwing: Controle vereist",
"Er is al een tijd geen activiteit geweest. Reageer om de dead man's switch te resetten.",
[MY_EMAIL])
def send_final_mail():
global final_sent
if os.path.exists(FINAL_MAIL_FLAG):
sys.exit(0)
messages = load_messages_from_files()
if not messages:
return
for recipients, subject, message in messages:
send_email(subject, message, recipients)
open(FINAL_MAIL_FLAG, "w").write("sent")
final_sent = True
sys.exit(0)
async def set_interval(update: Update, context: CallbackContext, interval_type):
global check_interval, warning_interval, final_interval
try:
input_value = context.args[0]
if input_value.endswith("d"):
new_interval = float(input_value[:-1]) * 86400
elif input_value.endswith("h"):
new_interval = float(input_value[:-1]) * 3600
elif input_value.endswith("m"):
new_interval = float(input_value[:-1]) * 60
else:
new_interval = float(input_value) * 86400
with lock:
if interval_type == "check":
check_interval = new_interval
elif interval_type == "warning":
warning_interval = new_interval
elif interval_type == "final":
final_interval = new_interval
await update.message.reply_text(f"{interval_type.capitalize()} interval ingesteld op {input_value}.")
except:
await update.message.reply_text(f"Gebruik: /set{interval_type} <tijd> (bijv. '1d', '2h', '30m')")
async def reset_timer(update: Update, context: CallbackContext):
global last_response_time, check_sent, warning_sent, final_sent
with lock:
last_response_time = time.time()
check_sent = False
warning_sent = False
final_sent = False
await update.message.reply_text("✅ Timer gereset.")
async def show_status(update: Update, context: CallbackContext):
with lock:
next_check = time.strftime('%d-%m-%Y %H:%M:%S', time.localtime(last_response_time + check_interval))
await update.message.reply_text(f"Volgende controle: {next_check}")
async def show_help(update: Update, context: CallbackContext):
help_text = """
📌 Commando's:
/status - Volgende controle
/setcheck <tijd> - Check-interval
/setwarning <tijd> - Waarschuwingstijd
/setfinal <tijd> - Finale e-mail tijd
/reset - Reset timer
/help - Toon deze lijst
"""
await update.message.reply_text(help_text)
def start_background_task():
def timer_checker():
global check_sent, warning_sent, final_sent
while True:
time.sleep(60)
with lock:
elapsed_time = time.time() - last_response_time
if elapsed_time >= final_interval and not final_sent:
send_final_mail()
elif elapsed_time >= warning_interval and not warning_sent:
send_warning_mail()
warning_sent = True
elif elapsed_time >= check_interval and not check_sent:
send_telegram_message("⚠️ Controle vereist: Er is al een tijd geen activiteit geweest. Reageer om de dead man's switch te resetten.")
check_sent = True
threading.Thread(target=timer_checker, daemon=True).start()
def start_event_loop():
asyncio.set_event_loop(loop)
loop.run_forever()
threading.Thread(target=start_event_loop, daemon=True).start()
start_background_task()
application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
application.add_handler(CommandHandler("status", show_status))
application.add_handler(CommandHandler("setcheck", lambda u, c: set_interval(u, c, "check")))
application.add_handler(CommandHandler("setwarning", lambda u, c: set_interval(u, c, "warning")))
application.add_handler(CommandHandler("setfinal", lambda u, c: set_interval(u, c, "final")))
application.add_handler(CommandHandler("reset", reset_timer))
application.add_handler(CommandHandler("help", show_help))
application.run_polling()