Skip to content

Development

Everything you need to build features, fix bugs, or extend Mailyte. Whether you're adding a new worker, writing tests, or shipping a release — start here.


In this section

  • Getting Started (Dev)


    Set up your local dev environment, run the stack, and make your first change.

    Dev setup

  • Adding Features


    How to add a new feature end to end — from database migration to API endpoint to worker.

    Adding features

  • Contributing


    PR process, branch naming, commit conventions, and code review guidelines.

    Contributing

  • Coding Standards


    Ruff, mypy, the baseline ratchets, naming conventions, and file organization.

    Coding standards

  • Testing


    Running and writing tests — unit, integration, and end-to-end.

    Testing

  • Custom Workers


    Build a new background worker module with the standard worker template.

    Custom workers

  • Plugin Development


    The supported extension points — webhooks, custom workers, and mail-pipeline hooks.

    Plugin development

  • Monitoring Integration


    Add Prometheus metrics, Grafana dashboards, and health check endpoints.

    Monitoring integration

  • Release Process


    Versioning, changelog management, building images, and deploying.

    Release process


Repo Structure

Text Only
mailyte-email-server/
  alembic/              # Alembic migration scripts (alembic/versions/)
  config/               # Service configuration files
  database/
    migrations/sql/     # Frozen SQL bootstrap files (historical; CE first-boot)
  deployment/           # Production deployment configs
  docs/                 # This handbook (MkDocs Material; mkdocs.yml lives here)
  logs/                 # Service logs (git-ignored)
  mailer/               # Mail service Dockerfiles and configs
    postfix/
    dovecot/
    rspamd/
    cert_manager/
    log_ingestor/       # Parses Postfix logs into mail_logs/delivery_events
  monitoring/           # Prometheus, Grafana, Alertmanager configs
  scripts/              # Utility + CI scripts (run_mypy.sh, run_migrations.py, ...)
  secrets/              # Generated secret files (git-ignored)
  security/             # Security services (DLP, TOTP, geo-blocking, ...)
  shared/               # Shared Python modules across workers
  storage/              # Mail data, certs, DKIM keys (git-ignored)
  tests/                # Test suite (unit/, integration/, e2e/, load/)
  worker/               # Worker service modules (one directory per service)
    api/                # REST API gateway (FastAPI)
    activesync/  analytics/  archiver/  autoconfig/  caldav/
    dashboard/  delivery_optimizer/  encryption/  jmap/  migration/
    monitoring/  oauth/  queue_manager/  rag/  rate_limiter/
    storage_usage/  templates/  tracking/  url_protection/  webhooks/
  docker-compose.yml    # Base compose file
  docker-compose.dev.yml    # Dev override (hot reload)
  docker-compose.prod.yml   # Production override
  main.py               # Application entry point
  manage.py             # Migration CLI (Laravel-style wrapper around Alembic)
  pyproject.toml        # Python project config (ruff + mypy config)
  pytest.ini            # Pytest config
  requirements-test.txt # Test dependencies
  ruff-baseline.txt / mypy-baseline.txt / coverage-baseline.txt /
  openapi-untyped-baseline.txt   # CI ratchet baselines

Key directories

Most of your time will be spent in worker/ (business logic), shared/ (common utilities), tests/ (test suite), and alembic/ (database migrations). The mailer/ directory is for mail service configuration and rarely needs changes. There is no repo-root requirements.txt — each service pins its own in worker/<service>/requirements.txt.


Tech Stack

Component Technology Version
Language Python 3.11 (CI and containers; requires-python >= 3.11)
API framework FastAPI Pinned per service (worker/api/requirements.txt)
Database MySQL 8.0
Cache Redis 7
Vector DB Qdrant Latest
SMTP Postfix 3.x
IMAP/POP3 Dovecot 2.3+
Spam filter Rspamd Latest
Containers Docker + Docker Compose v2+
Migrations Alembic via manage.py / migrate service
Testing pytest 8.x (requirements-test.txt)
Lint/format Ruff baseline-gated in CI
Type check mypy + mypy-baseline baseline-gated in CI
Docs MkDocs Material docs/requirements.txt

Development workflow

Here's the typical flow for making a change:

flowchart LR
    A["Branch"] --> B["Write code"]
    B --> C["Write tests"]
    C --> D["Run linters"]
    D --> E["Run tests"]
    E --> F["Open PR"]
    F --> G["Code review"]
    G --> H["Merge"]
    style A fill:#4051b5,color:#fff
    style H fill:#2e7d32,color:#fff
Bash
git checkout develop
git checkout -b feature/my-new-feature

Branch naming: feature/, fix/, docs/, refactor/, test/

Make your changes in the relevant worker/ module or shared/ library. If you need a database change, create an Alembic migration.

Bash
# Fast unit tests
pytest tests/unit/

# A specific test file
pytest tests/unit/test_auth.py

# With coverage (CI ratchets the repo total — see Testing)
pytest tests/unit/ --cov=shared --cov=worker
Bash
# Format
ruff format .

# Lint (CI compares the count against ruff-baseline.txt)
ruff check .

# Type check (CI filters through mypy-baseline.txt)
bash scripts/run_mypy.sh | mypy-baseline filter

Push your branch and open a pull request. Fill in the PR template with what changed, why, and how to test it.


Common development tasks

I want to... How
Run the full stack locally ./start.sh dev — see Dev Setup
Add a new API endpoint Add a route in worker/api/routes/, see Adding Features
Create a database migration python manage.py migrate:create "description"
Build a new worker Copy an existing worker's layout, see Custom Workers
Add Prometheus metrics See Metrics Implementation
Extend Mailyte without forking See Plugin Development
Run the docs locally ./start.sh dev serves this handbook with live reload at http://localhost:8000 (the docs service — mkdocs.yml lives in docs/, so a bare mkdocs serve from the repo root does not work)
Ship a release Follow the Release Process

Guide What it covers
Getting Started Dev environment setup, running locally
Adding Features How to add a new feature end to end
Contributing PR process, branch naming, code review
Coding Standards Ruff, mypy, baseline ratchets, naming
Testing Running and writing tests
Custom Workers Building a new worker module
Plugin Development Extension points — webhooks, workers, pipeline hooks
Monitoring Integration Health checks and the shared metrics helper
Metrics Implementation Counters, gauges, histograms
Release Process Versioning, changelog, deployment

  • Getting Started -- install and run Mailyte (not dev-specific)
  • Architecture -- understand the system you're building on
  • API Reference -- the API you'll be extending
  • Features -- understand existing features before adding new ones
  • Security -- security practices to follow in your code