Apache James 常用 CLI 命令与工具详解

详解 Apache James 3.9.1 常用 CLI 命令与工具,包括基于 JMX 的命令行工具 james-cli 全部命令列表、用法与实测回显(域/用户/邮箱/配额/映射/垃圾名单),以及 WebAdmin REST API 与 Python 客户端测试工具,已实测通过。

Apache JamesApache JamesJavaApache运维2026/10/11

Apache James 常用 CLI 命令与工具详解

目标:详解 Apache James 3.9.1(james-server-jpa-guice 单机版)的管理命令与工具:命令行工具 james-cli(基于 JMX)、WebAdmin REST API、以及 SMTP/POP3/IMAP 的 Python 测试脚本。所有命令与回显来自 Ubuntu 22.04.5 真实服务器实测。

一、环境信息

  • 版本:Apache James 3.9.1(james-server-jpa-guice.zip)
  • 部署目录:/opt/data/james/james-server-jpa-guice
  • JDK:OpenJDK 21($JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64)
  • CLI 实现 jar:james-server-jpa-app.lib/james-server-cli-3.9.1.jar(主类 org.apache.james.cli.ServerCmd)
  • JMX:127.0.0.1:9999,用户 james-admin,密码见 conf/jmxremote.password
  • WebAdmin REST:127.0.0.1:8000,认证请求头 Password
  • 实测域名:example.com;实测用户:root@example.com、admin@example.com(密码 q1w2e3r4)

二、工具概览

工具接入方式用途前提
james-cli(ServerCmd)JMX(9999)域/用户/邮箱/配额/映射/垃圾名单管理服务已启动、JMX 密码
WebAdmin REST APIHTTP(8000)域/用户/邮箱管理、健康检查服务已启动、Password 头
Python 客户端(smtplib/poplib/imaplib)SMTP 25 / POP3 110 / IMAP 143收发实测与集成测试用户已创建

💡 说明:James 3.x(Guice 架构)起官方推荐的自动化管理接口是 WebAdmin REST API;命令行 james-cli 仍随发行附带,通过 JMX 通道执行同等操作。两者功能互补,本文分别给出实测用法。

三、前置条件

  1. 服务已启动。若尚未启动,在部署目录执行:
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 &
  1. 获取 JMX 密码:
cat /opt/data/james/james-server-jpa-guice/conf/jmxremote.password

实测回显:

james-admin dsxpFTtR0Q

⚠️ 注意:JMX 密码在每次启动时自动生成(james.jmx.credential.generation=true),重启后须重新读取。

  1. WebAdmin 密码已在 webadmin.properties 固定为 q1w2e3r4(未固定则查启动日志)。

四、命令行工具 james-cli

4.1 通用用法与全局参数

命令行工具入口为 org.apache.james.cli.ServerCmd,需用 java 直接加载发行包 classpath:

cd /opt/data/james/james-server-jpa-guice
$JAVA_HOME/bin/java -cp "james-server-jpa-app.jar:james-server-jpa-app.lib/*" \
  org.apache.james.cli.ServerCmd \
  --host 127.0.0.1 --port 9999 \
  --username james-admin --password dsxpFTtR0Q \
  <command>

全局参数(实测 --help 输出):

usage: java org.apache.james.cli.ServerCmd --host <arg> <command>
 -h,--host <arg>              node hostname or ip address
 -p,--port <arg>              remote jmx agent port number
 -password,--password <arg>   remote jmx password
 -username,--username <arg>   remote jmx username

💡 说明:--host/--port 对应 jmx.properties 的 jmx.address/jmx.port(默认 9999),--username/--password 对应 jmxremote.access/password 文件内容。为便于阅读,下文以 CLI() 指代整条前缀命令。

4.2 全部命令速查(实测 Help 回显)

未指定子命令或输入非法命令时打印完整用法,实测完整命令清单如下:

AddUser <username> <password>
RemoveUser <username>
ListUsers
AddDomain <domainName>
RemoveDomain <domainName>
ContainsDomain <domainName>
ListDomains
AddDomainMapping <domain> <targetDomain>
RemoveDomainMapping <domain> <targetDomain>
ListDomainMappings <domain>
ListMappings
ListUserDomainMappings <user> <domain>
AddAddressMapping <fromUser> <fromDomain> <toAddress>
RemoveAddressMapping <fromUser> <fromDomain> <toAddress>
AddRegexMapping <user> <domain> <regex>
RemoveRegexMapping <user> <domain> <regex>
SetPassword <username> <password>
CopyMailbox <srcBean> <dstBean>
DeleteUserMailboxes <user>
CreateMailbox <namespace> <user> <name>
ListUserMailboxes <user>
DeleteMailbox <namespace> <user> <name>
ImportEml <namespace> <user> <name> <path>
GetStorageQuota <quotaroot>
GetMessageCountQuota <quotaroot>
GetQuotaroot <namespace> <user> <name>
GetMaxStorageQuota <quotaroot>
GetMaxMessageCountQuota <quotaroot>
SetMaxStorageQuota <quotaroot> <maxMessageCount>
SetMaxMessageCountQuota <quotaroot> <maxStorage>
SetGlobalMaxStorageQuota <maxStorage>
SetGlobalMaxMessageCountQuota <maxMessageCount>
GetGlobalMaxStorageQuota
GetGlobalMaxMessageCountQuota
ReindexMailbox <namespace> <user> <name>
ReindexAll
GetSieveQuota
SetSieveQuota <quota>
RemoveSieveQuota
GetSieveUserQuota <username>
SetSieveUserQuota <username> <quota>
RemoveSieveUserQuota <username>
AddActiveSieveScript <username> <scriptname> <path>
GetDropList <ownerScope> <owner>
AddDropListEntry <ownerScope> <owner> <deniedEntity>
RemoveDropListEntry <ownerScope> <owner> <deniedEntity>
DropListQuery <ownerScope> <owner> <deniedEntity>

⚠️ 注意:实测 Help 子命令返回 Help does not exist 并打印上述用法(等价于无参数调用),命令列表以此处为准。

4.3 域名管理命令(实测)

创建域:

CLI() AddDomain example.com

💡 说明:AddDomain 实测于 WebAdmin 已建域之后,若域已存在会提示已存在。推荐日常用 WebAdmin PUT /domains/<name>(见 5.1)。

列出全部域:

CLI() ListDomains

实测回显:

example.com
localhost
ListDomains command executed sucessfully in 425 ms.

检查域是否存在:

CLI() ContainsDomain example.com

实测回显:

example.com exists
ContainsDomain command executed sucessfully in 716 ms.

删除域:

# 先建一个临时域 test.com,再删除演示
CLI() AddDomain test.com
CLI() RemoveDomain test.com

实测回显:

AddDomain command executed sucessfully in 342 ms.
RemoveDomain command executed sucessfully in 380 ms.

💡 说明:command executed sucessfully 即为成功标志(sucessfully 为 James 输出原文)。

4.4 用户管理命令(实测)

创建用户:

CLI() AddUser admin@example.com q1w2e3r4

实测回显:

AddUser command executed sucessfully in 424 ms.

列出用户:

CLI() ListUsers

实测回显:

root@example.com
admin@example.com
ListUsers command executed sucessfully in 529 ms.

修改密码:

CLI() SetPassword root@example.com q1w2e3r4

实测回显:

SetPassword command executed sucessfully in 459 ms.

删除用户及其邮箱:

CLI() RemoveUser <username>
CLI() DeleteUserMailboxes <user>

4.5 邮箱与邮件导入命令(实测)

创建邮箱(namespace 用 #private):

CLI() CreateMailbox "#private" "root@example.com" "Test"

实测回显:

CreateMailbox command executed sucessfully in 1935 ms.

列出用户邮箱:

CLI() ListUserMailboxes root@example.com

实测回显:

INBOX
Test
ListUserMailboxes command executed sucessfully in 580 ms.

删除邮箱 / 复制邮箱 / 导入 EML:

CLI() DeleteMailbox "#private" "root@example.com" "Test"
CLI() CopyMailbox "#private&root@example.com" "#private&admin@example.com"
CLI() ImportEml "#private" "root@example.com" "INBOX" /tmp/mail.eml

4.6 配额命令(实测)

全局存储配额设置与查询(先设置再查询):

CLI() SetGlobalMaxStorageQuota 1000000

实测回显:

SetGlobalMaxStorageQuota command executed sucessfully in 693 ms.
CLI() GetGlobalMaxStorageQuota

实测回显:

Global Maximum Storage Quota: 976.56 KiB
GetGlobalMaxStorageQuota command executed sucessfully in 538 ms.

全局邮件数配额:

CLI() SetGlobalMaxMessageCountQuota 100000
CLI() GetGlobalMaxMessageCountQuota

查询某个 quota root 的邮件数使用情况(quotaroot 形如 #private&user@domain):

CLI() GetMessageCountQuota "#private&root@example.com"

实测回显:

MailboxMessage count quota for #private&root@example.com is: 1 / UNLIMITED
GetMessageCountQuota command executed sucessfully in 1421 ms.

查询 quota root(正确 4 参数形态):

CLI() GetQuotaroot "#private" "root@example.com" "INBOX"

实测回显:

Quota Root: #private&root@example.com
GetQuotaroot command executed sucessfully in 417 ms.

⚠️ 排障实录:未设置全局存储配额时直接 GetGlobalMaxStorageQuota 会抛 java.lang.NullPointerException(SerializableQuotaLimitValue 空值),属 James 3.9.1 已知行为;先执行 SetGlobalMaxStorageQuota <值> 后即可正常查询。另 GetQuotaroot 需 4 个参数(namespace/user/name),只给 1 个会提示 GetQuotaroot should be used with 4 arguments but only 1 were provided。

4.7 地址映射与转发命令

CLI() AddAddressMapping root example.com admin@example.com   # 发往 root@example.com 转发到 admin@example.com
CLI() RemoveAddressMapping root example.com admin@example.com
CLI() ListMappings
CLI() AddDomainMapping example.com mail.example.com          # 域别名
CLI() RemoveDomainMapping example.com mail.example.com
CLI() ListDomainMappings example.com
CLI() AddRegexMapping postmaster example.com "postmaster@.+"  # 正则转发
CLI() ListUserDomainMappings root example.com

💡 说明:地址/域映射实际写入 RecipientRewriteTable(RRT),对应 mailetcontainer.xml 中的 RecipientRewriteTable mailet,实现别名、转发、正则重写。

4.8 Sieve 脚本与垃圾名单命令

CLI() GetSieveQuota
CLI() SetSieveQuota 10485760            # 10MB
CLI() GetSieveUserQuota root@example.com
CLI() SetSieveUserQuota root@example.com 10485760
CLI() AddActiveSieveScript root@example.com myrules /tmp/sieve.txt
CLI() GetDropList Global root@example.com
CLI() AddDropListEntry Global root@example.com blocked@spam.com
CLI() DropListQuery Global root@example.com blocked@spam.com
CLI() RemoveDropListEntry Global root@example.com blocked@spam.com

4.9 索引重建命令

CLI() ReindexMailbox "#private" "root@example.com" "INBOX"
CLI() ReindexAll

💡 说明:邮箱搜索索引异常(如升级后)用 ReindexAll 全量重建;大批量重建期间建议低峰执行。

五、WebAdmin REST API

5.1 域名与用户

# 建域(204 = 成功)
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"

# 列域
curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/domains
# 实测回显:["example.com","localhost"]

# 建用户
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"

# 列用户
curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/users
# 实测回显:[{"username":"root@example.com"},{"username":"admin@example.com"}]

# 列某用户的邮箱
curl -s -H "Password: q1w2e3r4" http://127.0.0.1:8000/users/root@example.com/mailboxes
# 实测回显:[{"mailboxName":"INBOX","mailboxId":"1"}]

⚠️ 注意:WebAdmin 无 GET /users/<user> 明细端点,实测返回 404 notFound;用户信息以 GET /users 列表为准。

5.2 健康检查

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

实测回显(全部组件 healthy):

{"status":"healthy","checks":[{"componentName":"Guice application lifecycle","status":"healthy"},{"componentName":"MailReceptionCheck","status":"healthy"},{"componentName":"EventDeadLettersHealthCheck","status":"healthy"},{"componentName":"IMAPHealthCheck","status":"healthy"},{"componentName":"Embedded ActiveMQ","status":"healthy"},{"componentName":"EmptyErrorMailRepository","status":"healthy"}]}

💡 说明:status: healthy 表示进程、邮件接收、IMAP、内嵌 ActiveMQ 与错误邮件仓库均正常;可用于监控探活。

六、Python 客户端测试工具

6.1 SMTP 发信(smtplib)

python3 -c "
import smtplib
from email.mime.text import MIMEText
msg = MIMEText('Hello from James', 'plain', 'utf-8')
msg['Subject'] = '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')
"

服务端日志确认投递(250 2.6.0 Message received 与 Local delivered):

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

6.2 POP3 收信(poplib)

python3 -c "
import poplib
m = poplib.POP3('127.0.0.1', 110, timeout=15)
print(m.user('admin@example.com'))     # 必须带域名
print(m.pass_('q1w2e3r4'))
print(m.stat())
m.quit()
"

实测回显:

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

6.3 IMAP 收信(imaplib + 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'])

七、注意事项

  • JMX 密码随机:每次重启变化,用 CLI 前先 cat conf/jmxremote.password。
  • 参数完整:GetQuotaroot/CreateMailbox 等需要完整参数(namespace/user/name),namespace 一般 #private;配额 root 形如 #private&user@domain。
  • 认证头:WebAdmin 用 Password 请求头,不是 Basic Auth。
  • POP3/IMAP 登录名:必须带域名(enableVirtualHosting=true)。
  • 命令耗时:每个命令末尾输出 command executed sucessfully in <毫秒> ms. 即成功标志(实测数百~数千 ms,如 in 425 ms.、in 538 ms.);若提示 Error while playing command 则失败(见 4.6 排障实录)。

八、常见问题(FAQ)

Q1:james-cli 报 You must specify a command.? 未传子命令。按 4.1 完整命令格式补 <command>,或用无参数调用查看完整命令列表。

Q2:james-cli 连接失败(认证/连接异常)? 确认 --host 127.0.0.1 --port 9999 与 jmx.properties 一致、--username/--password 取自 jmxremote.access/password;服务重启后密码会变,重新读取。

Q3:GetGlobalMaxStorageQuota 抛 NullPointerException? 全局配额未初始化所致,先 SetGlobalMaxStorageQuota <值> 再查询(见 4.6)。

Q4:WebAdmin 返回 404? 端点路径不对或该资源无对应 REST 路由(如 GET /users/<user> 不存在),改用 GET /users 列表 + /users/<user>/mailboxes。

Q5:POP3/IMAP 认证失败? 登录名用完整邮箱(root@example.com);IMAP 明文被禁用需 STARTTLS(见 6.3)。

九、参考链接