SnappyMail 2.38.2 配置参数详解

SnappyMail 2.38.2 配置体系逐项实测:application.ini 十六节关键参数、域配置 JSON 全键、管理面板与 JSON API 的对应关系,以及参数改动的生效机制与排障,每项给出实测命令与回显。

SnappyMailSnappyMail邮件服务器2026/10/21

SnappyMail 2.38.2 配置参数详解

目标:把 SnappyMail 2.38.2 的配置体系讲透——三层配置(全局 application.ini / 每域 domains/*.json / 管理面板)分别管什么、关键参数默认值与含义、怎么改、怎么验证生效。本文全部参数验证都在真实部署环境完成(改 → 生效 → 验证闭环),命令与回显逐行照录。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64),主机名 mail.example.com
  • SnappyMail:2.38.2(官方 latest.tar.gz 安装于 /var/www/webmail/snappymail)
  • 运行栈:Nginx 1.18.0 + PHP-FPM 8.1(Unix Socket)
  • 邮件后端:Dovecot 2.3.16(IMAP 143)+ Postfix 3.6.4(SMTP 25),均监听本机回环
  • 测试账号:demo@example.com、alice@example.com(密码 q1w2e3r4,仅实验环境);管理员 admin
  • 访问入口:http://127.0.0.1:8147/(映射到 Nginx 80 端口站点)

二、配置体系全景

SnappyMail 配置分三层,职责边界清晰:

层级位置格式管什么修改方式
全局配置data/_data_/_default_/configs/application.iniPHP INI 风格分节键值站点标题、登录策略、安全开关、日志、缓存、联系人、默认 IMAP/SMTP 行为管理面板各设置页,或直接文本编辑
域配置data/_data_/_default_/domains/<域名>.jsonJSON该域用户的 IMAP/SMTP/Sieve 服务器与认证方式管理面板 Domains 页
用户/会话状态data 目录下 admin_password.txt、缓存、日志文件等文件临时凭据、缓存、日志应用自动管理

两个关键机制(实测确认):

  • 生效方式:PHP 应用每次请求读取配置,文本编辑 application.ini 后立即生效,无需重启 Nginx/PHP-FPM(见 §3.4 实测)。
  • 管理面板入口:默认 /?admin;受 [security] allow_admin_panel 开关控制。

三、application.ini 参数详解

文件位于 data/_data_/_default_/configs/application.ini,v2.38.2 共 16 个分节(实测 grep -n '^\[' application.ini 回显):webmail、interface、contacts、security、admin_panel、ssl、capa、login、plugins、defaults、logs、debug、cache、imap、labs、version。以下按节展开,**【实测】**标记的参数均做过改→生效→验证闭环。

3.1 [webmail] — 站点基本属性

参数默认值(实测)说明
title"SnappyMail Webmail"浏览器标签标题与站点名
loading_description"SnappyMail"加载页描述文案
external_login_url""外部登录页地址(配合 SSO)
allow_external_loginOff允许从外部 URL 登录

【实测】修改 title 并即时验证(管理面板 ⇔ API 等价操作):

B=http://127.0.0.1:8147
# 管理员登录(Cookie 持久化是关键,缺 -c 会得到 AuthError[102])
rm -f cj.txt
T=$(curl -s -c cj.txt "$B/?/admin/AppData" | grep -oE '"token":"[^"]+"' | cut -d'"' -f4)
curl -s -c cj.txt -b cj.txt -X POST "$B/?/admin/Json" \
  -d "Action=AdminLogin&XToken=$T&Login=admin&Password=q1w2e3r4"
# 修改标题
T=$(curl -s -b cj.txt "$B/?/admin/AppData" | grep -oE '"token":"[^"]+"' | cut -d'"' -f4)
curl -s -c cj.txt -b cj.txt -X POST "$B/?/admin/Json" \
  --data-urlencode 'config[webmail][title]=Quzuo Lab Mail' \
  --data "Action=AdminSettingsSet&XToken=$T"
# 用户侧立即可见
curl -s "$B/?/AppData" | grep -oE '"title":"[^"]+"' | head -1

实测回显:

{"Action":"AdminSettingsSet","Result":true,"epoch":1792553791}
"title":"Quzuo Lab Mail"

3.2 [login] — 登录策略

参数默认值(实测)说明
default_domain""用户登录没写 @域 时自动补全的域;特殊值 HTTP_HOST/SERVER_NAME/gethostname 动态取值
allow_languages_on_loginOn登录页语言选择器
determine_user_languageOn按 Accept-Language 自动选语言
sign_me"Off"「记住我」能力开关
determine_user_domainOff从登录名/host 推断域并路由到对应域配置

【实测】default_domain = "example.com" 后,登录名只填用户名即可:

# 保存 default_domain
T=$(curl -s -b cj.txt "$B/?/admin/AppData" | grep -oE '"token":"[^"]+"' | cut -d'"' -f4)
curl -s -c cj.txt -b cj.txt -X POST "$B/?/admin/Json" \
  --data-urlencode 'config[login][default_domain]=example.com' \
  --data "Action=AdminSettingsSet&XToken=$T"

# 以短用户名 demo 登录
rm -f cj2.txt
T2=$(curl -s -c cj2.txt "$B/?/AppData" | grep -oE '"token":"[^"]+"' | cut -d'"' -f4)
curl -s -b cj2.txt -X POST "$B/?/Json" \
  -d "Action=Login&XToken=$T2&Email=demo&Password=q1w2e3r4&SignMe=0" \
  | grep -oE '"Email":"[^"]+"|Auth":(true|false)'

实测回显:

{"Action":"AdminSettingsSet","Result":true,"epoch":1792553805}
Auth":true
"Email":"demo@example.com"

Email 已被自动补全为 demo@example.com,配合 IMAP 域配置的 shortLogin 实现了「界面输短名、后端补域名」的体验。

3.3 [security] — 安全开关与管理员凭据

参数默认值(实测)说明
custom_server_signature"SnappyMail"自定义 HTTP 响应 Server 头
x_xss_protection_header"1; mode=block"XSS 防护头
gnupg / openpgpOn / OnPGP 能力开关
allow_admin_panelOn管理面板总开关(Off 时 /?admin 与管理 API 均被拒绝)
admin_login"admin"管理员用户名
admin_password$2y$10$…bcrypt 哈希(password_hash 生成,界面/接口永不回显明文)
admin_totp""管理员 TOTP 两步验证密钥(空为未启用)
admin_panel_host""限定可访问管理面板的主机名(空不限制)
secfetch_allowOff是否强制校验 Sec-Fetch 请求头(防 CSRF 的浏览器侧策略)

【实测一】首次安装的临时密码生命周期(安装向导行为):

# 首次访问 ?admin 生成临时密码文件
cat data/_data_/_default_/admin_password.txt  -> 0c3SNaU63l4I
# application.ini 同步写入哈希
grep -n admin_login /var/www/webmail/snappymail/data/_data_/_default_/configs/application.ini
admin_login = "admin"
# 改密(AdminPasswordUpdate 接口,等价于面板 Security 页操作)
{"Result": {"Weak": false}}
# 临时密码文件被自动删除
ls: cannot access 'admin_password.txt': No such file or directory
# 新密码复登
{"Auth": true}

【实测二】关闭管理面板开关(必须传 JSON 布尔值,传字符串 "false" 会被当真值处理):

T=$(curl -s -b cj.txt "$B/?/admin/AppData" | grep -oE '"token":"[^"]+"' | cut -d'"' -f4)
curl -s -c cj.txt -b cj.txt -X POST "$B/?/admin/Json" -H 'Content-Type: application/json' \
  -d "{\"Action\":\"AdminSettingsSet\",\"XToken\":\"$T\",\"config\":{\"security\":{\"allow_admin_panel\":false}}}"
curl -s -o /dev/null -w '%{http_code}\n' "$B/?admin"
curl -s -o /dev/null -w '%{http_code}\n' -b cj.txt "$B/?/admin/AppData"

实测回显:

{"Action":"AdminSettingsSet","Result":true,"epoch":1792553805}
GET /?admin -> 403
admin API -> 403

恢复方法(开关关掉后连管理 API 都进不去,只能改文件):编辑 application.ini 将 allow_admin_panel = Off 改回 On,实测保存后 GET /?admin 立即恢复 200。

3.4 [logs] — 日志

参数默认值(实测)说明
enableOff总开关
path""日志目录(空 = data/logs/)
level5(Notice)按 RFC 5424 严重级别过滤(0 紧急 ~ 7 调试,记该级及以上)
auth_loggingOn登录失败写 syslog(配合 Fail2ban)
filename"log-{Y-m-d}.txt"日志文件名模板

【实测】文本编辑 enable = Off → On(sed),无需重启,下一笔请求即产出日志文件:

sed -i 's/^enable = Off/enable = On/' \
  /var/www/webmail/snappymail/data/_data_/_default_/configs/application.ini
grep -A2 '^\[logs\]' /var/www/webmail/snappymail/data/_data_/_default_/configs/application.ini | head -3
ls /var/www/webmail/snappymail/data/_data_/_default_/logs/

实测回显:

[logs]
; Enable logging
enable = On
log-2026-10-21.txt

日志内容示例(同文件节选,记录了调试期的一次管理登录失败):

[2026-10-21T03:14:37.247+00:00][60][INFO][SERVICE] POST[INFO]: {"Action":"AdminLogin", "Login":"admin", "Password":"*******", "XToken":"0-7179df..."}
[2026-10-21T03:14:37.312+00:00][60][WARNING][SERVICE] UnknownError[999] at ServiceActions.php#156

3.5 [cache] — 缓存

参数默认值(实测)说明
enableOn应用缓存总开关
path""缓存目录(空 = data/cache/)
index / fast_cache_index"v1" / "v1"缓存键版本号,改动即整体清空对应缓存
httpOn浏览器侧静态资源缓存
http_expires3600Expires 头秒数
server_uidsOn搜索/排序时的 UID 缓存
system_dataOn系统数据缓存

运维技巧:升级版本或批量改配置后若发现行为未刷新,把 index 值改一下(如 "v1"→"v2")即可整体清缓存,等价于管理面板 Clear Cache 按钮。

3.6 [contacts] — 通讯录

参数默认值(实测)说明
enableOn通讯录开关
allow_syncOffCardDAV 同步
type"sqlite"存储后端,可选 mysql/postgresql/SQLite
pdo_dsn / pdo_user / pdo_password""外接数据库时的 DSN 与凭据
suger_sync / ldap …—LDAP 目录与同步相关(需对应 PHP 扩展)

3.7 [admin_panel] 与 [capa]、[plugins]、[defaults]

  • [admin_panel]:host = ""(管理面板专用主机名,配合反代隔离管理入口)、allow_admin_panel_second_step = Off(二次验证)。
  • [capa]:功能能力开关,控制用户可用功能面(如 capa_contacts、capa_openpgp 等),逐项 On/Off。
  • [plugins]:enable = On、enabled_list = ""(启用的插件列表,逗号分隔),与管理面板 Plugins 页联动。
  • [defaults]:新用户界面的出厂默认(主题、语言、时区等),用户未显式设置时生效。
  • [debug]:enable = Off(打开后前端报错更详细,排障用)。
  • [labs]:实验特性开关集合,非必要不动。
  • [version]:current = "2.38.2",应用版本号与升级迁移标记,升级时由应用改写。
  • [ssl]:CA 证书路径与传输层校验选项(verify_peer、allow_self_signed 等,默认按 PHP OpenSSL 配置)。
  • [imap]:全局 IMAP 行为默认值(use_force_selection = Off、message_list_fast_simple_search = On、fetch_new_messages = On 等),域配置 JSON 里的同名键会按域覆盖。
  • [interface]:界面元素显示开关(附件、菜单等)。

四、域配置 domains/*.json 详解

每个邮件域一份 JSON(v2.38.2 为 JSON,早期版本为 INI),管理面板 Domains 页保存时生成。实测 data/_data_/_default_/domains/example.com.json 全文如下(键位即全部可配项):

{
    "IMAP": {
        "host": "127.0.0.1", "port": 143, "type": 0, "timeout": 300,
        "shortLogin": true, "lowerLogin": true, "stripLogin": "",
        "sasl": ["PLAIN", "LOGIN"],
        "ssl": {"verify_peer": true, "verify_peer_name": true,
                "allow_self_signed": false, "SNI_enabled": true,
                "disable_compression": true, "security_level": 1},
        "use_expunge_all_on_delete": false, "fast_simple_search": true,
        "force_select": false, "message_all_headers": false,
        "message_list_limit": 10000, "search_filter": "",
        "spam_headers": "rspamd,spamassassin,bogofilter",
        "virus_headers": "rspamd,clamav", "disabled_capabilities": []
    },
    "SMTP": {
        "host": "127.0.0.1", "port": 25, "type": 0, "timeout": 60,
        "shortLogin": true, "lowerLogin": true, "stripLogin": "",
        "sasl": ["PLAIN", "LOGIN"],
        "ssl": {"verify_peer": true, "verify_peer_name": true,
                "allow_self_signed": false, "SNI_enabled": true,
                "disable_compression": true, "security_level": 1},
        "useAuth": false, "setSender": false, "usePhpMail": false,
        "authPlainLine": false
    },
    "Sieve": {
        "host": "127.0.0.1", "port": 4190, "type": 0, "timeout": 10,
        "shortLogin": false, "lowerLogin": true, "stripLogin": "",
        "sasl": ["SCRAM-SHA3-512", "SCRAM-SHA-512", "SCRAM-SHA-256",
                 "SCRAM-SHA-1", "PLAIN", "LOGIN"],
        "ssl": {"verify_peer": true, "verify_peer_name": true,
                "allow_self_signed": false, "SNI_enabled": true,
                "disable_compression": true, "security_level": 1},
        "enabled": false, "authLiteral": true
    },
    "whiteList": ""
}

4.1 通用键(IMAP/SMTP/Sieve 三段共用)

键含义实测要点
host / port服务器地址与端口同机回环场景用 127.0.0.1;type=0 明文、1 SSL 直连、2 STARTTLS
timeout连接/命令超时(秒)IMAP 300、SMTP 60、Sieve 10
shortLogintrue 时仅取 @ 前面的用户名做认证本环境 true:demo@example.com → IMAP 用户 demo(PAM 系统账号)
lowerLogin登录名转小写大小写敏感后端可关闭
stripLogin正则剔除登录名片段高级整形场景
sasl允许的认证机制清单Dovecot 支持 PLAIN/LOGIN;SCRAM 系列按服务器能力声明
ssl.*OpenSSL 层校验type 非 0 时生效;自签证书环境需 allow_self_signed: true

4.2 IMAP 段专有键

  • fast_simple_search:简单搜索走服务器端快速路径;
  • force_select / use_expunge_all_on_delete:与服务器兼容性相关的行为修正;
  • message_list_limit:单次列表条数上限(10000);
  • spam_headers / virus_headers:识别反垃圾/杀毒标记的服务器头顺序(rspamd、spamassassin、clamav…)。

4.3 SMTP 段专有键

  • useAuth:SMTP 是否认证(本环境 Postfix 回环放行,false;跨机需 true 且配 sasl);
  • usePhpMail:true 时改走 PHP mail()(受限于本机 MTA,一般不用);
  • setSender / authPlainLine:与投递头、AUTH PLAIN 编码相关的兼容项。

4.4 Sieve 段专有键

  • enabled:是否启用 ManageSieve(本环境 Dovecot 未装 sieved,false;启用后用户可管理服务器端过滤规则);
  • authLiteral:LITERAL+ 扩展兼容开关。

4.5 whiteList

该域登录页显示的域名白名单提示(空 = 不限制)。

域配置保存与核验:管理面板 Domains 页保存即写入;命令行等价操作为管理 API AdminDomainSave(POST JSON 到 ?/admin/Json),列表查询用 AdminDomainList。实测保存后 AdminDomainList 回显 "name": "example.com", "enabled": true。

五、管理面板与配置的对应关系

管理面板每页操作的落点(本环境逐一核对):

面板页落盘位置对应 JSON API 动作(POST ?/admin/Json)
登录页生成 admin_password.txt;application.ini [security]AdminLogin
General[webmail]、[login]AdminSettingsSet(config[节][键])
Domainsdomains/<域>.jsonAdminDomainSave / AdminDomainList / AdminDomainDelete
Security[security](登录名/密码/TOTP/开关)AdminPasswordUpdate、AdminSettingsSet
Contacts[contacts]AdminSettingsSet、AdminContactsTest
Plugins[plugins]、plugins/ 目录AdminPluginList、AdminPluginEnable、AdminPluginSettingsUpdate
About版本信息AdminAppData(含 ApplicationVersion)
—(维护)data/ 整体AdminBackup、AdminClearCache、AdminUpgradeCore

管理 API 通用约束(实测踩坑记录):

  • CSRF:所有写操作必须带 XToken,值取自 ?/admin/AppData 回显的 System.token,与 Cookie 会话绑定;
  • Cookie 持久化:curl 每次请求都要 -c 保存 + -b 回带,否则改密/登录后拿到的新会话 Cookie 丢失,报 AuthError[102];
  • 布尔值:AdminSettingsSet 走 JSON body 传 true/false 才是布尔语义,表单编码的字符串 "false" 会被 PHP 当真值;
  • 响应包裹:所有动作返回 {Action, Result, code, message, epoch},失败时 Result:false + 非 0 code(如 102=AuthError、999=UnknownError)。

六、配置生效机制与排障

  • 文本编辑即时生效:PHP-FPM 每请求读配置。实测两处闭环(logs.enable、allow_admin_panel)均为「sed 保存 → 下一请求生效」,无需重启任何服务。若改动后行为未变,优先怀疑改错文件(注意 data/_data_/_default_/ 中间还有一层 _default_ 前缀目录)或缓存(改 [cache] index 值清空)。
  • 改错文件不生效:域行为问题先确认改动落在 domains/<域>.json 而不是全局 [imap] 节——域配置按域覆盖全局默认。
  • /?admin 403:allow_admin_panel 被关(本机实测复现:403 且管理 API 一并 403),唯一恢复路径是编辑 application.ini;
  • AuthError[102]:管理会话失效/CSRF Token 不匹配/未登录——重新走一遍「AppData 取 token → AdminLogin → 再取 token → 业务动作」,并确认 Cookie 全程回带;
  • 密码文件反复出现:admin_password.txt 只在「管理员从未设置密码」时生成,改密成功即删除;若反复出现说明改密未真正提交成功(回看 AdminPasswordUpdate 的 Result);
  • 日志不开则无排障依据:默认 enable=Off,建议部署初期打开([logs] enable=On + level=5),稳定后回调。

七、参考链接