5
0
0

xvmail服主使用教程文档

2026-11-11
文章摘要
|

xvmail 服主完全使用教程

对应版本:xvmail 1.7.0。构建环境 Java 21,Paper API 编译目标 1.21.4-R0.1-SNAPSHOT,plugin.yml 声明 api-version: 1.21 与 folia-supported: true。Folia 运行与多版本兼容尚未在真实服务器验证,请勿直接对外做宽泛兼容承诺。

一、部署前必做的三件事(先看这里)

新装或升级后,请按顺序确认,否则会出现「邮件发不出去」「收不到真实邮件」「付费扣不了钱」:

  1. 处理 AI 审核:moderation.enabled 默认 true,但 api-key 与 model 默认为空,审核是 fail-closed 的——没配好服务时所有发信都会被拒绝。要么填好兼容接口的 URL / Key / 模型,要么明确改成 enabled: false(关闭后仍保留本地链接与宣传拦截)。
  2. 配置 SMTP:smtp.enabled 默认 false。验证码、绑定、真实邮件同步全部依赖 SMTP;不启用就只有游戏内邮件。
  3. 确认经济插件:付费发送需要 Vault 加一个经济实现(EssentialsX / CMI 等),或 PlayerPoints;并把 sending.currency 改成实际使用的那一个。启动时看日志 付费发送货币=...:<状态> 就能确认。

改完执行 /mailadmin reload,必要时重启服务器。

二、安装与配置文件

把 release/xvmail-1.7.0.jar 放进 plugins/,启动服务器。JAR 已打包 Gson 与 Jakarta Mail(Angus 实现),不需要额外下载依赖;Vault、PlayerPoints 只是软依赖,仅在付费发送时需要。

首次启动会生成 plugins/xvmail/config.yml。从旧版本升级时,saveDefaultConfig() 不会覆盖已有配置,因此插件做了一次性迁移:若配置里没有 config-version: 2,会在首次启动把 email-bind.auto-send-real-email 打开并写入 config-version: 2,后台会打印一条升级日志。之后服主手动改回 false 不会被再次覆盖。

完整配置示例

config-version: 2
storage:
  directory: mail
mail:
  max-inbox-size: 200
  unread-reminder-on-join: true
  subject-max-length: 80
  content-max-length: 2000
  console-sender-name: "服务器"
  console-notify-online: true
smtp:
  enabled: true
  host: smtp.qq.com
  port: 465
  username: "your@qq.com"
  password: "邮箱 SMTP 授权码"
  from-address: "your@qq.com"
  from-name: "teana server"
  use-ssl: true
  use-tls: false
  timeout: 10000
email-bind:
  enabled: true
  auto-send-real-email: true
  send-cooldown-seconds: 60
  code-expire-minutes: 10
  max-attempts: 5
moderation:
  enabled: false
  api-url: "https://api.openai.com/v1/chat/completions"
  api-key: ""
  model: ""
  timeout-ms: 8000
sending:
  daily-free-limit: 10
  daily-paid-limit: 20
  currency: vault
  paid-cost: 100.0
  attachment-max-bytes: 32768
claim:
  command-template: ""
templates:
  welcome:
    subject: "欢迎来到服务器"
    content: "你好 {player},欢迎加入服务器!有问题可以联系管理员。"
  event:
    subject: "活动通知"
    content: "你好 {player},服务器有新活动开启,欢迎上线参与。"

上面示例把 moderation.enabled 设成了 false,是为了让插件开箱可发信;生产环境若要 AI 审核,请改成 true 并补齐 Key 与模型。

关键配置项说明

配置 作用
mail.max-inbox-size 每个玩家的邮件上限,满了会拒绝新邮件
mail.subject-max-length / content-max-length 主题、正文长度上限
mail.console-sender-name 管理员 / 控制台邮件的发件人显示名;不要设成某个玩家名,否则真实邮件会把服务器邮件误标成玩家邮件
mail.console-notify-online 在线收件人是否收到游戏内新邮件提示
smtp.from-name 真实邮件里显示的服务器名,也是 HTML 模板标题栏和「来自」一行的文字
smtp.from-address 实际发信地址,必须与 SMTP 账号一致,否则多数服务商会拒收
email-bind.auto-send-real-email 是否把游戏邮件同步到已验证绑定邮箱,默认开启
sending.currency vault 或 playerpoints,必须与实际安装的经济插件一致
claim.command-template 领取邮件触发的控制台命令模板

三、真实邮箱同步与 HTML 邮件

覆盖范围

同步默认开启。以下路径只要收件人有已验证绑定邮箱、SMTP 可用,都会额外发一封真实邮件:

  • 玩家之间发信(GUI 写信、/mail send、/mail sendex、模板邮件)
  • 管理员 GUI / 控制台 send、claim 领取邮件
  • recent 按最近上线时间筛选的群发(只对真正投递成功的收件人发送)
  • 外部插件调用 XvMailAPI 的基础发信接口

游戏内投递始终优先,真实邮件失败不影响游戏内邮件。未绑定邮箱、SMTP 未启用、SMTP 投递失败时只保留游戏内邮件;失败原因写入后台日志,不会打扰收件人。关闭同步:把 auto-send-real-email 设为 false 后 /mailadmin reload。

发件人显示规则(1.7.0 起)

邮件来源 使用的模板与展示 SMTP 发件人显示名
玩家 A → 玩家 B Player Mail:圆形首字母头像 + 玩家 A 的 ID +「向你发送了一封邮件 · <服务器名>」 玩家A (via <服务器名>)
管理员 / 控制台 / 系统 / 群发 / 验证码 System Notice:系统通知 或 邮箱验证 标签 + 主题 + 正文 <服务器名>

例如服务器名设为 teana server、玩家 Steve 给 Alex 发信,Alex 收到的邮件发件人显示 Steve (via teana server),头像圆里是 S,正文上方写「Steve / 向你发送了一封邮件 · teana server」。这样玩家互发不会再被误写成服务器发的邮件。判断依据是发件人名是否等于 console-sender-name 或「系统」,所以请保持 console-sender-name 是服务器身份名。

HTML 邮件模板(可自定义)

1.7.0 起使用两套独立的 HTML 模板,都是 Content-Type: text/html; charset=UTF-8,带 X-Mailer: xvmail/1.7.0:

模板 用于 文件
Player Mail 玩家发给玩家 plugins/xvmail/templates/player-mail.html
System Notice 管理员 / 控制台 / 系统邮件、群发、领取邮件、邮箱验证码 plugins/xvmail/templates/system-mail.html

首次启动时插件会把两份默认模板释放到 plugins/xvmail/templates/,之后优先读取数据目录里的文件,所以改样式、品牌名、页脚文案都不需要重新编译 JAR。改完执行 /mailadmin reload 即可生效(重载会重新读取模板与 SMTP 设置);如果模板文件读取失败,会回退到 JAR 内置版本并在后台记日志,两个文件都缺失时使用极简内置兜底模板。

占位符(方括号形式,插件一次性替换,替换值不会二次解析):

模板 占位符 内容
玩家邮件 [player_name] 发件玩家 ID
玩家邮件 [player_initial] 发件玩家名首字母,用于圆形头像
玩家邮件 [server_name] smtp.from-name
玩家邮件 [Article] 邮件正文(转义后换行转 <br>)
玩家邮件 [Attachment_content] 附件说明:有物品 / 有可领取奖励 / 无附件
两套模板 [server_name] smtp.from-name,用于邮件标题、页脚、版权行和「来自」一行
两套模板 [brand_first] / [brand_rest] smtp.from-name 按第一个空格拆成两段,用于双色品牌栏;无空格时前半为全名、后半为空
系统邮件 [notice_type] 系统通知 或 邮箱验证
系统邮件 [notice_title] 邮件主题 / 验证码标题
系统邮件 [notice_content] 正文或验证码高亮区块

模板里已经没有写死的服务器名:品牌栏、<title>、页脚、版权行全部取自 smtp.from-name,改配置即可全站生效;想显示成 Teana Server 这种大小写,把 smtp.from-name 设成对应写法即可。两套模板的版权区底部都加了一行「邮件系统由 xvmail 插件提供」。

升级行为:插件用 templates/template-version.txt 记录模板版本。从没有该文件的旧版本升级时,会自动把旧模板备份成 templates/*.old 并释放新模板,启动日志会提示;之后手动改过模板也不会再被覆盖(除非删除版本文件或升级到更高模板版本)。

玩家填写的主题、正文、玩家名、服务器名都会做 HTML 转义,作为文本显示,避免注入标签或脚本;因此玩家在游戏里写 <b> 不会变成加粗,这是刻意的安全设计。模板用了渐变、圆角、flex 等样式,Outlook 等客户端可能降级显示,建议实发到常用邮箱验收。

SMTP 配置要点

  • QQ / 163 邮箱:通常 port: 465、use-ssl: true、use-tls: false,password 填邮箱设置里生成的 SMTP 授权码,不是登录密码。
  • Gmail / Outlook:通常用 port: 587、use-ssl: false、use-tls: true(STARTTLS),以服务商当前要求为准。
  • from-address 必须与 username 一致;from-name 只影响显示名,可自由设成服务器名。
  • 二者不要同时开 use-ssl 与 use-tls,容易握手失败。
  • 大批量群发时 SMTP 任务队列上限为 128,超出的同步请求会被拒绝并在后台记日志,建议分批群发。

合规提示:邮件主题与正文会经由你选择的 SMTP 服务商,开启 AI 审核时还会发到第三方审核接口。请确认服务商数据政策、在服规里告知玩家,并妥善保管 config.yml(含 API Key 与邮箱授权码),不要公开或发给玩家。

四、邮箱绑定与验证码

/mail bindeamil <邮箱>      玩家申请验证码(兼容 /mail bindemail)
/mail verifyemail <验证码>  完成验证
/mail myemail               查询绑定
/mail unbindemail           解绑
  • 只有验证成功才会写入 email_bindings.yml,结构为 bindings.<uuid>.email / verified。
  • 验证码有发送冷却(send-cooldown-seconds)、有效期(code-expire-minutes)和错误次数上限(max-attempts),全部存在内存中;服务器重启或插件重载后验证码失效,需要重新申请。
  • 验证码邮件发送失败时会提示玩家检查服主 SMTP 配置,且不会占用绑定数据。
  • 关闭 email-bind.enabled 后玩家无法申请绑定,但已有绑定仍可用于同步。

五、AI 内容审核

审核只作用于玩家发的邮件。管理员 / 控制台 send、管理员 GUI 写信、recent 群发、claim 领取邮件一律跳过本地规则与 AI,直接投递,后台会留一条 管理员邮件跳过内容审核 日志便于审计。这些路径仍受主题 / 正文长度、收件人存在性和收件箱容量限制。OP 权限请只给可信的人:管理员邮件可以带链接等内容且不受审核。

moderation:
  enabled: true
  local-rules: false
  api-url: "https://api.openai.com/v1/chat/completions"
  api-key: "替换为你的API密钥"
  model: "你的审核模型"
  timeout-ms: 8000
  • 执行顺序:先跑本地规则(若开启),通过后才调用 AI。以前本地规则排在 AI 前面且不可关闭,命中就直接拒绝,AI 再正常也不会被调用——这是「AI 明明正常却一直发送失败」的最常见原因。现在 local-rules 默认 false,可由服主决定是否开启。
  • 本地规则已收紧:域名只在常见顶级域名后缀下判定(Hi.Hello 不再误伤),宣传关键词去掉了「欢迎 / 加入」(服务器欢迎新人加入 不再误伤);链接、IP、邮箱地址、以及「服务器 + IP / 地址 / 进群 / 群号 / 推广」仍会被拦。
  • AI 判定已放宽:返回内容会去掉标点、Markdown 星号、空白再判断,包含 APPROVE 且不含 REJECT 即放行,所以 APPROVE.、**APPROVE**、审批结果:APPROVE 都能通过。响应结构兼容 choices[0].message.content、choices[0].delta.content、choices[0].text 与顶层 output_text。
  • 超时、HTTP 错误、响应格式异常、Key / 模型为空,仍然一律拒绝(fail-closed)。
  • 所有拒绝都会写日志:后台会打印 邮件被拒绝:发件人=… 收件人=… 原因=…,在线发件玩家也会收到一条具体原因提示;收件人不存在、内容超长、收件箱已满同样有日志。排查发送失败先看这条日志。
  • 审核会把邮件主题和正文发给第三方,请按隐私政策告知玩家,不要泄露 API Key。

六、每日额度与付费发送

sending:
  daily-free-limit: 10
  daily-paid-limit: 20
  currency: vault
  paid-cost: 100.0
  attachment-max-bytes: 32768
  • /mail send 用免费额度,用完提示 /mail sendex;付费发送另受 daily-paid-limit 限制。管理员邮件不占玩家额度。
  • 只有投递成功才保留额度与扣费;审核拒绝、收件人不存在、邮箱满、服务异常时会自动退回次数和费用,附带物品也会退回。
  • Vault 只是桥接层,必须再装 EssentialsX / CMI 等经济实现;只装 Vault 会提示「Vault 未注册经济服务」。
  • 用 PlayerPoints 请把 currency 改成 playerpoints;插件启动日志会在 Vault 不可用却检测到 PlayerPoints 时给出这条提示。
  • 扣费失败时,玩家消息和后台日志都会显示具体原因(未安装 / 未注册经济服务 / 余额不足 / API 版本不兼容),不再只提示「请检查经济插件」。
  • 退款使用离线玩家接口,玩家掉线时也会尝试退回并在失败时记日志。

七、模板与领取邮件

模板

templates 下每个条目含 subject 与 content,支持 {player}(收件人)和 {sender}(发件人)。玩家可在 GUI 模板菜单选择,或用 /mail template <模板名> <玩家名>。

领取邮件

/mailadmin claimcommand give {player} diamond 3
/mailadmin claim Alex 新手奖励 完成新手任务后点击领取
  • 模板必须且只能包含一个 {player},只允许安全字符;分号、换行、引号、命令拼接字符会被拒绝。
  • 玩家点击领取后,由控制台执行替换后的命令;领取状态先写盘再执行命令,双击不会重复发奖。
  • 属于「最多执行一次」的取舍:若在写盘后、命令执行前服务器崩溃,可能出现已标记领取但奖励未发。建议把奖励命令设计成幂等,并保留发放日志。
  • 同样地,如果模板后来被改坏或命令执行返回失败,玩家也无法重领;请只填写可信且稳定的命令。

八、管理员 GUI 与命令

/mailadmin(GUI)提供:发送邮件、管理指定玩家邮箱、重载配置、近期上线筛选、发送领取邮件、设置领取命令。

/mailadmin                                            管理主菜单(仅玩家可用 GUI)
/mailadmin send [online|offline] <玩家> <主题> <正文>  向在线/离线玩家投递
/mailadmin recent <天数> <主题> <正文>                 近 N 天上线过的玩家群发(1–3650)
/mailadmin claim <玩家> <主题> <正文>                  发送领取邮件
/mailadmin claimcommand <命令模板>                     设置领取命令
/mailadmin listall <玩家>                              查看该玩家邮件数/未读数
/mailadmin clearall <玩家>                             清空该玩家邮箱
/mailadmin reload                                      重载配置并刷新 SMTP 设置

recent 依据服务器已知玩家的最后上线时间筛选;离线投递要求玩家曾加入过服务器。

九、数据文件与备份

文件 内容
mail/<uuid>.yml 每个玩家的邮件(含附件、领取状态)
mail/pending-attachments.yml 发送失败 / 领取失败待退回的物品
email_bindings.yml 已验证的邮箱绑定
daily_quotas.yml 每日免费 / 付费发送计数
config.yml 配置(含密钥,注意保密)

建议停服后一起备份。所有文件写入都在有界后台线程池中进行,并采用「临时文件 + 原子替换」,避免写一半崩溃损坏数据。

十、性能与并发

  • 邮件、绑定、额度读写使用独立的有界后台线程池;文件写盘采用临时文件原子替换。
  • SMTP、验证码、AI HTTP 请求全部在后台线程执行,不阻塞游戏主线程;涉及玩家、GUI、控制台命令的 Bukkit 操作回到 Paper/Folia 调度器。
  • 玩家主手物品在发送成功后才扣除;发送失败会退回,玩家离线时暂存到 pending-attachments.yml,下次登录补发。
  • 已知取舍:删除 / 清空带未领取附件的邮件不会退回物品;SMTP 队列 128;验证码与最近上线记录存在内存中,重启后重建。

十一、排障速查

现象 常见原因 处理
所有玩家都发不出邮件 moderation.enabled: true 但 Key / 模型为空,fail-closed 配好审核服务,或明确设为 false
AI 正常却一直发送失败 本地规则先于 AI 命中;AI 返回不是纯 APPROVE;接口 HTTP / 结构异常 看后台 邮件被拒绝:… 原因=… 日志;确认 moderation.local-rules: false,按日志原因修配置
某句话发不出去 服主开启了 local-rules 时的本地粗筛误伤 关掉 local-rules,或换掉正文里的域名 / IP / 邮箱写法
提示「具体原因见服务器日志」 收件人不存在、主题/正文超长、收件箱已满 看后台 邮件投递失败 / 邮件未写入 日志
游戏里收到了,真实邮箱没有 SMTP 未启用、玩家未绑定、同步被关、SMTP 队列满、投递失败 看启动日志与后台警告,逐项排查;检查垃圾邮件箱
真实邮件发件人显示成服务器名 该邮件确实是管理员 / 系统发的;或 console-sender-name 被设成玩家名 检查 mail.console-sender-name 与 smtp.from-name
邮件看着不像 HTML 客户端把 HTML 当纯文本显示,或用了只显示纯文本的客户端 查看邮件源码应有 Content-Type: text/html; charset=UTF-8 与 X-Mailer
付费提示扣费失败 没装经济实现、currency 不匹配、余额不足、API 版本不兼容 看启动日志 付费发送货币=... 与扣费失败的具体原因
领取后没拿到奖励 命令模板失效、命令执行失败、服务器在写盘后崩溃 查后台 Claim redeemed 日志;奖励命令做成幂等
recent 群发有人没收到真实邮件 邮箱满未投递成功,或 SMTP 队列 128 被占满 分批群发,看后台队列拒绝日志

十二、已知限制与未验证项

  • 存储为 YAML,没有实现 SQLite;也没有过期邮件自动清理。
  • 领取奖励为「最多执行一次」,存在写盘后崩溃导致奖励未发的窗口。
  • 删除带未领取附件的邮件会丢失物品。
  • 外部 XvMailAPI 只覆盖基础收发、未读查询、真实邮件与绑定查询,不含附件、领取邮件、群发、额度与审核管理。
  • 编译目标为 Paper API 1.21.4,源码声明 Folia 调度支持;未在真实 Paper/Folia 服务器完成装载测试,也没有自动化测试。上线前请在测试服验证启动/关闭、在线与离线收件、GUI 点击路径、SMTP 凭据、经济扣费与退款、附件与领取的并发路径。
  • 兼容范围只承诺已核对到的编译目标与源码声明,不建议宣传「兼容所有 1.21.x–26.x」。

十三、升级与重载

  • config.yml 改动后执行 /mailadmin reload,会重新读取配置并刷新 SMTP 设置;模板、额度、审核配置即时生效。
  • 领取命令模板通过 /mailadmin claimcommand 或 GUI 设置,会写回 config.yml。
  • 升级到 1.7.0 后的首次启动会执行 config-version: 2 迁移(详见第二节)。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论