Apache James: Modular Mail Server and Mailet Platform

Apache James is an open-source mail server and also a toolkit for applications whose business logic is based on email. The name stands for Java Apache Mail Enterprise Server. James can accept and forward messages via SMTP, manage local mailboxes, expose them through IMAP, POP3, or JMAP, and control the entire message flow through freely combinable processing components. The project therefore describes itself not merely as a server, but as a modular inversion-of-control platform on the JVM (Apache James – Project Overview).

This dual role distinguishes James from traditional Mail Transfer Agents such as Postfix and from turnkey security appliances. An administrator can run James as a pure SMTP relay, a complete mailbox server, or an embedded mail engine within a product. Spam scanning, encryption, archiving, or domain-specific routing do not come from a rigid feature block, but from a pipeline of Matchers and Mailets. This makes James exceptionally adaptable, but shifts part of the product responsibility from the vendor to the operating organization.

This explanation follows a message through James: from the protocol servers through the queue and Mailet pipeline to mailbox storage. The operating variants, diagnostics, and finally the project’s technical evolution build on that foundation.

Classification: MTA, MDA, and Application Platform

Not every component in an email system has the same role. A Mail User Agent (MUA) is the user’s client, such as Thunderbird. A Mail Transfer Agent (MTA) transports messages between systems. A Mail Delivery Agent (MDA) places a message into the destination mailbox. James can serve as both MTA and MDA; through its protocol and mailbox modules, it also provides server-side services for MUAs. The official component overview lists separate projects for servers, protocols, Mailets, mailboxes, and tests (Apache James – Software Components).

RoleImplementation in JamesHandoff point
Message transportSMTP and LMTP servers, queue, Remote Delivery Mailetother MTAs, relays, and gateways
Local deliveryMailet pipeline and Mailbox APIusers, domains, and quotas
Mailbox accessIMAP, POP3, and JMAPmail clients and web applications
Filter logicMatchers, Mailets, Processors, and Sieveinternal rules and external scanning services
AdministrationWebAdmin REST API, CLI, Health Checks, and metricsautomation and monitoring

James is therefore not a mail client, nor is it a preconfigured secure mail gateway. It provides building blocks for transport, delivery, storage, and processing. Whether this becomes a simple relay, a multi-tenant mail service, or a product-specific gateway is determined by the selected distribution and configuration.

Protocols, TLS, and Ports

James provides SMTP, LMTP, IMAP, POP3, and ManageSieve as TCP-based services; JMAP and WebAdmin use HTTP (Apache James – Protocol Servers). Depending on the listener, TLS protects a connection encrypted from the start or is inserted into an existing session through StartTLS. DNS is not part of the James process, but it is essential for a public MTA: MX records determine the destination, A and AAAA records its addresses, and PTR records affect the reputation of outgoing connections.

The port number alone does not describe the security semantics. Port 25 is intended for server-to-server transport; authenticated client submission belongs on port 587 according to RFC 6409. Since RFC 8314, port 465 has again been registered for implicitly encrypted Message Submission. The same two patterns apply to IMAP and POP3: a plaintext connection with possible StartTLS, or TLS established immediately.

ServiceTypical portsStandardMeaning in James
SMTP25, 587, 465RFC 5321acceptance, relay, and submission
LMTPconfigurable, registered 24RFC 2033local handoff with status per recipient
IMAP4rev2143, 993RFC 9051synchronous mailbox access
POP3110, 995RFC 1939simple message retrieval
ManageSieve4190RFC 5804management of user-specific Sieve rules
JMAP Mailusually 443RFC 8621HTTP-based mailbox access for modern clients

The ports are configurable; the binding factor is the combination of listener, protocol, TLS mode, and authentication. The IANA Service Name and Port Number Registry remains the reference for registered assignments.

Architectural Approach

James follows a component-based architecture. Protocol servers, queue, processing logic, mailbox, user management, search index, and administration are separated from each other through APIs and assembled through dependency injection. The distributions documented for James 3.9 use Google Guice for this; the Spring setup belongs to an older generation. The decoupling is not merely code organization: it allows the same Mailbox API to be used with different persistence layers and the same Mailet logic to be used in very different server profiles.

The central data path is asynchronous. An SMTP listener does not have to deliver an accepted message completely before responding to the connection. It places a mail object into a queue; a Spooler removes it later and sends it through the Mailet container. The queue thus separates reception load, processing time, and the availability of downstream systems. The distributed operations documentation accordingly describes it as a mandatory part of an SMTP server (Apache James – Distributed Server Operations).

The Processing Path of a Message

  1. Protocol acceptance: SMTP or LMTP checks the session, authentication, envelope sender, and recipients. After the end of DATA, an internal Mail object is created with the envelope, MIME content, and attributes.
  2. Queue: The object is queued persistently or transiently. Only from this point onward are acceptance and processing decoupled.
  3. Spooler: Workers remove queue entries and hand them to the Mailet container.
  4. Processor: A named Processor contains an ordered list of Matcher/Mailet pairs. The required root Processor is the entry point.
  5. Matcher: A Matcher does not modify the message, but returns the subset of recipients for which a condition applies.
  6. Mailet: The associated Mailet modifies the message or envelope, triggers a side effect, delivers locally or remotely, or branches into another Processor.
  7. Result: The message ends up in a user mailbox, in outgoing delivery, in a Mail Repository for later handling, or is completed after a successful action.

An important detail is the recipient-specific split. If a Matcher applies only to some recipients, the container splits processing into matching and nonmatching recipient sets. Rules therefore do not necessarily apply to an entire MIME message. A Mailet can also jump directly to another Processor via ToProcessor; the pipeline is therefore more of a directed processing graph than a single linear list. The official Mailet Container documentation describes exactly this model.

A minimal, simplified pattern looks like this:

<processor state="root" enableJmx="true">
  <mailet match="RelayLimit=30" class="ToRepository">
    <repositoryPath>cassandra://var/mail/relay-denied/</repositoryPath>
  </mailet>
  <mailet match="RecipientIsLocal" class="LocalDelivery" />
  <mailet match="All" class="RemoteDelivery" />
</processor>

The order is part of the semantics. A broadly matching rule at the beginning can make subsequent rules unreachable; an infinite loop between Processors can tie up the Spooler. James therefore provides configurable error handling for each Matcher and Mailet, as well as dedicated error Processors (Mailet Container Configuration).

The component architecture becomes concrete as soon as a message reaches the queue. The Processor, Matcher, and Mailet then determine which processing steps follow and where the result goes.

Technical Structure

The architecture describes the message path; installation and operation must now translate it into a concrete component model. The decisive factor is which runtime, storage, and supporting services the selected James profile actually requires.

Technology Stack and Administration Overview

For an initial product assessment, operational boundaries matter more than class names. The following overview condenses the stack into the questions that should be clarified before installation, integration, or taking over an existing environment:

AreaTechnology or artifactWhat the administrator needs to know
RuntimeJava 21, JVM; source code primarily Java, with some Scala modulesheap, garbage collection, threading, and JVM patches are part of server operations
Build and packageMaven multi-module project; ZIPs and Docker imagescustom Mailets must match the James, Java, and Jakarta generation
WiringGuice in the 3.9 generation; Spring in older installationsthe selected distribution determines the available modules and configuration files
Configurationconf/*.xml, conf/*.properties, environment variablesespecially important: smtpserver.xml, mailetcontainer.xml, webadmin.properties, JMAP, and backend files
ProcessingMailQueue, Spooler, Processor, Matcher, Mailetacceptance, processing, and final delivery are separate states
DataPostgreSQL/JPA or Cassandra; optional S3, OpenSearch, RabbitMQsource, projection, queue, and blob content require separate recovery plans
AdministrationWebAdmin REST API and james-cliREST is more powerful; the CLI is included with every wiring variant
ObservabilityHealth Checks, Dropwizard Metrics, Prometheus, JMX, logs, Grafanaqueues, Mailets, Matchers, protocols, and backends have their own metrics
SecurityTLS keystores, SMTP AUTH, JWT for WebAdmin, network segmentationWebAdmin without enabled JWT is not protected by default

According to the project, all configuration files reside in conf or conf/META-INF; which ones actually apply depends on wiring and backend. Values can be obtained from the environment with ${env:VARIABLE} (Apache James – Configuration). This is practical for containers, but it does not replace secret management: certificates, private keys, JWT keys, and database passwords should be provided as mounted secrets or through the orchestration platform.

Protocol Layer

The Protocols project provides extensible server implementations for SMTP, LMTP, IMAP, POP3, ManageSieve, and JMAP (James Protocols). The listeners are not hardwired to a particular storage implementation. IMAP and JMAP access data through the Mailbox API; SMTP hands accepted messages to the queue and Mailet container. This allows protocols to be scaled or disabled independently of the backend topology.

Mailbox, Mail Repository, and Blob Store

James distinguishes among three storage terms that should not be conflated in operations:

StorageContentVisibilityTypical recovery
Mailboxfolders, messages, flags, UIDs, ACLs, and quotas for a userIMAP/JMAP/POP3restore or replication of the mailbox backend
Mail Repositorymessages from processing paths such as error, relay-denied, or quarantineadministration onlyfix the cause and reprocess the message
Blob Storebinary MIME content or large objectsindirectly referenced through metadataconsistent backup with metadata and references

The persistence documentation emphasizes that a Mail Repository is not the user mailbox. This separation is valuable for incident response: a faulty message can be isolated, investigated, and returned to the pipeline after a correction without bypassing the mailbox model.

Event Bus, Search, and Projections

Mailbox operations generate events, such as MailboxAdded, MessageMoveEvent, FlagsUpdated, or quota changes. Listeners use these to update quotas, search indexes, and other projections. In the distributed profile, RabbitMQ handles communication, OpenSearch handles search, and Cassandra handles metadata; binary content is stored in an S3-compatible object store. This decomposition enables horizontal scaling, but creates eventual consistency between the source and projections. Failed listener events end up in an Event Dead Letter and must be monitored and, if necessary, redelivered (Distributed James – Mailbox Event Bus).

MIME, Sieve, and Sender Authentication

The James project encompasses more than the server. Apache Mime4J parses MIME structures in a streaming manner or as an object model; jSieve implements the Sieve filtering language; jSPF and jDKIM provide Java libraries for sender verification and DKIM signing and verification, respectively. These modules are independent projects and can also be used outside a complete James server (Apache James – Components).

Which of these components run on one node or in a distributed setup is not merely a performance question. The choice also determines consistency, restart behavior, and the number of backends to monitor.

Operating Variants and Scaling

For James 3.9.0, Apache documents several profiles. They are not simply different installers, but different consistency, scaling, and operational models. In this version, the JPA variant is explicitly designated as legacy; it is joined by a PostgreSQL distribution and a distributed distribution (Apache James – Downloads). The items labeled operational inference in the infographic are derived recommendations, not literal vendor statements.

ProfilePersistence and servicesSuitable forOperational consequence
JPA/Guice (legacy)embedded H2 database or external SQL database; traditional single-server modellabs, migration of older installations, small specialized solutionsfew components, but a limited strategic path and vertical scaling
PostgreSQLPostgreSQL as the core; optional OpenSearch, RabbitMQ, and S3-compatible storagenew single-node or multi-node installations with a relational basisbackup and HA are well understood; introduce additional services only for required scaling
Distributed/GuiceCassandra, RabbitMQ, OpenSearch, and an S3-compatible object storelarge, horizontally scalable servicesmultiple failure domains, projections, Dead Letters, and more complex consistency checks
Memorytransient in-memory componentstesting and developmentno persistent production data

The 3.9 release highlights the high-performance PostgreSQL implementation as a major addition and describes it as capable of running standalone as well as scaling with RabbitMQ, OpenSearch, and S3 (Apache James 3.9.0). For new installations, this is usually the easiest starting point to understand: start with relational consistency and familiar backup procedures, then add services only for specifically measured requirements.

Security Model

James provides TLS, SMTP authentication, protocol controls, and cryptographic Mailets. However, this does not automatically result in secure production operation. Transport encryption protects one hop; it replaces neither end-to-end encryption nor mandatory recipient verification. The TLS configuration separates keystore, enabled cipher suites, StartTLS, and implicit TLS for each listener. A certificate change must therefore be tracked separately for SMTP, IMAP, POP3, and HTTP.

WebAdmin deserves special attention. The REST API can modify domains, users, mailboxes, queues, repositories, quotas, and maintenance tasks. According to the WebAdmin documentation, JWT authentication is disabled by default; without additional protection, the API must therefore never be reachable from an uncontrolled network. Health endpoints and API documentation may also intentionally remain outside authentication.

Minimum production hardening includes:

  • binding WebAdmin to a management network, enabling JWT, and further restricting access through a firewall or reverse proxy;
  • preventing open relays through explicit relay, authentication, and recipient rules;
  • operating submission and server-to-server SMTP on separate listeners with different policies;
  • removing demo domains, sample users, and default passwords from container images before the first external start;
  • managing private keys outside the container layer and monitoring expiration dates;
  • treating custom Mailets as application code: review dependencies, run tests, and limit runtime permissions;
  • deliberately designing spam and malware scanning. James is a platform; external scanners and reputation services are integrated through Mailets or protocol handoffs.

For troubleshooting, the message path is checked again in the same order: listener, queue, Mailet pipeline, repository, mailbox, and outgoing delivery.

Operations and Troubleshooting

With a modular mail server, “the service is running” is not a sufficient statement of state. WebAdmin Health Checks distinguish healthy, degraded, and unhealthy; in strict mode, even a degraded component results in HTTP 503. Depending on the profile, checks include JPA or Cassandra, OpenSearch, RabbitMQ, the Guice lifecycle, Event Dead Letters, and a complete test delivery (WebAdmin Health Checks).

For diagnostics, a layered approach is more efficient than a global log search:

  1. Connection: Does the client reach the correct listener, and does TLS succeed with the expected certificate and hostname?
  2. SMTP transaction: Which response code was returned for MAIL FROM, RCPT TO, and DATA? A 250 after DATA means acceptance, not necessarily final delivery.
  3. Queue: Is the number of queued entries growing, is their age increasing, or is the same remote error recurring?
  4. Mailet pipeline: Which Processor and which Matcher/Mailet pair handled the message? The mail ID serves as the correlation key.
  5. Repository: Is the message in error, address-error, relay-denied, or a custom repository? Fix the cause before reprocessing.
  6. Mailbox and events: Is the message present in the authoritative mailbox store but missing from the search index or JMAP? Then listeners, Dead Letters, and reindexing are more relevant than SMTP.
  7. Remote Delivery: For outgoing delivery, check DNS, route, TLS, peer response code, retry plan, and bounce generation separately.

A compact synthetic check can connect the administration and data planes:

$headers = @{ Authorization = "Bearer $env:JAMES_ADMIN_JWT" }
Invoke-RestMethod `
  -Uri "https://james-admin.example.net/healthcheck?strict" `
  -Headers $headers

On Windows, Invoke-RestMethod calls the REST endpoint; on Linux and Unix, curl performs the same HTTP check. Both commands test only the documented WebAdmin Health Check here and do not replace a synthetic SMTP or mailbox transaction.

In addition, at minimum, alert on queue depth and age, error repositories, Event Dead Letters, OpenSearch indexing lag, backend latencies, SMTP response classes, JVM memory, and certificate expiration periods. In the distributed variant, a healthy James process while RabbitMQ or OpenSearch is impaired is only a partial success.

Tools for the Administrator Workstation

James includes a command-line client for domains, users, mailboxes, mappings, quotas, and reindexing; in Guice containers, it is available as james-cli (James CLI). A reliable diagnostic setup should also include several protocol-neutral tools on the administrator workstation:

ToolUse with James
swakscomplete SMTP and submission transaction with AUTH, TLS, envelope, and freely set headers
openssl s_clientcheck certificate chain, SNI, cipher, and StartTLS on SMTP, IMAP, or POP3
curl and jqquery WebAdmin, Health Checks, tasks, and metrics automatically
dig or Resolve-DnsNamecheck MX, A/AAAA, PTR, SPF, DKIM, and DMARC
tcpdump or Wiresharkdistinguish handshakes, retransmits, connection drops, and protocol dialogs
Prometheus and Grafanamonitor queue and protocol metrics, latency percentiles, Mailet/Matcher runtimes, and backend states
JMX, VisualVM, and jcmdinvestigate heap, threads, garbage collection, and JVM-internal metrics

The native metrics documentation lists active SMTP, IMAP, and LMTP connections, queue entries, sent and delivered messages, response times per protocol, and runtimes of individual Mailets and Matchers, among other metrics. These metrics are more meaningful than a single process uptime because they reflect the path of a message through the architecture.

Technical History

James did not originate as a port of an existing Unix MTA. The oldest surviving project pages from 1997/1998 initially describe a planned Java server that was not yet usable, based on shared packages from the Java Apache Project. It envisioned a shared protocol interface, JDBC storage, and a MailServlet interface modeled after Servlets; the Apache JServ environment provided technical groundwork (James 1.0 Archive). The later Mailet API preserved the core idea of small, deployable processing components without becoming part of the Java Servlet specification.

PeriodTechnical development step
1997–1998Design in the Java Apache Project: pure Java server, shared protocol and resource interfaces, MailServlet concept
February 2001Migration from the Java Apache Project to the Jakarta project (Jakarta News 2001)
James 1.x/2.xstable SMTP/POP3 server, temporarily NNTP; Mailet engine, file and RDBMS storage; Avalon/Phoenix component container (Document Archive)
early 2000srise from a Jakarta subproject to an independent Apache Software Foundation top-level project (James 2.1.3 – archived project page)
2010James 3.0 M1 with full IMAP support, SMTP/LMTP, revised Mailet API, and Maildir, JPA, and JCR storage (Release Announcement)
James 3.xreplacement of Avalon/Phoenix by Spring and later a strategic move toward Guice; expansion of IMAP, JMAP, REST administration, and distributed backends
September 2025James 3.9.0: transition from javax to jakarta, Java 21, and new PostgreSQL implementation (Release Announcement)

The source code resides in the official apache/james-project repository. The 3.9 generation considered here consists primarily of Java; some modules use Scala. It is built as a large Maven multi-module project. Its long history explains why multiple generations remain visible in documentation and installations: Phoenix and Spring terms in older texts, Guice in the 3.x documentation, JPA as a legacy path, and PostgreSQL or Cassandra profiles for distributed deployments.

Suitability and Limitations

James is especially suitable when email is part of an application rather than merely infrastructure: rule-based processing, custom Mailets, open protocols, JMAP, controllable data storage, or horizontal scaling without a proprietary server core. The public APIs allow transport, mailbox, and business logic to evolve independently.

James is less suitable for organizations expecting a turnkey appliance with a complete GUI, preconfigured spam and malware protection, vendor SLAs, and a single backup object. Modular freedom creates integration work. The distributed profile in particular requires operational experience with multiple data systems and a clear definition of source, projection, rebuild, and recovery point.

The key architectural question is therefore: Should email be operated as a configurable protocol system or as a finished product? For the former, James provides an unusually deep and open toolkit. For the latter, a more heavily preconfigured product is often more economical.

Sources

New posts by email

Selected posts on messaging, security and M365. No spam. Unsubscribe anytime.

Only for the newsletter. No spam, one-click unsubscribe. Privacy

Enlarged infographic