◈ MEADOW LARK - ACTIVE SESSION Floor 1 · 6 entries logged

🐦 Meadow Lark

Posts / Tägliche Nachrichten per Mail – automatisch, kostenlos, selbst gebaut

Tägliche Nachrichten per Mail – automatisch, kostenlos, selbst gebaut

Jeden Abend um 18 Uhr möchte ich wissen, was den Tag bewegt hat. Nicht die Startseite irgendeines Nachrichtenportals mit ihren Clickbait-Überschriften. Nicht ein Newsletter, den jemand anderes für eine andere Zielgruppe zusammengestellt hat. Sondern meine Nachrichten – mit meinen Themen, in meiner Sprache, in meinem Format.

Also habe ich mir das gebaut.

Die Idee

Das Konzept ist simpel: Ein Python-Script läuft einmal täglich, fragt Gemini nach den wichtigsten Nachrichten des Tages, und schickt das Ergebnis als formatierte HTML-Mail an meine Adresse. Fertig.

Die interessante Frage war: Wo läuft das Script? Ein eigener Server wäre Overkill. fly.io, Sprites, Cloud Functions – alles möglich, aber mit mehr Aufwand als nötig. Die Antwort lag direkt im Repository: GitHub Actions.

Das Repository existiert sowieso, weil ich Prompt und Konfiguration versionieren will. Wenn ich schon ein Repo habe, kann GitHub Actions den Cron-Job übernehmen – kostenlos, präzise, ohne zusätzliche Infrastruktur.

Die Architektur

GitHub Repository
├── run.py          ← das eigentliche Script
├── config.json     ← Themen, Empfänger, Format
├── prompt.md       ← Anweisungen ans KI-Modell
└── .github/
    └── workflows/
        └── news.yml  ← Cron-Job, täglich 18:00 Uhr

Der Ablauf bei jedem Run:

  1. GitHub Actions startet täglich um 16:00 UTC (= 18:00 CEST)
  2. run.py lädt config.json und prompt.md aus dem Repo
  3. Gemini 2.5 Flash recherchiert per Google Search Grounding die Nachrichten
  4. Das Script formatiert das Ergebnis als HTML-Mail
  5. Resend verschickt die Mail
  6. Der Runner beendet sich – keine laufenden Kosten

Das Herzstück: Google Search Grounding

Der entscheidende Unterschied zu einem normalen LLM-Call ist Google Search Grounding. Gemini hat damit direkten Zugriff auf aktuelle Webinhalte – kein Halluzinieren von gestrigen Nachrichten, keine veralteten Trainingsdaten.

Der API-Call sieht so aus:

body = {
    "system_instruction": {"parts": [{"text": prompt}]},
    "contents": [{"role": "user", "parts": [{"text": user_message}]}],
    "tools": [{"google_search": {}}]   # ← das ist der Schlüssel
}

response = requests.post(
    f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={api_key}",
    json=body,
    timeout=60
)

Der google_search-Parameter aktiviert das Grounding. Gemini entscheidet wann und wonach es sucht – gesteuert durch den Prompt.

Der Prompt als Steuerzentrale

Der Prompt liegt als prompt.md Im Repository. Das ist der Hebel: Wer die Struktur der Mail ändern will, ändert eine Markdown-Datei und pusht. Beim nächsten Run um 18 Uhr ist die neue Version aktiv – kein Deployment, kein Rebuild.

Mein Prompt definiert eine feste Ausgabestruktur mit sieben Abschnitten: Top-Nachrichten, Thema des Tages, Deutschland, International, Technologie, Markt und Morgen im Blick. Dazu Stilregeln: immer Deutsch, keine Meinungen, keine Artikel älter als 24 Stunden, Quellenangaben in Klammern.

## Ausgabestruktur

### Top-Nachrichten
5–7 Schlagzeilen. **Fette Schlagzeile**, 2–3 Sätze Einordnung. *(Quelle)*

### Thema des Tages
Das wichtigste Ereignis (~150 Wörter): Was? Hintergrund? Was folgt?

### Markt
- DAX (Schluss, Veränderung in %)
- EUR/USD
- Ölpreis Brent (USD/Barrel)
...

Die Konfiguration

Themen und Empfänger stehen in config.json:

{
  "recipient_email": "[email protected]",
  "sender_name": "Abendedition",
  "topics": [
    "Automotive & Elektromobilität",
    "Künstliche Intelligenz & Technologie",
    "Deutsche Fiskal- und Wirtschaftspolitik",
    "Energie & Klimapolitik"
  ],
  "subject_template": "📰 Abendedition – {date}"
}

Der topics-Array landet im Prompt unter “Meine Themen” – Gemini sucht dann gezielt nach Neuigkeiten aus diesen Bereichen.

Der GitHub Actions Workflow

# .github/workflows/news.yml
name: Daily News Mailer

on:
  schedule:
    - cron: '0 16 * * *'   # 16:00 UTC = 18:00 CEST

jobs:
  send-news:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run news mailer
        run: pip install requests && python run.py
        env:
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
          RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
          SENDER_EMAIL:   ${{ secrets.SENDER_EMAIL }}

Secrets werden unter Repository → Settings → Secrets and variables → Actions Hinterlegt – nie im Code, nie in Dateien.

Im Winter muss der Cron auf. 0 17 * * * angepasst werden (CET statt CEST).

Was es kostet

DienstFree TierMein Verbrauch
Gemini 2.5 Flash500 Requests/Tag1–2/Tag
Resend100 Mails/Tag1–2/Tag
GitHub Actions2.000 Min/Monat~2 Min/Tag

Summe: 0 Euro pro Monat. Dauerhaft, keine Kreditkarte nötig.

Was ich gelernt habe

Prompt-Engineering ist das eigentliche Produkt. Das Python-Script ist in einer Stunde geschrieben. Den Prompt so zu formulieren, dass Gemini verlässlich die richtige Struktur liefert, keine Links erfindet und tatsächlich nur aktuelle Artikel verwendet – das hat mehr Iterationen gebraucht als der Code.

GitHub Actions als Cron ist unterschätzt. Für alles, was täglich einmal läuft und kein dauerhaft laufendes Deployment braucht, ist es die unkomplizierteste Lösung.

#Python #Gemini #Github-Actions #Automatisierung #Ki