Thank you for your interest in contributing to RustMail! This document provides guidelines and instructions for contributing.
git clone https://github.com/rustmailapp/rustmail.git
cd rustmail
# Install UI dependencies
cd ui && pnpm install && cd ..
# Build everything
make build
# Or run in development mode (auto-reload)
make dev| Command | Description |
|---|---|
make dev |
Run backend + frontend in dev mode |
make build |
Production build (UI + Rust) |
make test |
Run all Rust tests |
make lint |
Clippy + TypeScript type check |
make fmt |
Format Rust + TypeScript code |
make check |
Cargo check + TypeScript check |
make clean |
Remove build artifacts |
Before filing a bug report, please check existing issues. Then use the Bug Report template — it will guide you through the required information.
feat/short-description— New featuresfix/short-description— Bug fixesrefactor/short-description— Code restructuringdocs/short-description— Documentation changes
Rust:
- Run
cargo fmtbefore committing - Zero clippy warnings:
cargo clippy --all-targets -- -D warnings - No
unwrap()in library crates (crates/rustmail-smtp,crates/rustmail-storage,crates/rustmail-api) unwrap()is acceptable in tests andrustmail-server(the binary)- Error handling:
thiserrorin libraries,anyhowin the binary - Async everywhere — no blocking calls on the tokio runtime
TypeScript (UI):
- Run
pnpm exec prettier --write .before committing - Type checking must pass:
pnpm exec tsc -b
Write atomic commits with descriptive messages:
feat: add webhook retry with exponential backoff
fix: prevent FTS5 injection via unsanitized search input
refactor: extract SMTP session handling into dedicated module
docs: add reverse proxy deployment guide
- Fork the repository and create your branch from
master - Make your changes with tests where applicable
- Ensure all checks pass:
make lint && make test - Open a pull request with a clear description of the change
- Link any related issues
- One logical change per pull request
- Tests for new functionality
- No unrelated formatting or refactoring changes
- Clear description of why the change is needed
When a PR introduces a new user-visible feature (CLI flag, API endpoint, UI capability), tick each item that applies:
- Row added to the features table in
README.md - Feature page under
docs/features/(or relevant subsection) -
docs/api.yamlupdated if the feature exposes an HTTP endpoint -
docs/configuration/cli-flags.mdupdated if a CLI flag changed - Feature card added to
rustmailapp/rustmail-www(homepage grid) if it's a headline capability - Commit message uses the
feat:Conventional Commit prefix so it shows up in the release changelog
Releases use cargo-release. Workspace config lives in Cargo.toml under [workspace.metadata.release].
master is protected (required status checks) and cannot be pushed to directly, so the flow is:
# 1. From a clean master, run the version bump.
# Bumps workspace version, refreshes Cargo.lock, commits as "chore: Release",
# creates tag v<new>, attempts to push (which will be rejected by branch protection).
cargo release patch --execute --no-confirm
# 2. Move the local commit onto a branch and reset master.
git branch chore/bump-<new>
git tag -d v<new>
git reset --hard origin/master
git push -u origin chore/bump-<new>
# 3. Open a PR, wait for CI, merge.
gh pr create --base master --head chore/bump-<new> --title "chore: bump version to <new>"
# 4. After merge, tag the merge commit and push the tag.
git fetch
git tag v<new> origin/master
git push origin v<new>The tag push triggers .github/workflows/release.yml, which builds multi-platform binaries, Docker images, and a GitHub Release with a changelog auto-generated from conventional commits since the previous tag.
Use cargo release minor or cargo release major for non-patch bumps. All workspace crates have publish = false; cargo-release skips crates.io automatically.
See the Architecture page for crate layout, data flow, and design decisions.
Adding a new dependency requires justification. Prefer:
- Well-maintained crates (recent activity, >100 stars or part of a known ecosystem)
- Crates with minimal transitive dependencies
By contributing to RustMail, you agree that your contributions will be licensed under the MIT or Apache 2.0 license, at the user's choice.