A modern, feature-rich email management application built with Flutter and Node.js, providing seamless Gmail integration with intelligent email organization and access.
This application is currently in development mode, and the Gmail OAuth consent screen is in Testing status.
Because of this:
- Only whitelisted test users in Google Cloud Console can log in using Gmail OAuth.
- If you are not added as a test user, Google will block login and show:
“Access blocked: This app is not verified.”
You can log in to InboxIQ in two ways:
You can create an account using your:
- Password
This will allow you to access the app and connect Gmail later.
To use Gmail features (Inbox, Drafts, Sent, Attachments, etc.),
you must log in using a Google account added as a test user.
If you are a tester, please use the following test account:
Email: utkb30938@gmail.com
Password: test@123
- 🔐 Hybrid Authentication System - Secure Supabase authentication with email/password
- 🔗 Gmail OAuth Integration - Seamless Gmail account connection with read-only access
- 📬 Email Management - View and organize emails by type (Inbox, Sent, Drafts, Starred, Unread, Trash, Spam)
- 🔄 Automatic Email Sync - Background synchronization of up to 500 latest emails
- 📎 Attachment Support - View and download email attachments
- 🎨 Rich Email Display - HTML rendering with inline images and formatting
- 📱 Cross-Platform - Works on Android and iOS
- 🔒 Secure Token Storage - Encrypted OAuth tokens with AES-256-CBC
- 🎯 Clean Architecture - Feature-based modular structure
- Flutter - Cross-platform mobile framework
- Riverpod - State management
- Dio - HTTP client
- Supabase Flutter - Authentication and database client
- flutter_html - HTML email rendering
- Node.js - Runtime environment
- Express.js - Web framework
- Google APIs - Gmail API integration
- Supabase - PostgreSQL database and authentication
- Crypto - Token encryption
- Supabase - Database, authentication, and storage
- Google Cloud Console - OAuth 2.0 credentials
- Cloudflare Tunnel - Public HTTPS tunnel for development
Before you begin, ensure you have the following installed:
- Flutter SDK (3.0 or higher)
flutter --version
- Node.js (18.0 or higher)
node --version
- npm (comes with Node.js)
npm --version
- Supabase Account - Sign up here
- Google Cloud Console Project - Create here
- Cloudflare Tunnel (for development) - Download here
inboxiq/
├── lib/
│ ├── features/ # Feature-based modules
│ │ ├── auth/ # Authentication feature
│ │ │ ├── domain/ # Business logic layer
│ │ │ │ ├── entities/
│ │ │ │ ├── repositories/
│ │ │ │ └── usecases/
│ │ │ ├── data/ # Data layer
│ │ │ │ ├── datasources/
│ │ │ │ ├── models/
│ │ │ │ └── repositories/
│ │ │ └── presentation/ # UI layer
│ │ │ ├── providers/
│ │ │ └── screens/
│ │ └── email/ # Email feature
│ │ ├── domain/
│ │ ├── data/
│ │ └── presentation/
│ │ ├── providers/
│ │ ├── screens/
│ │ └── widgets/
│ ├── backend/ # Node.js backend
│ │ ├── config/ # Configuration files
│ │ ├── controllers/ # Request handlers
│ │ ├── middleware/ # Express middleware
│ │ ├── routes/ # API routes
│ │ ├── services/ # Business logic
│ │ └── utils/ # Utility functions
│ ├── core/ # Shared utilities
│ │ ├── constants/
│ │ ├── di/ # Dependency injection
│ │ ├── errors/
│ │ └── utils/
│ └── main.dart # App entry point
├── supabase/
│ └── schema.sql # Database schema
└── .env # Environment variables
git clone <repository-url>
cd inboxiqflutter pub getcd lib/backend
npm install
cd ../..- Create a new project at Supabase
- Go to Settings → API and copy:
- Project URL
anonpublic keyservice_rolesecret key
- Run the database schema:
-- Execute supabase/schema.sql in Supabase SQL Editor
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Gmail API
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID
- Configure OAuth consent screen:
- User Type: External
- Publishing status: Testing
- Add test users (your Gmail account)
- Scopes:
https://www.googleapis.com/auth/gmail.readonly
- Create OAuth 2.0 Client ID:
- Application type: Web application
- Authorized redirect URIs:
https://your-cloudflare-url.trycloudflare.com/api/oauth/callback
Create .env file in the project root:
SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
API_BASE_URL=https://your-cloudflare-url.trycloudflare.comCreate .env file in lib/backend/:
PORT=3000
SUPABASE_URL=your_supabase_project_url
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_REDIRECT_URI=https://your-cloudflare-url.trycloudflare.com/api/oauth/callback
ENCRYPTION_KEY=your_32_byte_hex_encryption_keyGenerate Encryption Key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"- Download Cloudflare Tunnel
- Start tunnel:
cloudflared tunnel --url http://localhost:3000
- Copy the generated URL (e.g.,
https://xxxxx.trycloudflare.com) - Update
.envfiles with the new URL - Update Google Cloud Console redirect URI
cd lib/backend
npm startThe server will start on http://localhost:3000
cloudflared tunnel --url http://localhost:3000flutter runGET /health- Server health status
GET /api/oauth/connect- Generate OAuth URL (requires auth)GET /api/oauth/callback- Handle OAuth callbackPOST /api/oauth/verify- Verify authorization code (requires auth)GET /api/oauth/connect/status- Check connection status (requires auth)
GET /api/emails- Get emails list- Query params:
limit,offset,type(inbox, sent, draft, starred, unread, trash, spam)
- Query params:
GET /api/emails/:emailId- Get email detailsGET /api/emails/:emailId/attachments/:attachmentId- Get attachmentPOST /api/emails/sync- Start email syncGET /api/emails/sync/status- Get sync status
Features:
- Domain: Entities, repositories (interfaces), use cases
- Data: Models, repository implementations, data sources
- Presentation: Screens, widgets, providers (Riverpod)
Routes → Controllers → Services → Database/APIs
Layers:
- Routes: Express route definitions
- Controllers: Request/response handling
- Services: Business logic
- Config: Configuration files
- Middleware: Authentication, logging
- Utils: Helper functions
- ✅ Encrypted OAuth tokens (AES-256-CBC)
- ✅ Row-level security in Supabase
- ✅ JWT token authentication
- ✅ Secure token refresh mechanism
- ✅ Environment variable protection
- ✅ HTTPS via Cloudflare Tunnel
These are the error faced by me while integrating backend Google client and Application
"Connection refused" error:
- Ensure backend is running on port 3000
- Check firewall settings
- Verify
API_BASE_URLin Flutter.env
"redirect_uri_mismatch" error:
- Verify Cloudflare URL matches Google Cloud Console redirect URI exactly
- Check for trailing slashes
- Ensure URL is HTTPS
Key tables:
oauth_tokens- Encrypted OAuth tokensemails- Synced email dataemail_sync_status- Sync progress tracking
See supabase/schema.sql for full schema.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
💻 Author: Utkarsh
📧 Email: ubhatt2004@gmail.com
🐙 GitHub: https://github.com/UKbhatt
- Supabase for backend infrastructure
- Flutter for cross-platform development
- Google Gmail API for email access
Note: This application requires Google OAuth consent screen approval for production use. For development, use test users in Google Cloud Console.