Apache James: Build a Mail Server From Parts, Not From Scratch
Project brief: Emails at the heart of your business logic. Create your *own personal solution* for emails treatment by assembling the components you need thanks to the Inversion of Control mail platform offered and go further customizing filtering and routing rules using *James Mailet Container*.
At a glance
- What is it?
- Apache James is a JVM mail platform that assembles SMTP, IMAP, JMAP, and POP3 from interchangeable components. This review covers how the Mailet Container works, what the demo Docker image gets you, and where the project's flexibility becomes a cost.
- Who is it for?
- Adopt Apache James if you need a self-hosted mail server on the JVM and you are willing to learn its component model, especially the Mailet Container and Guice wiring. Do not adopt it if you want a turnkey appliance with a simple config file, because the distributed variant pulls in Cassandra, S3, OpenSearch, and RabbitMQ, and even the demo requires Docker.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What James Actually Solves
Most mail servers ship as a fixed bundle: you get the MTA, the delivery agent, and the storage, and you configure them within preset limits. James takes the opposite route. It is a Java platform where you assemble the mail handling pipeline from components. The README says it directly: create your own personal solution for emails treatment by assembling the components you need thanks to the Inversion of Control mail platform. The target user is a Java developer or a team that wants to embed mail logic into a larger application, not an administrator who wants to point and click. James gives you SMTP, IMAP, JMAP, POP3, and more, but the value is not the protocol list. The value is that you can replace storage backends, add custom filtering, and route messages through your own code without forking the server.
The Mailet Container Is the Core Mechanism
The README names the James Mailet Container as the way to go further customizing filtering and routing rules. A mailet is a small Java class that processes a message as it moves through the server. The container holds a chain of these mailets, and each one can inspect, modify, reject, or forward a message. This is a pipe-and-filter architecture. The container is wired with Inversion of Control, which in practice means Guice modules define which components exist and how they connect. The README mentions that the docker distributions are based on Guice applications. So the flow is: a message arrives via SMTP, the mailet chain runs, and the final mailet delivers to storage or forwards elsewhere. This is not a new idea, but James makes it the primary extension point. If you need a custom spam check or a specific header rewrite, you write a mailet and insert it into the chain. The documentation and examples in the repository show this pattern, though the README itself only points to the examples directory.
Try It in One Docker Command
The quickest path to a running James is the demo image. The README gives a single command: docker run -p "465:465" -p "993:993" apache/james:demo-3.8.0. That image uses JPA with hsqldb for storage and Lucene for indexing. It ships with a default domain james.local and three users, user01, user02, and user03, all with password 1234. The server listens on IMAPS port 993 and SMTPS port 465. You can connect with Thunderbird right away. This is a real advantage: you can have a working mail server in minutes without building anything. The demo is intentionally small and in-memory, so it is not a production deployment. It is a way to see the protocols work and to start writing mailets against a live server.
Building From Source Requires Patience
If you want to modify James itself, the build is a Maven project. The README states you need Maven 3.6.1 minimum and JDK 11. The command is mvn clean install in the cloned repository. The README warns that the test suite is long and resource consuming, and it requires a docker daemon. You can skip tests with -DskipTests, parallelize with -T 4, and skip javadoc with -Dmaven.javadoc.skip=true. The project has parts written in Scala, so an IDE with Scala support is recommended. This is a heavy build. The repository is large, and the modularity means many submodules. Expect the first build to take a long time even with tests skipped. This is not a project you casually compile on a laptop. The build is a real barrier for contributors, and the README does not hide that.
Four Deployment Shapes, Four Different Operational Profiles
James does not ship as one server. The README lists four Guice-based applications: memory-app for testing, jpa-app with JPA and Lucene, cassandra-app with Cassandra and OpenSearch, and distributed-app with Cassandra, RabbitMQ, S3, and OpenSearch. The memory app is for tests only. The JPA app is the demo default. The Cassandra app adds a real database but still runs on one node. The distributed app is the one the README calls easy-to-operate and scalable, but it requires four external systems. Each shape has its own README and its own configuration. This is both the strength and the weakness of James. You can choose the right size for your workload, but you must learn the specifics of each. The distributed app is not a single binary; it is a composition of infrastructure. If you do not already run Cassandra and RabbitMQ, the operational cost is significant.
Where the Modularity Bites
The Inversion of Control approach has a cost. The README says you can assemble components, but it does not give a quick reference for which components exist or how to wire them. The documentation is spread across the website, the staged docs, and the examples directory. For a newcomer, the first task is not writing a mailet, it is understanding the Guice module structure. The README points to examples but does not explain them. Also, the demo image uses a default domain and default passwords, which is fine for trying, but it means the first thing you must do in a real deployment is change those. The README does not mention a default configuration file path or an environment variable to override the domain. You have to dig into the server app READMEs. Another limitation is that James is JVM-only. If your team is not comfortable with Java and Maven, the learning curve is steep. The Scala parts add another layer.
The Real Alternative: A Traditional MTA vs. James
The obvious alternative is a traditional MTA like Postfix or Exim, often paired with Dovecot for IMAP. Those tools are written in C and configured through text files. They are proven, widely deployed, and have huge communities. The difference in approach is fundamental: Postfix gives you a fixed pipeline with configuration directives, while James gives you a programmable pipeline where the logic is Java code. With Postfix, you customize behavior through lookup tables and policy services, but the core flow is fixed. With James, you can replace storage, add a mailet that calls your internal API, or even implement a new protocol. If your requirement is a standard mail server with minimal custom logic, Postfix and Dovecot are simpler and have far more operational guides. If your requirement is to embed mail processing into a Java application or to build a custom mail service, James is the better fit.
Maintenance, License, and the Upgrade Path
James is an Apache project with Apache-2.0 license, which means you can use it commercially without a copyleft obligation. The README does not give a release cadence or a changelog, and the repository shows no recent releases in the provided data. The latest version mentioned is 3.8.0, and the documentation links point to staged versions, which suggests the docs are updated for upcoming releases. The project has been around for a long time, and it is not archived, so maintenance is ongoing. But the upgrade cost is real: because you assemble components, a new version may change the Guice modules or the mailet API. The README does not provide a migration guide. You should check the ADRs and the documentation before upgrading. The build also requires a docker daemon for tests, so your CI pipeline must support that. Overall, the license is permissive, but the operational and upgrade burden is on you.
Editorial conclusion
Adopt Apache James if you need a self-hosted mail server on the JVM and you are willing to learn its component model, especially the Mailet Container and Guice wiring. Do not adopt it if you want a turnkey appliance with a simple config file, because the distributed variant pulls in Cassandra, S3, OpenSearch, and RabbitMQ, and even the demo requires Docker. Before committing, verify that your target deployment (memory, JPA, Cassandra, or distributed) has the exact protocol and storage mix you need, and check the current documentation for the version you plan to run, since the README points to staged docs and the latest release shown is 3.8.0.
Community notes