Email clients have a fundamental problem. They are either web interfaces controlled by the provider (Gmail, Outlook.com) or native apps that talk directly to the provider's API and store nothing locally. In both cases, the provider holds your data, controls your experience, and decides what features you get. Courier takes a different approach. It is a full-stack email proxy and client where the backend fetches and sends mail through Gmail, Fastmail, Microsoft Exchange, and generic IMAP/SMTP servers, while the frontend communicates exclusively with the Courier API. Your email never touches a third-party service that you do not control. Every message is stored durably in PostgreSQL, with the last 1,000 messages per account hot-cached in Redis for instant retrieval.

Overview

Courier is an email client built on the same FastAPI and React 19 fleet architecture as every other Renkara tool. The core architectural principle is simple: the client never communicates with email providers directly. All email operations flow through the Courier backend, which acts as a proxy to whatever provider you use. This gives us complete control over the email pipeline, including filtering, rules, transformations, and features that providers do not offer natively. Markdown composition, a programmable rules engine, snooze, scheduled send, undo send, smart folders, and LLM-powered classification all exist because the proxy architecture makes them possible.

Key Features

Markdown Composition

The compose window in Courier is a Markdown editor. You write in Markdown, with a live split-pane preview showing the rendered HTML alongside your source text. The toolbar provides formatting buttons for bold, italic, headers, lists, links, code blocks, quotes, and tables, but you can also use keyboard shortcuts or type Markdown directly. When you send, Courier transforms your Markdown into a multipart/alternative message with both plain text and HTML parts. The HTML uses an email-safe template with clean typography, responsive width, dark mode support, and properly styled code blocks. Images pasted from the clipboard upload to S3 and insert as Markdown image references. Code blocks render with syntax highlighting. The original Markdown is preserved in the database, so editing a draft brings back your source text, not a round-tripped HTML mess.

Rules Engine

Courier includes a programmable rules engine that preprocesses every incoming message through a user-defined pipeline. Rules execute in priority order and combine conditions with actions. Conditions match on any message property: sender, subject, body, attachments, size, headers, importance, or which account received the message. Conditions support exact match, contains, starts with, regex, numeric comparisons, and list membership. Condition groups can nest arbitrarily with AND/OR logic.

Actions cover everything you would expect: apply or remove labels, move to folders, archive, mark read, star, delete, forward, redirect, auto-reply with a template, snooze, block sender, send a push notification, or POST message metadata to a webhook. The stop_processing flag halts the pipeline after a rule matches, preventing subsequent rules from firing. Rules run server-side on the backend, not in the client, so they execute even when you are not looking at the app.

LLM-Powered Classification

An optional rule action sends message content to an LLM for classification. This enables sophisticated spam detection that catches what pattern matching misses, automatic categorization into user-defined buckets (receipts, travel, newsletters, personal), priority scoring based on content and sender relationship, and one-line summary generation for long messages. The LLM uses Mercury 2 for cost-effective classification. Results are stored as message metadata and become available to subsequent rules in the pipeline. The feature requires explicit user opt-in because it sends message content to an inference endpoint, and it is rate-limited to 100 classifications per hour per account.

Proxy Architecture

Courier connects to Gmail via the Gmail API, Fastmail via JMAP, Microsoft 365 via the Graph API, and generic IMAP servers via IMAP4rev1. Each provider uses its native push mechanism where available: Google Pub/Sub for Gmail, JMAP EventSource for Fastmail, Graph subscriptions for Microsoft, and IMAP IDLE for generic servers. Polling fallback runs every 2 minutes. On initial connection, Courier fetches all messages (newest first, paginated) and stores them in PostgreSQL. Attachments are extracted and stored in S3 with deduplication by SHA-256 hash. Sent messages are stored locally immediately without waiting for the provider's sent folder sync. An outbox queue manages scheduled sends and retry logic with exponential backoff.

Snooze and Scheduled Send

Snooze temporarily removes a message from the inbox and brings it back at a specified time. Preset options cover later today, tomorrow, this weekend, and next week, with a custom date and time picker for anything else. A background worker checks snoozed messages every minute and returns them to the inbox as unread when the snooze expires. Scheduled send works the other way: compose a message, pick a send time, and the outbox worker dispatches it at the right moment. Undo send provides a configurable window (5, 10, 20, or 30 seconds) after hitting send during which you can cancel the message before it actually leaves the outbox.

Threading and Conversation View

Messages group into threads by the References and In-Reply-To headers. The conversation view displays all messages in chronological order with quoted text detection and collapsing, so you see only new content by default. Inline images render in place. Attachment chips show previews with download links. Reply, Reply All, and Forward are available inline at the bottom of the conversation. Thread-level actions let you archive, delete, snooze, or mark all messages in a thread with a single click. You can mute a thread to stop notifications or split a message into a new thread.

Integration Points

Unified Inbox

Courier merges all connected accounts into a single inbox view. Color-coded account indicators show which account received each message. An account filter bar lets you show or hide specific accounts. Per-account unread badges in the sidebar give you a quick read on where attention is needed. You can also view accounts individually if the unified view gets noisy.

Fleet Architecture

Courier uses the standard Renkara fleet stack: auth-service JWT tokens, CSS Modules with custom properties for light and dark mode, React 19 + Vite + TypeScript on the frontend, FastAPI + SQLAlchemy 2.0 async on the backend. Background workers run on Celery with a Redis broker. WebSocket connections provide real-time updates: new messages appear instantly without polling the client. Smart folders (saved searches) give you dynamic views based on search criteria, functioning like virtual mailboxes that update automatically.

Advantages Over SaaS

Gmail is free but reads your email to sell advertising. Microsoft 365 costs $100 per year and locks your workflow into their ecosystem. Fastmail costs $50 per year and provides a good experience but limited programmability. Superhuman charges $30 per month for speed and keyboard shortcuts.

Courier stores every message in your own PostgreSQL instance. No advertising company reads your correspondence. No provider decides to sunset a feature you rely on. If Fastmail changes their pricing or Google alters their API, your messages are already in your database. You switch providers by updating a configuration, not by migrating years of email history. The rules engine and LLM classification layer are features that no provider offers because they require full control of the email pipeline. Courier has that control by design.

The privacy architecture is deliberate. External image loading is disabled by default to block tracking pixels. Read receipts are blocked. No analytics or telemetry runs in the client. DMARC, SPF, and DKIM status display directly in the message header so you can see at a glance whether a message is authenticated. Phishing protection highlights suspicious URLs and warns when a display name does not match known contacts.

Specifications

ComponentDetail
BackendFastAPI, SQLAlchemy 2.0 async, PostgreSQL
FrontendReact 19, Vite, TypeScript
Ports3425 (frontend), 3426 (backend)
DatabasePostgreSQL (shared RDS), `courier` database
CacheRedis/Valkey (last 1,000 messages per account, LRU eviction)
WorkersCelery + Redis broker (snooze, scheduled send, sync)
AttachmentsS3 with SHA-256 deduplication, presigned URLs
AuthBearer token via auth-service (RS256 JWT)
Email ProvidersGmail, Fastmail, Microsoft 365/Exchange, IMAP/SMTP
ComposeMarkdown with live preview, multipart/alternative on send
Rules EnginePriority-ordered pipeline, nested AND/OR conditions, 18 action types
LLM ClassificationMercury 2, opt-in, 100 classifications/hour/account
ThemesLight and dark mode via CSS custom properties