DEV Community

Sam Hartley
Sam Hartley

Posted on

I Built a Morning Briefing Bot in 50 Lines of Python — Here's Why I Check Telegram Before Email Now

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"
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Weekly summary on Sundays — "This week you shipped 12 commits, closed 3 issues, and your GPU earned $47."

  2. 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)

Collapse
 
francofuji profile image
Francisco Perez

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."