SnappyMail 2.38.2 配置参数详解
SnappyMail 2.38.2 配置体系逐项实测:application.ini 十六节关键参数、域配置 JSON 全键、管理面板与 JSON API 的对应关系,以及参数改动的生效机制与排障,每项给出实测命令与回显。
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.ini | PHP INI 风格分节键值 | 站点标题、登录策略、安全开关、日志、缓存、联系人、默认 IMAP/SMTP 行为 | 管理面板各设置页,或直接文本编辑 |
| 域配置 | data/_data_/_default_/domains/<域名>.json | JSON | 该域用户的 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_login | Off | 允许从外部 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_login | On | 登录页语言选择器 |
| determine_user_language | On | 按 Accept-Language 自动选语言 |
| sign_me | "Off" | 「记住我」能力开关 |
| determine_user_domain | Off | 从登录名/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 / openpgp | On / On | PGP 能力开关 |
| allow_admin_panel | On | 管理面板总开关(Off 时 /?admin 与管理 API 均被拒绝) |
| admin_login | "admin" | 管理员用户名 |
| admin_password | $2y$10$… | bcrypt 哈希(password_hash 生成,界面/接口永不回显明文) |
| admin_totp | "" | 管理员 TOTP 两步验证密钥(空为未启用) |
| admin_panel_host | "" | 限定可访问管理面板的主机名(空不限制) |
| secfetch_allow | Off | 是否强制校验 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] — 日志
| 参数 | 默认值(实测) | 说明 |
|---|---|---|
| enable | Off | 总开关 |
| path | "" | 日志目录(空 = data/logs/) |
| level | 5(Notice) | 按 RFC 5424 严重级别过滤(0 紧急 ~ 7 调试,记该级及以上) |
| auth_logging | On | 登录失败写 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] — 缓存
| 参数 | 默认值(实测) | 说明 |
|---|---|---|
| enable | On | 应用缓存总开关 |
| path | "" | 缓存目录(空 = data/cache/) |
| index / fast_cache_index | "v1" / "v1" | 缓存键版本号,改动即整体清空对应缓存 |
| http | On | 浏览器侧静态资源缓存 |
| http_expires | 3600 | Expires 头秒数 |
| server_uids | On | 搜索/排序时的 UID 缓存 |
| system_data | On | 系统数据缓存 |
运维技巧:升级版本或批量改配置后若发现行为未刷新,把
index值改一下(如 "v1"→"v2")即可整体清缓存,等价于管理面板 Clear Cache 按钮。
3.6 [contacts] — 通讯录
| 参数 | 默认值(实测) | 说明 |
|---|---|---|
| enable | On | 通讯录开关 |
| allow_sync | Off | CardDAV 同步 |
| 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 |
| shortLogin | true 时仅取 @ 前面的用户名做认证 | 本环境 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[节][键]) |
| Domains | domains/<域>.json | AdminDomainSave / 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] 节——域配置按域覆盖全局默认。 /?admin403: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),稳定后回调。
七、参考链接
- 官方 Wiki 配置说明:https://github.com/the-djmaze/snappymail/wiki
- v2.38.2 源码默认配置模板(参数全集权威来源):仓库内
snappymail/v/2.38.2/app/libraries/RainLoop/Config/Application.php - 本专栏姊妹篇:《Ubuntu 22.04 安装 SnappyMail 指南》(安装与向导实测)、《SnappyMail 2.38.2 API 使用详解》(JSON API 逐动作实测)