Ubuntu 22.04 安装 Apache James 3.9.1 指南

在 Ubuntu 22.04 上从零部署 Apache James 3.9.1(JPA+Guice 单机版)邮件服务器,含 JDK 21 安装、官方发行下载校验、keystore 生成、POP3 启用、JVM 堆限、SMTP/POP3/IMAP 收发实测与持久化验证,已实测通过。

Apache JamesApache James安装部署JavaApacheUbuntu 22.042026/10/11

Ubuntu 22.04 安装 Apache James 3.9.1 指南

目标:在 Ubuntu 22.04 上从零部署 Apache James(Java Apache Mail Enterprise Server)3.9.1 邮件服务器,打通 SMTP/IMAP/POP3 三协议收发,并完成 JVM 堆限制与数据持久化验证。本文已在 Ubuntu 22.04.5 LTS 真实服务器实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • 运行架构:x86_64,6 核,48GB 内存
  • JDK:OpenJDK 21(21.0.12.1,对应 Ubuntu 包 openjdk-21-jdk-headless)
  • Apache James:3.9.1(发行物 james-server-jpa-guice.zip,Guice + JPA 单机版)
  • 部署目录:/opt/data/james/james-server-jpa-guice
  • 数据目录:/opt/data/james/james-server-jpa-guice/var(含 mail 邮件体、store/derby 数据库)
  • 默认监听端口:SMTP 25/465/587、IMAP 143/993、POP3 110、WebAdmin 8000、JMX 9999
  • 管理方式:WebAdmin REST API + 命令行工具 james-cli(基于 JMX)
  • 管理账号:root@example.com / admin@example.com,密码均为 q1w2e3r4

二、前置条件

以 root 身份执行,或确保当前用户拥有 sudo 权限。本节安装基础工具与 JDK。

2.1 更新软件源

apt-get update

回显末尾:

Reading package lists... Done

2.2 安装基础工具

apt-get install -y curl wget ca-certificates unzip

安装完成后校验:

curl --version | head -1
wget --version | head -1

2.3 安装 JDK 21 并配置 JAVA_HOME

Apache James 3.9.1 官方要求 Java 21 SDK(见发行物 README.adoc)。安装:

apt-get install -y openjdk-21-jdk-headless

设置环境的 JAVA_HOME(写入 /etc/profile 以便开机自动生效):

echo 'export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64' >> /etc/profile
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile
source /etc/profile

💡 说明:若服务器本身已有多个 JDK,务必保证 /usr/lib/jvm/java-21-openjdk-amd64/bin/java 是环境中使用的那个;也可通过 update-alternatives --config java 手动指定。

校验版本与 JAVA_HOME:

java -version
readlink -f $(which java)
$JAVA_HOME/bin/java -version

实测回显:

openjdk version "21.0.12.1" 2026-08-18
OpenJDK Runtime Environment (build 21.0.12.1+1-1-22.04.4-Ubuntu)
OpenJDK 64-Bit Server VM (build 21.0.12.1+1-1-22.04.4-Ubuntu, mixed mode, sharing)
/usr/lib/jvm/java-21-openjdk-amd64/bin/java

三、版本选型说明

Apache James 当前在 Apache 官方下载站 downloads.apache.org/james/server/ 提供多个版本目录。实测查询到 3.7.6 / 3.8.2 / 3.9.0 / 3.9.1(其中 3.9.1 为最新发布)。

各版本目录下提供的发行物形态(zip):

发行物 zip场景数据后端
james-server-jpa-guice.zip单机部署(推荐,即需即用)内置 Apache Derby(JPA)
james-server-distributed-guice.zip分布式集群部署需外接 Cassandra/RabbitMQ 等
james-server-postgres-app.zip单机 + PostgreSQL 后端PostgreSQL
james-server-spring-app-<ver>-app.zipSpring 版视配置
james-project-<ver>-source-release.zip源码编译安置-

💡 建议:做单机 0→1 邮件服务器实测选 james-server-jpa-guice.zip,其内置 Derby 数据库,无需额外安装数据库软件即可启动,最适合入门与验证。

四、部署步骤(官方 zip 安装方案)

4.1 创建部署目录并下载发行包

mkdir -p /opt/data/james
cd /opt/data/james
wget https://downloads.apache.org/james/server/3.9.1/james-server-jpa-guice.zip

下载完成回显:

download ok
-rw-r--r-- 1 root root 101131562 Oct  5 20:10 james-server-jpa-guice.zip

4.2 校验 SHA512 完整性

Apache 官方在每份发行物旁提供 .sha512 校验文件。下载并比对:

curl -s https://downloads.apache.org/james/server/3.9.1/james-server-jpa-guice.zip.sha512
sha512sum james-server-jpa-guice.zip

实测两次输出完全一致:

4e13ecc53916e2e0e8124db9f1cc512bf8dfd1dd71f252637314df5cdb4b43a6c3b9da28e30e579ba2b1e347304485692fbd68f6e7f7571a5f7b6faa3e4ee19a  james-server-jpa-guice.zip
4e13ecc53916e2e0e8124db9f1cc512bf8dfd1dd71f252637314df5cdb4b43a6c3b9da28e30e579ba2b1e347304485692fbd68f6e7f7571a5f7b6faa3e4ee19a  james-server-jpa-guice.zip

⚠️ 注意:校验值逐日保持稳定,若你下载的是更新版本文档,请以官方 .sha512 文件为准,切勿硬编码。

4.3 解压发行包

cd /opt/data/james
unzip -q james-server-jpa-guice.zip

解压后目录结构:

/opt/data/james/james-server-jpa-guice/
├── conf/                      # 全部配置文件
├── extensions-jars/           # WebAdmin 扩展 jar 放置目录
├── james-server-jpa-app.jar   # 主启动 fat-jar
├── james-server-jpa-app.lib/  # 依赖库(含 openjpa agent)
├── LICENSE
└── README.adoc

4.4 生成 TLS keystore

James 的 SMTP/IMAP/POP3 的 TLS 配置默认引用 conf/keystore(类型 PKCS12,密码 james72laBalle,见 conf/smtpserver.xml 等文件)。生成 keystore:

cd /opt/data/james/james-server-jpa-guice
keytool -genkey -alias james -keyalg RSA -storetype PKCS12 -keystore conf/keystore -storepass james72laBalle -dname "CN=mail.example.com, OU=IT, O=Example, L=Beijing, ST=Beijing, C=CN" -validity 3650

实测回显:

Generating 3,072 bit RSA key pair and self-signed certificate (SHA384withRSA) with a validity of 3,650 days
        for: CN=mail.example.com, OU=IT, O=Example, L=Beijing, ST=Beijing, C=CN

生成后校验文件存在:

ls -la conf/keystore
# -rw-r--r-- 1 root root 3558 Oct 11 11:12 conf/keystore

⚠️ 注意:<keystore>、<secret> 必须与 keystore 的实际 -storepass 一致(此处均为 james72laBalle),否则 TLS 服务启动会失败。

4.5 启用 POP3 服务(可选)

发行包默认 conf/pop3server.xml 中 POP3 为 enabled="false",仅 IMAP/SMTP 默认启用。若需 POP3 110 端口,改为启用:

sed -i 's/<pop3server enabled="false">/<pop3server enabled="true">/' conf/pop3server.xml
grep -n "enabled" conf/pop3server.xml | head -2

实测修改后回显:

24:    <pop3server enabled="true">

4.6 固定 WebAdmin 密码

WebAdmin 默认 password.generate=true(每次启动生成随机密码并写进日志),为便于管理可固定密码(示例使用 q1w2e3r4):

sed -i 's/^password.generate=true/password.generate=false/' conf/webadmin.properties
sed -i 's/^#password=secret1,secret2/password=q1w2e3r4/' conf/webadmin.properties
grep -nE "password" conf/webadmin.properties

实测修改后回显(关键行):

57:password.generate=false
60:password=q1w2e3r4

4.7 启动 James 服务(含 JVM 堆限制)

James 的启动命令以 java -jar james-server-jpa-app.jar 运行(其 README 提供了标准启动参数)。为符合服务器资源规划,将 JVM 堆限制在 256–512MB:

cd /opt/data/james/james-server-jpa-guice
nohup $JAVA_HOME/bin/java -Xms256m -Xmx512m \
  -javaagent:james-server-jpa-app.lib/openjpa-4.1.1.jar \
  -Dworking.directory=. \
  -Djdk.tls.ephemeralDHKeySize=2048 \
  -Dlogback.configurationFile=conf/logback.xml \
  -jar james-server-jpa-app.jar > /var/log/james.log 2>&1 &

💡 说明:-javaagent:james-server-jpa-app.lib/openjpa-4.1.1.jar 是 James 处理 JPA 增强的必需参数。后台运行的日志重定向到 /var/log/james.log,便于排障。 ⚠️ 注意:SMTP 端口 25、POP3 110 等低于 1024 的端口需要 root 权限绑定,请以 root 运行(官方 README 明确提示 "binding ports below 1024 requires administrative rights")。

等待启动完成后查看关键日志:

grep -E "Service bound|JAMES server started|StartUpChecks" /var/log/james.log

实测回显:

11:12:48.451 [INFO ] o.a.j.p.l.n.AbstractConfigurableAsyncServer - IMAP Service bound to: 0.0.0.0:143
11:12:48.490 [INFO ] o.a.j.p.l.n.AbstractConfigurableAsyncServer - IMAP Service bound to: 0.0.0.0:993
11:12:48.999 [INFO ] o.a.j.p.l.n.AbstractConfigurableAsyncServer - SMTP Service bound to: 0.0.0.0:25
11:12:49.003 [INFO ] o.a.j.p.l.n.AbstractConfigurableAsyncServer - SMTP Service bound to: 0.0.0.0:465
11:12:49.008 [INFO ] o.a.j.p.l.n.AbstractConfigurableAsyncServer - SMTP Service bound to: 0.0.0.0:587
11:13:13.320 [INFO ] o.a.j.p.l.n.AbstractConfigurableAsyncServer - POP3 Service bound to: 0.0.0.0:110
11:12:49.637 [INFO ] o.a.j.w.j.EmbeddedJettyServer - >> Listening on 127.0.0.1:8000
11:12:49.861 [INFO ] o.a.j.StartUpChecksPerformer - StartUpChecks all succeeded
11:12:49.861 [INFO ] o.a.j.GuiceJamesServer - JAMES server started in: 9136ms

五、验证 JVM 堆限制生效

使用 jps -v 查看 James 进程的 JVM 参数,确认 -Xms256m -Xmx512m 已生效:

$JAVA_HOME/bin/jps -v | grep james-server

实测回显:

7577 james-server-jpa-app.jar -Xms256m -Xmx512m -javaagent:james-server-jpa-app.lib/openjpa-4.1.1.jar -Dworking.directory=. -Djdk.tls.ephemeralDHKeySize=2048 -Dlogback.configurationFile=conf/logback.xml

💡 说明:从输出可见初始堆 -Xms256m、最大堆 -Xmx512m 均按预期生效。若需要调整,改启动命令行中的 -Xms/-Xmx 即可(如 -Xms256m -Xmx256m)。

六、配置说明

  • 配置文件全部位于 conf/ 目录,改完需重启 James 生效。
  • 关键文件与作用:
文件作用
smtpserver.xmlSMTP 服务、端口、TLS、认证(默认 25/465/587)
imapserver.xmlIMAP 服务、端口、TLS(默认 143/993)
pop3server.xmlPOP3 服务、端口、TLS(默认 110,需自行启用)
lmtpserver.xmlLMTP 服务(默认禁用,绑定 127.0.0.1:24)
mailetcontainer.xml邮件处理管道(mailet)流程配置
domainlist.xml本地有效域名列表
usersrepository.xml用户存储配置
james-database.properties数据库连接配置(默认 Derby)
jvm.properties额外 JVM 系统属性和杂项开关
webadmin.propertiesWebAdmin REST API 端口、密码认证与 HTTPS
jmx.propertiesJMX 开关与端口(默认 9999)
logback.xml日志级别与输出配置
  • 数据目录为 var/:var/mail/ 存放各邮件仓库(error/relay/address-error 等),var/store/derby 为 Derby 数据库(用户、域名、邮箱元数据)。

七、创建域名与用户并验证收发

7.1 创建域名

James 管理主推 WebAdmin REST API(默认 127.0.0.1:8000,密码为上一步固定的 q1w2e3r4),认证使用请求头 Password:

curl -s -XPUT \
  -H "Password: q1w2e3r4" \
  -H "Accept: application/json" \
  http://127.0.0.1:8000/domains/example.com \
  -w "\nHTTP_CODE=%{http_code}\n"

实测回显(HTTP 204 = 创建成功):

HTTP_CODE=204

列出域名验证:

curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/domains

实测回显:

["example.com","localhost"]
HTTP_CODE=200

7.2 创建用户

curl -s -XPUT \
  -H "Password: q1w2e3r4" \
  -H "Content-Type: application/json" \
  -d '{"password":"q1w2e3r4"}' \
  http://127.0.0.1:8000/users/root@example.com \
  -w "\nHTTP_CODE=%{http_code}\n"

实测回显(HTTP 204 = 创建成功):

HTTP_CODE=204

创建第二个用户 admin(示例管理账号之一):

curl -s -XPUT \
  -H "Password: q1w2e3r4" \
  -H "Content-Type: application/json" \
  -d '{"password":"q1w2e3r4"}' \
  http://127.0.0.1:8000/users/admin@example.com \
  -w "\nHTTP_CODE=%{http_code}\n"

列出用户验证:

curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/users

实测回显:

[{"username":"root@example.com"},{"username":"admin@example.com"}]
HTTP_CODE=200

7.3 用 Python smtplib 发信(SMTP)

python3 -c "
import smtplib
from email.mime.text import MIMEText
msg = MIMEText('Hello from James test', 'plain', 'utf-8')
msg['Subject'] = 'James SMTP test'
msg['From'] = 'root@example.com'
msg['To'] = 'admin@example.com'
s = smtplib.SMTP('127.0.0.1', 25, timeout=15)
s.sendmail('root@example.com', ['admin@example.com'], msg.as_string())
s.quit()
print('SENT root to admin')
"

实测关键回显(250 2.6.0 Message received 表示收下):

reply: b'250 2.6.0 Message received'
SENT root to admin

可在日志确认投递成功:

grep -E "Local delivered|spooled" /var/log/james.log | tail -2

实测回显:

11:17:27.752 [INFO ] o.a.j.t.m.d.SimpleMailStore - Local delivered mail Mail1791717447548-J5s4r4Pm7RNHSpoUL1pN with messageId null successfully from root@example.com to <admin@example.com> in folder [INBOX] with composedMessageId ComposedMessageId{mailboxId=2, messageId=DefaultMessageId{}, uid=MessageUid{uid=1}}

7.4 用 POP3 收信

POP3 认证需使用完整邮箱名(含域名):

python3 -c "
import poplib
m = poplib.POP3('127.0.0.1', 110, timeout=15)
print(m.getwelcome())
print(m.user('admin@example.com'))
print(m.pass_('q1w2e3r4'))
num, size = m.stat()
print('STAT: %d messages, %d bytes' % (num, size))
m.quit()
"

实测回显:

+OK <动态消息ID,实测如 02765503.1791718067103@7e0efb73a715> POP3 server (JAMES POP3 Server ) ready
USER: b'+OK'
PASS: b'+OK Welcome admin@example.com'
STAT: 1 messages, 565 bytes

⚠️ 注意:POP3 的 USER 必须用 root@example.com(带域名)而不是 root,否则 James 返回 -ERR Authentication failed.(日志显示 Could not retrieve user Username{localPart=root, domainPart=Optional.empty})。

7.5 用 IMAP 收信

发行包默认 IMAP 明文登录被禁用(LOGINDISABLED),需先建立 STARTTLS 再登录:

python3 -c "
import imaplib
c = imaplib.IMAP4('127.0.0.1', 143, timeout=15)
c.starttls()
print(c.login('root@example.com', 'q1w2e3r4'))
print(c.select('INBOX'))
print(c.search(None, 'ALL'))
c.logout()
"

实测回显:

('OK', [b'LOGIN completed.'])
('OK', [b'1'])
('OK', [b'1'])

💡 说明:若直接 c.login() 不带 STARTTLS,会返回 LOGIN failed. Plain login / authentication are disabled.,这是 James 的安全默认策略,属预期行为。

八、数据持久化验证

重启 James,确认已创建的域名、用户仍然存在(数据落在 var/ 目录,非内存态):

$JAVA_HOME/bin/jps -l | grep "james-server-jpa-app.jar" | awk '{print $1}' | xargs -r kill
sleep 5
$JAVA_HOME/bin/jps -l | grep jpa | wc -l   # 返回 0,表示进程已退出

重新启动后,用 WebAdmin 或命令行工具查询:

curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/domains
curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/users

实测重启后回显(用户与域均保留):

["example.com","localhost"]
[{"username":"root@example.com"},{"username":"admin@example.com"}]

💡 结论:James 将 Derby 数据库与邮件数据持久化到 var/ 目录,重启不丢用户与域名。

九、注意事项

  • 端口限制:25/110 等 <1024 端口须 root 运行;若安全组受限,可改 smtpserver.xml/pop3server.xml/imapserver.xml 中的 <bind> 到高端口并重启。
  • WebAdmin 认证:REST 请求用 Password 请求头(而非 Basic Auth)。若放开 host=localhost 为 0.0.0.0,务必开启 HTTPS 或妥善保护。
  • JMX:默认 jmx.port=9999、用户名 james-admin、密码每次启动自动生成(写于 var//. 启动日志 与 jmxremote.password 文件中)。命令行工具 james-cli 依赖它。
  • POP3 默认关闭:发行包默认 POP3 禁用,需手动开启。
  • JVM 堆:默认未显式限堆,务必按 4.7 节加上 -Xms256m -Xmx512m。

十、常见问题(FAQ)

Q1:启动后 110 端口不监听? POP3 默认禁用。按 4.5 节把 pop3server.xml 的 enabled 改为 true 后重启即可。日志核实:应出现 POP3 Service bound to: 0.0.0.0:110。

Q2:WebAdmin 返回 No Password header. / HTTP 401? 你用了 Basic Auth(--user)而非 James 的密码头。应改为在请求中带 -H "Password: <密码>"(见 4.6 固定密码与 7.1 用法)。若密码未固定则随机,去启动日志查询。

Q3:IMAP 登录报 LOGINDISABLED / Plain login ... disabled? James 安全默认禁止明文认证。用 IMAP STARTTLS 后再 login(见 7.5),或改用内部受信网络并调整相关 TLS 策略。

Q4:POP3 报 Authentication failed? POP3 的 USER 需用带域名的完整邮箱(root@example.com),单纯 root(local-part)会认证失败。

Q5:启动报 TLS/keystore 相关错误? keystore -storepass 与 smtpserver.xml 等文件的 <secret> 不一致,或 keystore 不存在。按 4.4 用 james72laBalle 重新生成并放置到 conf/keystore。

十一、卸载方式

# 1. 停止服务(按 JVM 进程终止)
$JAVA_HOME/bin/jps -l | grep "james-server-jpa-app.jar" | awk '{print $1}' | xargs -r kill

# 2. 删除解压目录与数据
rm -rf /opt/data/james/james-server-jpa-guice

# 3. 可选:删除下载的压缩包
rm -f /opt/data/james/james-server-jpa-guice.zip

# 4. 可选:卸载 JDK
apt-get purge -y openjdk-21-jdk-headless

十二、参考链接