Your reading list, owned by you.
Turn your emails into a personalized reading feed with full-text content, semantic search, and smart link extraction. Self-hosted, open source, and private by design.
"If you've ever emailed yourself before, this app is for you."
"I mean, doesn't everyone do this?" — David
"Another read-it-later app shut down and took my whole library with it. Never again." — David, after losing his bookmarks for the third time
"I already email myself links. Why not just turn that into the whole app?" — David, at 2 AM, convincing himself to build this
"I miss RSS readers. I miss Google Reader. I will not let go." — David, mass-replying to everyone who said RSS is dead
- Email yourself a link (or any email matching your configured query)
- MailFeed syncs it, extracts the links, and fetches the full article content
- Browse everything in a clean reading feed with search and filters
- Gmail Integration — Syncs emails you send to yourself (
from:me to:me) by default, configurable to any Gmail query - Smart Link Extraction — Automatically finds, deduplicates, and follows redirects to surface real URLs
- Content Fetching — Fetches full articles with Mozilla Readability, falls back to the Wayback Machine for lost content
- Reading Feed — Clean interface with filters, search, categories, and reading time estimates
- Semantic Search — Chat with your saved links using vector embeddings and RAG-powered search
- AI Analysis — (Coming Soon) Summaries, key points, categorization, and content scoring
curl -fsSL https://raw.githubusercontent.com/toothbrush-inc/mailfeed/main/scripts/setup.sh | bashThis installs Docker if needed, clones the repo, walks you through entering your Google credentials, and starts everything. Open http://localhost:3000 when it's done.
You'll need:
- Google OAuth credentials (create them here) with the Gmail API enabled
- (Optional) A Gemini API key for AI features — you can add this later
git clone https://github.com/toothbrush-inc/mailfeed.git
cd mailfeed
cp .env.example .env # Add your Google credentials
docker compose up --build -d # Start the app + databaseOpen http://localhost:3000.
git clone https://github.com/toothbrush-inc/mailfeed.git
cd mailfeed
npm install
cp .env.example .env # Add your credentials + DATABASE_URL
docker compose up -d postgres # Start just the database
npx prisma db push # Apply schema
npm run dev # Start dev serverYou need a Google Cloud project with OAuth credentials to sign in and access Gmail.
- Create a Google Cloud project
- Enable the Gmail API
- Create OAuth 2.0 credentials (Web application)
- Add redirect URI:
http://localhost:3000/api/auth/callback/google
- Add redirect URI:
- Configure the OAuth consent screen
- Add scope:
https://www.googleapis.com/auth/gmail.readonly - Add your email as a test user (if using External)
- Add scope:
- Copy the Client ID and Client Secret into your
.env
Gemini API (optional): Get a key from Google AI Studio and add it as GEMINI_API_KEY in .env. This enables semantic search and AI features.
docker compose up -d # Start everything
docker compose down # Stop (data persists)
docker compose down -v # Stop and delete all data
docker compose logs -f app # View app logs
docker compose logs -f postgres # View database logsTo add or change a variable (e.g. adding GEMINI_API_KEY later):
- Edit
.envin the project root - Restart the container:
docker compose up -d app
No rebuild needed — the container reads .env at startup.
npm run dev # Start development server
npm run build # Production build
npm run lint # Run ESLint
npx prisma studio # Database GUI
npx prisma db push # Apply schema changesYou can add links to MailFeed programmatically — useful for browser extensions, shortcuts, or other integrations.
POST /api/links/add
Content-Type: application/json
{ "url": "https://example.com/article" }
Authentication: MailFeed uses session cookies (NextAuth). Requests must include a valid session cookie. If you're building a browser extension that runs on the same origin as your MailFeed instance (e.g. localhost:3000), the cookie is sent automatically.
Example with curl (grab the cookie from your browser's dev tools):
curl -X POST http://localhost:3000/api/links/add \
-H "Content-Type: application/json" \
-b "authjs.session-token=YOUR_SESSION_TOKEN" \
-d '{"url": "https://example.com/article"}'Responses:
| Status | Meaning |
|---|---|
| 200 | Link added and content fetched |
| 400 | Invalid or excluded URL |
| 401 | Not authenticated |
| 409 | URL already exists in your feed |
| 500 | Server error |
The response includes the full link object with fetched content, metadata, and any nested links extracted from social media posts.
app/
├── (auth)/login/ # Login page
├── (dashboard)/ # Protected routes
│ ├── feed/ # Main reading feed
│ ├── emails/ # Email list view
│ ├── settings/ # User settings
│ └── reports/ # Reported links
├── api/
│ ├── sync/ # Email sync endpoint
│ ├── links/ # Link CRUD
│ ├── chat/ # RAG chatbot
│ └── embeddings/ # Vector embeddings
components/ # React components
lib/ # Core logic
├── gmail.ts # Gmail API integration
├── content-fetcher.ts # Article extraction
├── gemini.ts # AI analysis
├── embeddings.ts # Vector embeddings
└── vector-search.ts # Similarity search
- Framework: Next.js 16 (App Router)
- Database: PostgreSQL + pgvector
- ORM: Prisma
- Auth: NextAuth.js v5
- AI: Google Gemini
- UI: React 19, Tailwind CSS v4, shadcn/ui
See FAQ.md for common questions about privacy, email syncing, AI features, and more.
MIT


