I Built a Morning Briefing Bot in 50 Lines of Python — Here's Why I Check Telegram Before Email Now
For years, my morning routine was the same: open laptop, check email, get distracted by Slack, remember I needed to check the weather, forget what I was doing, and 20 minutes later realize I hadn't started actual work yet.
Sound familiar?
Three months ago, I built a dead-simple Telegram bot that aggregates everything I actually care about into one message. It fires at 8 AM every day. I read it in 30 seconds. Then I start working.
No apps to switch between. No rabbit holes. Just one message with the stuff that matters.
What It Actually Sends
Every morning at 8 AM, my phone buzzes with something like this:
📅 Morning Brief — Wednesday, Jul 1
Today: Team standup at 10:00, Dentist at 14:30
Tomorrow: Deploy to prod (set reminder!)
🌤️ Weather: 28°C, sunny — no rain expected
💻 Systems: Mac Mini ✅ | GPU Server ✅ | Ubuntu Box ✅
All green. Uptime: 47 days.
📝 Yesterday's notes: "Refactored auth module, tests passing"
⚠️ One thing: GitHub issue #142 still open — "fix API rate limiting"
That's it. No graphs. No dashboards. No "click here to see more." Just the facts I need to plan my day.
Why Telegram?
I already use Telegram for my devops dashboard (wrote about that here). Adding a morning briefing was a natural extension.
But honestly? The real reason is friction reduction. My phone's notification shade is a graveyard of app alerts I ignore. Telegram is one of the few apps I actually open. Putting my briefing there means I actually read it.
The Architecture (It's Embarrassingly Simple)
Here's the entire stack:
- Cron job on my Mac Mini — triggers at 8:00 AM daily
- 50-line Python script — gathers data from 4 sources
- Telegram Bot API — sends the formatted message
That's it. No web framework. No database. No message queue. Just a script that runs, collects, formats, and sends.
The Script
Here's the core of it (simplified, but functional):
#!/usr/bin/env python3
import os
import json
import requests
from datetime import datetime, timedelta
# Config
BOT_TOKEN = os.environ['BRIEFING_BOT_TOKEN']
CHAT_ID = os.environ['MY_TELEGRAM_CHAT_ID']
# Gather data
def get_calendar():
# I export from Apple Calendar to a local ICS file nightly
# This reads today's events from it
# ... (parsing logic here) ...
return ["Team standup at 10:00", "Dentist at 14:30"]
def get_weather():
# wttr.in — free, no API key needed
r = requests.get('https://wttr.in/Sakarya?format=%C+%t')
return r.text.strip()
def get_system_status():
# Quick ping to my other machines
machines = {
'Mac Mini': '192.168.1.105',
'GPU Server': '192.168.1.106',
'Ubuntu Box': '192.168.1.100'
}
status = {}
for name, ip in machines.items():
response = os.system(f'ping -c 1 -W 2 {ip} > /dev/null 2>&1')
status[name] = '✅' if response == 0 else '❌'
return status
def get_github_issues():
# Check my main repo for open issues labeled "urgent"
# ... (GitHub API call) ...
return ["#142: Fix API rate limiting"]
# Build and send message
def send_briefing():
calendar = get_calendar()
weather = get_weather()
systems = get_system_status()
issues = get_github_issues()
today = datetime.now().strftime('%A, %b %d')
lines = [
f"📅 Morning Brief — {today}",
"",
"Today:",
*[f" • {event}" for event in calendar] if calendar else [" • Nothing scheduled 🎉"],
"",
f"🌤️ Weather: {weather}",
"",
"💻 Systems:",
*[f" {name} {status}" for name, status in systems.items()],
"",
]
if issues:
lines += ["⚠️ Open issues:", *[f" • {issue}" for issue in issues]]
message = '\n'.join(lines)
requests.post(
f'https://api.telegram.org/bot{BOT_TOKEN}/sendMessage',
json={'chat_id': CHAT_ID, 'text': message, 'parse_mode': 'HTML'}
)
if __name__ == '__main__':
send_briefing()
The real version has error handling and a few more data sources (like yesterday's git commit summary), but this is the gist. 50 lines. One cron entry. Done.
The Cron Job
# crontab -e
0 8 * * * /usr/bin/python3 /Users/sam/scripts/morning_briefing.py >> /tmp/briefing.log 2>&1
That's literally the entire scheduling infrastructure.
What Changed
Before: I'd check 4-5 apps every morning. Sometimes I'd miss something. Sometimes I'd get distracted. Average time to "actually working": 20-30 minutes.
After: One notification. 30 seconds to read. I know what's happening today, whether my systems are healthy, and if there's anything urgent. Then I close Telegram and start work.
Average time to "actually working": 2 minutes.
The weird part? I feel less anxious. I used to have this low-grade worry that I was forgetting something. Now I know the bot checks for me. If there was a problem, I'd know.
The Downsides (Because Nothing's Perfect)
ICS parsing is brittle. Apple Calendar exports aren't always clean. I had to add a nightly script that sanitizes the ICS file before the morning run.
Weather API can be flaky. wttr.in is great until it isn't. I added a fallback to a local weather file that updates every hour.
No interactivity. It's a one-way push. If I want details ("what's in that GitHub issue?"), I have to go look. I tried adding reply buttons, but honestly, it added complexity I didn't need. The goal was speed, not interactivity.
Edge cases suck. Daylight saving time shift? The cron fired at 7 AM for a week before I noticed. Public holidays? The bot doesn't know. I had to add a manual "skip" flag for vacation days.
Should You Build This?
If you check more than 3 apps every morning: probably yes.
You don't need my exact setup. Use whatever you have:
- Discord webhook instead of Telegram?
- A simple Bash script instead of Python?
- iOS Shortcuts instead of cron?
The pattern matters more than the stack: one automated message, curated by you, delivered where you already look.
Start small. My first version just sent the weather and today's calendar. Everything else came later. The 50-line script grew to 150 lines over three months — but it started as a weekend experiment.
What's Next
I'm experimenting with two additions:
Weekly summary on Sundays — "This week you shipped 12 commits, closed 3 issues, and your GPU earned $47."
Context-aware alerts — If I have a meeting in 15 minutes and haven't checked the briefing, send a nudge. But only for external meetings (not "standup" — I won't forget that).
The goal isn't to build a product. It's to build a personal utility that removes friction from my day.
I write about running AI locally, building weird automation, and occasionally making money from side projects. If this was useful, drop a comment with your morning routine — I'm always looking for ideas to steal.
Top comments (1)
The friction-reduction framing is the correct way to think about this. The real cost of a multi-app morning routine isn't the time spent, it's the context-switch tax and the decision fatigue from choosing which alert to acknowledge first. Consolidating into a single Telegram message at a fixed time means your attention is never in a reactive mode — you go to the information, it doesn't come for you.
One extension worth considering: if your briefing aggregates anything that arrives via email (GitHub issue digests, calendar invites, service alerts), you can route those through a scriptable inbox rather than your primary address so the bot reads from an API instead of your personal mailbox — keeps the "stuff I need to action" cleanly separate from the "stuff the bot reads for me."