Contributing Guide & Monorepo Architecture

Learn how to set up the EmitMail monorepo locally, understand the single-app multi-service architecture, and contribute across the API, Worker, Dashboard, and Documentation.

Welcome to the EmitMail open-source contributor guide! EmitMail is built as a cohesive, single-monorepo application powering high-deliverability transactional email dispatch, 2048-bit RSA DKIM generation, and an inbound SMTP mailbox engine.

Whether you are fixing a bug, adding a new feature to the Backend API, optimizing the Background Worker, polishing the Cloudflare Kumo Dashboard, or improving our Documentation, this guide will help you get up and running in minutes.


1. Monorepo Architecture Overview

EmitMail is organized as a pnpm workspace containing four applications. The packages/ directories are workspace scaffolding and are not currently shared implementation packages.

emitmail/
├── apps/
│   ├── api/            # Express REST API, Prisma ORM, Inbound SMTP receiver (Port 2525)
│   ├── worker/         # Decoupled BullMQ delivery engine, direct MX transport (Port 25)
│   ├── dashboard/      # Next.js 16 UI, @cloudflare/kumo design system, React 19
│   └── docs/           # Next.js 16 + Fumadocs documentation engine (Port 3001)
├── packages/           # Workspace scaffolding; currently no shared package implementation
├── docker/             # Production & development Dockerfiles
├── scripts/            # Deliverability tests and queue simulation scripts
└── docker-compose.dev.yml # Local development PostgreSQL & Redis infrastructure

How the Single Monorepo Works Together

┌─────────────────────────────────────────────────────────────────────────────┐
│                             EmitMail Monorepo                               │
│                                                                             │
│   ┌────────────────────┐                   ┌────────────────────────────┐   │
│   │  apps/dashboard    │ ──(HTTP/REST)───► │  apps/api                  │   │
│   │  (Next.js + Kumo)  │                   │  (Express + Prisma)        │   │
│   │  Port 3000         │                   │  Port 4000                 │   │
│   └────────────────────┘                   └──────┬──────────────┬──────┘   │
│                                                   │              │          │
│                                           (BullMQ │              │ (Prisma) │
│                                             Jobs) │              │          │
│                                                   ▼              ▼          │
│   ┌────────────────────┐                   ┌──────────────┐ ┌───────────┐   │
│   │  apps/docs         │                   │ Redis        │ │ PostgreSQL│   │
│   │  (Fumadocs Engine) │                   │ Port 6379    │ │ Port 5432 │   │
│   │  Port 3001         │                   └──────┬───────┘ └─────▲─────┘   │
│   └────────────────────┘                          │               │         │
│                                            (Pulls │               │         │
│                                             Jobs) │               │ Updates │
│                                                   ▼               │ Status  │
│                                            ┌──────────────┐       │         │
│                                            │ apps/worker  │───────┘         │
│                                            │ (SMTP Engine)│                 │
│                                            └──────────────┘                 │
└─────────────────────────────────────────────────────────────────────────────┘

2. Quickstart: Local Environment Setup

Prerequisites

Ensure you have installed:

  • Node.js: v20.x or v22.x (LTS recommended)
  • pnpm: v9.x or higher (corepack enable && corepack prepare pnpm@latest --activate)
  • Docker & Docker Compose: For local PostgreSQL 16 and Redis 7
  • Git: For version control

Clone the Repository

git clone https://github.com/omkarbhosale-dev/emitmail.git
cd emitmail

Install Workspace Dependencies

Install dependencies across the entire monorepo using pnpm:

pnpm install

Configure Environment Variables

Copy the example .env.example file to .env:

cp .env.example .env

Review the values in .env.example. It contains safe placeholders, not production-ready secrets. For local development, docker-compose.dev.yml provides PostgreSQL and Redis; set the API and worker connection variables to match that compose file before starting services.

Start Local PostgreSQL & Redis

Launch the containerized development database and Redis instances:

pnpm dev:docker

Verify that both containers are running healthy:

docker compose -f docker-compose.dev.yml ps

Initialize and Seed Database

Generate the Prisma client, push the schema to PostgreSQL, and seed the default administrator:

# Generate Prisma Client
pnpm db:generate

# Push schema to local Postgres
pnpm db:push

# Seed the administrator (temporary password: emitmail)
pnpm db:seed

Sign in as admin with temporary password emitmail, then change it in dashboard Settings before using protected endpoints.


3. Running Services Locally

You can run individual services depending on which part of EmitMail you are developing:

CommandServiceURL / PortPurpose
pnpm dev:apiBackend APIhttp://localhost:4000Express REST API, Inbound SMTP on port 2525
pnpm dev:workerDelivery WorkerConsole (Background)BullMQ worker consuming queue & dispatching emails
pnpm dev:dashboardDashboard UIhttp://localhost:3000Next.js 16 App Router + Cloudflare Kumo components
pnpm dev:docsDocumentationhttp://localhost:3001Fumadocs MDX documentation site

Initial Admin Account

The seeded admin credentials are admin / emitmail. Change the temporary password in dashboard Settings before using protected endpoints.


4. Explore Component Contribution Guides

Explore our detailed guides for each component of the EmitMail application:


5. Contribution & Pull Request Workflow

We follow standard GitHub Flow for all contributions:

1. Branching Strategy

Create a descriptive branch from main:

  • feat/feature-name for new capabilities
  • fix/bug-description for bug fixes
  • docs/page-name for documentation updates
  • perf/optimization for performance enhancements
git checkout -b feat/custom-webhook-headers

2. Conventional Commit Guidelines

We use Conventional Commits to generate automated changelogs:

  • feat: add support for custom webhook headers
  • fix: handle 2048-bit multi-chunk DKIM TXT strings in resolver
  • docs: add contributing guide for backend api and worker
  • refactor: extract mx resolution logic into dedicated service

3. Verification Checklist Before Submitting a PR

Before opening a pull request, ensure:

  1. pnpm build:api compiles with 0 TypeScript errors.
  2. pnpm build:worker compiles with 0 TypeScript errors.
  3. pnpm build:dashboard builds successfully.
  4. pnpm build:docs generates all static MDX pages without errors.
  5. All environment variables have clear documentation in .env.example.

On this page