A formal “research desk memo” styled daily briefing: Spectral serif headlines, parchment tones, a classification bar, roman-numeral sections (Executive Summary, Top Developments, Thematic Watch, Markets & Macro, Technology & AI, Closing Note), and a real live market data table — sent every morning at 6:30am IST. Curated with India macro/micro trends as an explicit top-priority category alongside global business, AI, and markets news.
Cost: $0. Curation runs on Gemini’s free API tier, market data comes from Yahoo Finance (free, no key), and everything else (GitHub Actions, Gmail sending) is free-forever infrastructure. If Gemini’s call fails, the script falls back to a simpler local summarizer for that run — the email still arrives, just with only the Top Developments section (no executive summary, thematic watch, AI pulse, or closing note, since those need AI synthesis), and the footer honestly says which mode produced it. If the market data fetch fails for any reason, Markets & Macro is simply omitted that day rather than showing stale or fabricated numbers.
“Recommended Reading” from the original design reference isn’t included, since it would need a long-form-essay picker this pipeline doesn’t have. The Closing Note is an original insight rather than a quote attributed to a real person, to avoid ever misattributing something to someone who didn’t say it.
config.yaml lists RSS feeds — your global publishers (Reuters, AP,
BBC, TechCrunch, Ars Technica, MIT Tech Review, The Verge, OpenAI,
Anthropic, DeepMind, etc.) plus India-focused sources (Economic Times
Markets, LiveMint, Moneycontrol, Business Standard, RBI) — and
recipient_name for the “Good morning, ___.” greeting.news_briefing.py, which:
config.yaml already lists your publishers with RSS URLs pre-filled,
plus recipient_name (defaults to “Mohin” — change to whatever name you
want in the greeting). A few publishers (Reuters, AP, Anthropic, Meta
Business Blog, Google Ads Blog, LinkedIn Marketing Blog) don’t run a
public RSS feed, so those route through a Google News “site:” search
instead. The India-focused feeds (LiveMint, Moneycontrol, Business
Standard) use commonly-documented URLs that weren’t individually
re-verified — if fetch_articles logs a [warn] for one, search
"<site> RSS feed" to find the current URL. Same trick works for adding
any new source: "<site name>" RSS feed, or try /feed, /rss,
/rss.xml.
Don’t use your real Gmail password here. Instead:
gemini-2.5-flash, on Google’s free tier as of mid-2026.
Free-tier model names/limits do occasionally change — if the script’s
fallback keeps kicking in, check
https://ai.google.dev/gemini-api/docs/pricing for the current free
Flash model name and update the GEMINI_MODEL line near the top of
news_briefing.py..github/workflows/daily-briefing.yml — check it actually
landed there, since drag-and-drop sometimes misses hidden folders or
nests everything one level too deep).Repo → Settings → Secrets and variables → Actions → New repository secret. Add these four:
| Secret name | Value |
|---|---|
EMAIL_ADDRESS |
the Gmail address to send FROM |
EMAIL_APP_PASSWORD |
the 16-character app password from step 2 |
TO_EMAIL |
the address to send the briefing TO (can be the same Gmail address) |
GEMINI_API_KEY |
your Gemini API key from step 3 |
(If you skip GEMINI_API_KEY, the script runs the free local summarizer
instead — it degrades gracefully rather than failing.)
Actions tab → “Daily News Briefing” → Run workflow. Check your inbox within a minute or two. If it fails, click into the run to read the error log.
Once the test succeeds, it fires automatically every day at 6:30am IST — no seasonal time-zone adjustment ever needed.
recipient_name in config.yaml.BRIEFING_SPEC text
block near the top of news_briefing.py — the actual instruction
Gemini curates against.BRIEFING_SPEC targets 5-7; adjust the wording
there, and max_stories in fallback_curate() to match.tickers list in fetch_market_data() —
any valid Yahoo Finance symbol works (e.g. ^GSPC for the S&P 500, or
RELIANCE.NS for a specific Indian stock).ACCENT, INK, FONT_SERIF, FONT_MONO,
etc.) near the top of the rendering section in news_briefing.py.cron line in the workflow file (UTC).smtp.gmail.com / port in send_email().