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 收发实测与持久化验证,已实测通过。
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、IMAP143/993、POP3110、WebAdmin8000、JMX9999 - 管理方式: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.zip | Spring 版 | 视配置 |
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.xml | SMTP 服务、端口、TLS、认证(默认 25/465/587) |
imapserver.xml | IMAP 服务、端口、TLS(默认 143/993) |
pop3server.xml | POP3 服务、端口、TLS(默认 110,需自行启用) |
lmtpserver.xml | LMTP 服务(默认禁用,绑定 127.0.0.1:24) |
mailetcontainer.xml | 邮件处理管道(mailet)流程配置 |
domainlist.xml | 本地有效域名列表 |
usersrepository.xml | 用户存储配置 |
james-database.properties | 数据库连接配置(默认 Derby) |
jvm.properties | 额外 JVM 系统属性和杂项开关 |
webadmin.properties | WebAdmin REST API 端口、密码认证与 HTTPS |
jmx.properties | JMX 开关与端口(默认 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
十二、参考链接
- Apache James 官方站:https://james.apache.org/
- 发行包目录:https://downloads.apache.org/james/server/
- James 后台运维(CLI/WebAdmin):https://james.apache.org/server/manage-cli.html
- JPA-Guice 版说明(官方 README):https://github.com/apache/james-project/tree/master/server/apps/jpa-app