Automatically convert email digests into podcast episodes using Python, Google Cloud TTS, and Google Cloud Storage.
- Ingest: IMAP fetch
- Process: HTML parsing + clean text
- Synthesize: Google Cloud TTS
- Host: Upload MP3 to GCS
- Publish: Generate RSS feed
- Listen: Subscribe in any podcast app
.
├── src/
│ ├── config/
│ │ ├── __init__.py # Env config
│ │ └── settings.py # Typed settings
│ ├── core/
│ │ ├── models.py # Episode/Digest models
│ │ └── pipeline.py # Orchestration
│ ├── services/
│ │ ├── ingest_service.py
│ │ ├── tts_service.py
│ │ ├── rss_service.py
│ │ └── storage_service.py
│ ├── email_ingest.py # IMAP fetch
│ ├── text_processor.py # Text parsing/cleanup
│ ├── tts.py # Google Cloud TTS
│ ├── gcs_upload.py # GCS uploader
│ └── rss_feed.py # RSS generator
├── data/
│ ├── output/ # MP3/feed/processed text
│ ├── episodes.json # Episode store
│ └── feedback/ # Feedback files
├── assets/
│ └── audio/ # Music/chimes
├── credentials/ # GCS credentials
├── docs/ # Docs
├── scripts/ # Utilities
├── tests/ # Unit tests
├── main.py # Entrypoint
├── requirements.txt
├── .env.example
└── .gitignore
ffmpeg is required for audio processing:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt-get install ffmpeg
# Windows
# Download from https://ffmpeg.org/download.html and add to PATHpython3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtCopy .env.example to .env and fill in your credentials:
cp .env.example .envEdit .env with your actual values:
- Email: Gmail address and app-specific password
- Google Cloud TTS (Vertex AI voices): Voice name and language code (credentials via
GCS_CREDENTIALS_FILE) - Google Cloud Storage: Project ID, bucket name, and credentials file
- Podcast: Metadata (title, description, author)
For Gmail, you'll need an app-specific password:
- Enable 2-factor authentication on your Google account
- Go to https://myaccount.google.com/apppasswords
- Generate a new app password for "Mail"
- Use this password in your
.envfile
See docs/SETUP_GCS.md for detailed setup instructions.
Quick summary:
- Create a Google Cloud project
- Create a GCS bucket
- Make bucket publicly accessible
- Create a service account and download JSON credentials
- Update your
.envfile
Run the pipeline:
python main.pyTo run automatically every day at 6:45 AM Pacific, use launchd.
This project uses a launchd agent that runs every minute, but the wrapper script only executes the pipeline when it is 06:45 in America/Los_Angeles. This keeps the schedule pinned to Pacific time even if you travel to other time zones.
- Install the LaunchAgent:
mkdir -p ~/Library/LaunchAgents
cp "scripts/launchd/com.tldrpodcast.daily.plist" ~/Library/LaunchAgents/
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.tldrpodcast.daily.plist
launchctl enable "gui/$(id -u)/com.tldrpodcast.daily"- Verify it’s loaded:
launchctl print "gui/$(id -u)/com.tldrpodcast.daily" | headLogs are written to data/logs/.
To change the pinned timezone or time, edit scripts/run_daily_pipeline.sh (variables TARGET_TZ and TARGET_TIME).
To uninstall:
launchctl bootout "gui/$(id -u)" ~/Library/LaunchAgents/com.tldrpodcast.daily.plist
rm ~/Library/LaunchAgents/com.tldrpodcast.daily.plistRun tests:
python -m unittest discover -s testsThe script will:
- Fetch the latest email matching your subject filter
- Clean and process the text
- Generate an MP3 file using Google Cloud TTS
- Upload the audio to Google Cloud Storage
- Generate/update the RSS feed
- Upload the feed to Google Cloud Storage
Subscribe to the feed URL in your podcast app!
GitHub Actions runs tests on push and pull requests (see .github/workflows/tests.yml).
MIT