MailMerger-backend is a robust and scalable backend API designed for managing personalized email campaigns with advanced features like template management, email queueing, and user authentication. Built with FastAPI, SQLAlchemy, and Redis, it supports efficient email processing and template storage for high-performance applications.
- Features
- Demo
- Tech Stack
- Project Structure
- Setup and Installation
- Configuration
- Database Schema
- API Overview
- Frontend Repository
- Background Tasks
- Development & Testing
- Contribution
- License
- User Authentication: JWT-based login, signup, and refresh tokens. OAuth support (Google).
- Email Queue: Queue emails for asynchronous sending, retrieve or delete queued emails.
- Template Management: Create, manage, and cache email templates per user.
- Storage Integration: Connects to Supabase S3 for file storage needs.
- Database: Uses SQLAlchemy ORM with PostgreSQL (configurable).
- Caching: Heavy use of Redis for caching templates and email queues for fast access.
- Background Processing: Celery tasks for sending emails in the background.
- Configurable CORS: Supports cross-origin requests from configurable origins.
These screenshots from the frontend demonstrate features powered by the backend APIs.
- Framework: FastAPI (Python)
- ORM: SQLAlchemy
- Database: PostgreSQL (via
DB_CONNECTION_URL) - Cache: Redis (local/cloud, configurable)
- Task Queue: Celery (for background email sending through redis queue)
- Storage: Supabase S3
- Auth: JWT, OAuth (Google)
app/
├── main.py # FastAPI app entry point, middleware & router registration
├── models/ # SQLAlchemy models (User, Email, Template, etc.)
├── routes/ # API route definitions (auth, email, template, queue, storage)
├── utils/ # Utility functions & configuration
├── db/ # Database & Redis connection setup
├── pydantic_schemas/ # Request/response validation schemas
└── tasks/ # Celery tasks for background jobs
- Python 3.10+
- PostgreSQL database
- Redis server (local or cloud)
- Supabase account (for S3 storage)
- [Optional] Celery worker (for background email sending)
-
Clone the repository:
git clone https://github.com/manas-1404/MailMerger-backend.git cd MailMerger-backend -
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables:
- Copy
.env.exampleto.envand fill in all required values (see Configuration below).
- Copy
-
Run database migrations:
Tables are auto-created at FastAPI startup, but for production, set up migrations via Alembic if needed.
-
Start the FastAPI server:
uvicorn app.main:app --reload --host localhost --port 8000
-
[Optional only if sending batched emails] Start Celery worker:
celery -A app.celery_worker worker --loglevel=info --pool=solo
All critical settings are controlled via environment variables (see app/utils/config.py):
DB_CONNECTION_URL- PostgreSQL connection stringREDIS_HOST,REDIS_SERVER_PORT,REDIS_SERVER_DB- Redis config (local)REDIS_CLOUD_*- Redis config (cloud)SUPABASE_ACCESS_KEY_ID,SUPABASE_SERVICE_ROLE- Supabase credentialsSUPABASE_S3_STORAGE_ENDPOINT,SUPABASE_S3_STORAGE_REGION- Supabase S3 configJWT_SIGNATURE_SECRET_KEY,JWT_AUTH_ALGORITHM- JWT auth secretsGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET- Google OAuth credentialsALLOWED_ORIGINS- CORS allowed origins
See app/utils/config.py for the full list.
The backend uses PostgreSQL with four main tables: users, user_tokens, templates, and emails. The design keeps data organized, avoids duplication, and makes it easy to extend or scale.
Stores core account information.
-
Fields:
uid(PK): Unique user ID.name,email,password: Basic user profile and login details.jwt_refresh_token: Token used for refreshing login sessions.resume,cover_letter: File references for attachments (stored in Supabase storage) (accessed using object links).
-
Purpose: Acts as the main reference point for other tables.
Stores tokens for external services (e.g., Google API).
-
Fields:
token_id(PK): Unique token record.uid(FK → users.uid): User that owns the token.access_token,refresh_token,token_type,expires_at: Google OAuth, Gmail Service API token details.
-
Purpose: OAuth tokens are separated from primary user login data to simplify token rotation and expiry handling.
Stores user-created email templates for personalization and reuse.
-
Fields:
template_id(PK): Unique template record.uid(FK → users.uid): User that owns the template.t_body: Template content (HTML/text).t_key: Identifier or key for quick lookups.
-
Purpose: Lets users create multiple reusable templates without duplicating content in emails.
Represents queued or sent emails for campaigns.
-
Fields:
eid(PK): Unique email record.uid(FK → users.uid): Owner of the email.google_message_id: Reference for tracking emails via Google API.subject,body: Email content.to_email,cc_email,bcc_email: Recipient details.is_sent: Status flag indicating if the email is sent.send_at: Scheduled time to send the email.include_resume: Boolean flag to include user’s resume as an attachment.
-
Purpose: Allows managing large volumes of emails without repeating user or template data.
- One user can have multiple tokens (
1 users → M user_tokens). - One user can have multiple templates (
1 users → M templates). - One user can send or queue multiple emails (
1 users → M emails).
I designed this database schema to be clean, scalable, and easy to maintain as the system grows. A big part of that was applying normalization so that data is stored in the right place without duplication. The database schema is in 3NF.
-
First Normal Form (1NF):
Every table has a primary key and each column stores a single value. For example,to_email,cc_email, andbcc_emailare separate columns instead of one combined field. -
Second Normal Form (2NF):
Non-key fields depend entirely on the table’s primary key. Intemplates, every attribute depends ontemplate_idand nothing depends partly onuid. -
Third Normal Form (3NF):
There are no transitive dependencies. Data in each table depends only on its own primary key. For example,emailsreferencesusersviauidinstead of storing user details like name or email directly.
- Endpoints:
POST /api/auth/login- Login and receive JWT tokenPOST /api/auth/signup- Register new users
- Details:
- Credentials verified against hashed passwords.
- On login, user's templates are cached in Redis for faster access.
- JWT and refresh tokens are set as cookies.
- Endpoints:
GET /api/queue/get-email-queue- Retrieve queued emails for the userPOST /api/queue/add-to-queue- Add an email to the queuePOST /api/queue/send-queued-emails- Send queued emails (processed via Celery)DELETE /api/queue/delete-queue-email- Remove emails from the queue
- Details:
- Queues are stored in Redis for performance, fallback to DB if not cached.
- Email sending is performed asynchronously via Celery background worker.
- Endpoints:
GET /api/templates/get-all-templates- Fetch all templates for authenticated userPOST /api/templates/add-template- Add a new template- Other CRUD template endpoints available.
- Details:
- Templates are cached in Redis for each user to minimize DB queries.
- All cache operations have expiry set for performance and consistency.
- Endpoints:
- Storage endpoints connect to Supabase S3; see
app/routes/storage_routes.pyfor details.
- Storage endpoints connect to Supabase S3; see
- Celery is used for sending emails in the background.
- When a user requests to send queued emails,
send_emails_from_user_queueCelery task is triggered. - Ensure that the Celery worker is running and configured to connect to the same Redis instance as the server.
The frontend code for this project is available at: @manas-1404/MailMerger-frontend Please refer to the frontend repository for setup instructions and all client-side logic.
- Run locally: Follow setup instructions above.
- Testing: Add tests in a
tests/directory and usepytestfor running them. - Hot reload: Use
uvicorn ... --reloadfor auto-reloading during development.
Contributions are welcome! Please open issues or submit pull requests with improvements or bug fixes.
MIT License. See LICENSE for details.


