A one-user Gmail triage assistant with Gemini drafts and self-hosted reply telemetry.
GlassyReply watches Gmail, forwards new inbox messages to Telegram, generates Gemini-assisted reply drafts, and lets the owner act from inline keyboards: send, save draft, trash, star, label, forward, and download attachments.
The project is built for personal email operations: fast triage, quick reply drafting, private configuration, delivery feedback, and deployment on a small self-hosted runtime.
- Turn Gmail into a Telegram-native triage workflow
- Generate draft replies without opening the inbox first
- Keep actions explicit through owner-only inline buttons
- Configure the bot from Telegram or a signed private dashboard
- Run locally, in Docker, or on Fly.io with persistent SQLite state
- Attach self-hosted pixel telemetry to outbound HTML drafts
- Separate noisy proxy fetches from likely human opens using confidence scoring
flowchart LR
A["Gmail API"] --> B["GlassyReply bot"]
B --> C["Telegram owner"]
B --> D["Gemini API"]
B --> E["SQLite state"]
B --> F["Private dashboard"]
B --> G["Signed pixel routes"]
G --> H["Open confidence scoring"]
- Gmail inbox polling with optional Gmail Push wake-up
- Telegram inline keyboards for direct message actions
- Gemini-powered reply drafting
- Attachment download flow
- Labels, stars, trash, forwarding, draft creation, and send actions
- Owner claim flow through
/start - Guided setup through
/setup - Private signed dashboard for runtime configuration
- SQLite persistence for settings, Gmail state, and pending follow-ups
- Reply telemetry with signed image, CSS background, dark-mode, and font routes
- Telegram stats that separate proxy fetches, likely human opens, and reopens
- Docker and Fly.io deployment support
- Optional Cloudflare Worker for separate edge-hosted tracking experiments
- Runtime: Python 3.11+
- Bot layer: Telegram Bot API
- Mail layer: Gmail API + OAuth Web client
- AI layer: Gemini API
- Web layer: Quart routes for landing, dashboard, OAuth callback, health, Gmail push, and pixel telemetry
- Telemetry layer: signed tracking tokens, multi-route pixels, confidence scoring, proxy classification, optional Worker mode
- State: SQLite and local JSON token files
- Deploy: Docker, Docker Compose, Fly.io, optional Cloudflare Worker
- Tests: Python unit tests and Worker dry-run checks
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python3 tg_email.py --mode pollingThen open Telegram:
- Send
/startto claim the bot owner. - Send
/setupand follow the guided configuration. - Add a Gemini API key.
- Upload Google OAuth Web client credentials.
- Connect Gmail through the generated login link.
At minimum:
TELEGRAM_BOT_TOKEN=...Common runtime paths:
DATA_DIR=./data
STATE_DB_PATH=./data/state.db
GMAIL_TOKEN_PATH=./data/token.json
GMAIL_CREDENTIALS_PATH=./data/credentials.json
PUBLIC_BASE_URL=http://127.0.0.1:8080Most values can also be configured later through Telegram or the private dashboard.
docker compose up --buildGlassyReply can run on Fly with a persistent volume mounted at /app/data.
The bot supports polling, webhook mode, Gmail Push wake-up, and health checks.
GlassyReply includes a self-hosted telemetry layer for outbound HTML replies. The goal is not to pretend that email opens are perfect truth; the goal is to extract useful delivery feedback from a messy environment where Gmail image proxy, Apple Mail Privacy Protection, security scanners, and real humans can all fetch remote assets.
The telemetry system supports:
- signed pixel URLs so events cannot be spoofed casually
- same-app tracking routes on Fly:
/track/img/.../track/bg/.../track/dark/.../track/font/...
- optional Cloudflare Worker mode for a separate edge-hosted tracker
- webhook-secret validation before parsing telemetry events
- confidence scoring for likely human opens
- separation between proxy fetches, probable opens, and probable reopens
- readable timestamps using the configured timezone
- Telegram-side stats for tracked drafts
Tracked replies are handled carefully: the draft can be edited cleanly first, then sent with tracking only when the owner explicitly chooses the tracked send flow from Telegram. This avoids counting the owner's own Gmail draft editing as an open event.
This feature should be used carefully and only in contexts where tracking is allowed and appropriate.
python3 -m unittest discover -s tests -v
npm run worker:checktg_email.py: bot runtime, Gmail wrapper, Quart server, SQLite statesrc/index.ts: optional Cloudflare Worker telemetry routescripts/pixel_smoke_test.py: local telemetry smoke-test helpersdocs/pixel-tracker-research.md: notes on email-client tracking limits
- Only the configured Telegram owner can use bot handlers.
- Dashboard links are signed and time-limited.
- Gmail OAuth uses a Web client callback.
- Push and telemetry webhook secrets are checked before parsing payloads.
- Pixel tokens are signed.
- Gmail state and bot settings persist in SQLite.
GlassyReply is a personal automation project. The core triage, setup, configuration, and deployment paths are present; advanced telemetry should be treated as optional and experimental.