这篇记录 Matrix 里实现消息过期、自动删除的两种常见方式。第一种是在 Synapse 服务端启用 retention,让服务器按房间策略从数据库中清理过期事件;第二种是使用 maubot 的 expiringmessages 插件,让机器人在房间里按时间撤回消息。
如果你已经按前面的 Synapse Docker Compose 文章部署了 Matrix 服务,优先建议使用服务器端 retention。机器人方案更灵活,不一定需要服务器管理员权限,但它本质上是定时撤回消息,不等同于从数据库层面清理。
一、两种方案怎么选
服务器端 retention 适合你自己管理 Synapse 服务端的场景。它的优点是策略更底层,可以由 Synapse 后台任务定期清理过期事件;缺点是需要修改 homeserver.yaml 并重启 Synapse,而且房间还需要设置 m.room.retention 状态事件。
机器人方案适合没有服务器权限、但拥有房间管理权限的场景。它通过机器人执行 redact 撤回超时消息,配置更方便;缺点是撤回操作会受机器人权限、联邦同步、客户端缓存等因素影响。
简单理解:
- 有 Synapse 管理权限:优先用
retention。 - 只有房间管理权限:可以用 maubot 机器人。
- 对安全性要求很高:不要把这两种方案理解成绝对可靠的“阅后即焚”。
二、方案一:启用 Synapse retention
先编辑 Synapse 的配置文件。Docker 部署时通常在宿主机这个位置:
nvim /root/data/docker_data/synapse/data/homeserver.yaml在 homeserver.yaml 中加入或调整下面这段配置。注意:retention: 必须顶格写,前面不能有空格,也不能缩进到其他配置项下面。
retention:
enabled: true
default_policy:
max_lifetime: 3d
allowed_lifetime_max: 3d
purge_jobs:
- interval: 1d这段配置的含义是:
enabled: true:启用 Synapse 的消息保留策略。default_policy.max_lifetime: 3d:没有单独设置房间策略的房间,默认最多保留 3 天消息事件。allowed_lifetime_max: 3d:如果房间自己设置了更长的保留时间,Synapse 会把它限制到最多 3 天。purge_jobs:配置后台清理任务。这里不写shortest_max_lifetime和longest_max_lifetime,表示这个任务覆盖所有已经过期的房间事件,每天跑一次。
时间可以按自己的服务器负载和房间规模调整。清理间隔越短,过期消息越快被处理,但数据库后台任务也会更频繁。
如果只是写 purge_jobs,还不等于所有房间都会自动按 3 天删除。purge_jobs 只是告诉 Synapse 后台清理任务什么时候跑、负责哪些生命周期范围;具体某个房间要保留多久,需要房间里有 m.room.retention 状态事件,或者在服务端配置全局默认策略。
如果你的目标不是 3 天,而是“三个月后自动删除”,不要写 3M。Synapse 的时长单位里 m 表示分钟,不表示月份;M 也不是可靠的月份单位。三个月建议按 90 天写成 90d:
retention:
enabled: true
default_policy:
max_lifetime: 90d
allowed_lifetime_max: 90d
purge_jobs:
- interval: 1d这段配置表示:没有单独设置房间策略的房间,默认保留 90 天;如果某个房间自己设置了超过 90 天的策略,也会被服务端限制到 90 天以内。房间仍然可以设置比 90 天更短的保留时间。
如果你想强制所有房间都尽量按 90 天执行,不希望房间设置成更短或更长,可以同时加上 allowed_lifetime_min:
retention:
enabled: true
default_policy:
max_lifetime: 90d
allowed_lifetime_min: 90d
allowed_lifetime_max: 90d
purge_jobs:
- interval: 1d多数自用服务器不需要强制最短保留时间,只设置 allowed_lifetime_max 更灵活。
最终推荐确认一下这段配置在文件里的缩进大概是这样:
###### 消息保留策略,存在于房间级别,遵循 MSC1763
retention:
enabled: true
default_policy:
max_lifetime: 90d
allowed_lifetime_max: 90d
purge_jobs:
- interval: 1dpurge_jobs 也可以写成按生命周期分段的高级形式,例如官方示例里会把 3 天以内和 3 天以上的房间分给不同频率的任务。但如果自己管理的是小型 Matrix 服务器,通常用上面这种不限定范围的单个任务更稳妥,不容易漏掉房间。尤其不要写成 shortest_max_lifetime: 90d 和 longest_max_lifetime: 90d 同时放在同一个任务里;那只匹配最大生命周期刚好等于 90 天的房间,容易让其他房间被跳过。
错误写法示例,retention: 前面多了一个空格,会导致 Synapse 启动时报 YAML 解析错误:
retention:如果改完后 Synapse 起不来,可以先查看出错位置附近的行号:
nl -ba /root/data/docker_data/synapse/data/homeserver.yaml | sed -n '100,125p'也可以先验证 YAML 能不能正常解析:
docker run --rm \
-v /root/data/docker_data/synapse/data:/data \
matrixdotorg/synapse:latest \
python -c 'import yaml; yaml.safe_load(open("/data/homeserver.yaml")); print("YAML OK")'修改完成后重启 Synapse:
docker compose -f /root/data/docker_data/synapse/docker-compose.yaml restart如果你的 Compose 文件就在当前目录,也可以进入目录后执行:
cd /root/data/docker_data/synapse
docker compose restart三、给房间设置过期时间
服务端启用 retention 只是打开功能。如果前面没有配置 default_policy,具体房间还需要写入 m.room.retention 状态事件;如果已经配置了全局 default_policy,这一节可以不做,除非这个房间想使用不同于全局默认值的保留时间。
以 Element 为例,进入目标房间后,在输入框执行:
/devtools打开开发者工具后,先进入“浏览房间状态”,再点击右下角“发送自定义状态事件”。不要使用“发送自定义时间线事件”,否则发送后不会出现在房间状态里,Synapse 也不会把它当作房间保留策略。

在“事件类型”里只填写事件名本身:
m.room.retention如果界面里有“状态键(State Key)”输入框,保持为空。
事件内容示例,下面表示房间消息最多保留 3 天:
{
"max_lifetime": 259200000
}这里的 max_lifetime 单位是毫秒,常见换算如下:
- 1 小时:
3600000 - 12 小时:
43200000 - 1 天:
86400000 - 3 天:
259200000 - 7 天:
604800000
发送成功后,回到“浏览房间状态”页面,应该能看到新增的 m.room.retention。点进去确认内容里有 max_lifetime: 259200000,就说明当前房间的 3 天保留策略已经写入成功。保存后,Synapse 会在后台清理任务运行时处理过期消息。
这个房间状态事件只影响当前房间。其他房间如果没有设置 m.room.retention,并且服务端也没有配置 default_policy,就不会因为 purge_jobs 写了 3 天而自动删除。
需要注意,部分客户端可能仍然保留本地缓存,或者在时间线上显示为空白事件。服务端清理不代表每个客户端界面都会立刻同步成完全一样的状态。
四、方案二:使用 maubot 机器人
如果没有 Synapse 服务器管理权限,可以使用 maubot 的 expiringmessages 插件。它会在房间中追踪新消息,并在超过设定时间后执行撤回。
项目地址:
maubot:https://github.com/maubot/maubotexpiringmessages插件:https://github.com/maubot/expiringmessages
这个方案的前提是你已经有一个可用的 maubot 实例,并且已经创建好安装了 expiringmessages 插件的机器人。
五、邀请机器人进房间
把安装好插件的机器人邀请到目标房间,然后给它足够的权限。通常至少需要把机器人提升为版主或管理员,确保它有权限撤回房间消息。
Matrix 房间里撤回消息依赖 power level。大多数房间里,撤回他人消息通常需要 50 或更高权限。如果机器人权限不足,插件即使配置成功,也无法真正删除超时消息。
六、机器人常用指令
在目标房间发送下面的指令设置消息有效期:
!expire set <duration><duration> 可以使用 d、h、m、s 组合表示天、小时、分钟和秒。
常见示例:
!expire set 7d表示新消息 7 天后过期。
!expire set 12h表示新消息 12 小时后过期。
!expire set 1d12h30m表示新消息 1 天 12 小时 30 分钟后过期。
查看当前房间设置:
!expire show取消当前房间的自动撤回:
!expire unset注意,机器人一般只会追踪设置之后发送的新消息。设置之前已经存在的历史消息,不一定会被自动纳入处理。
七、重要限制
无论使用 retention 还是机器人撤回,都不要把它当成绝对可靠的隐私销毁机制。
首先,Matrix 是联邦协议。消息一旦进入其他服务器,清理或撤回事件需要跨服务器同步。对方服务器是否及时处理、是否保留历史、客户端是否已经缓存,都不是本服务器能完全控制的。
其次,撤回不等于防截图。任何成员都可以在消息过期前截图、复制或通过客户端缓存保存内容。
最后,“阅后即焚”在 Matrix 里并不可靠。已读状态依赖客户端是否发送回执事件,也无法强制所有客户端按同一逻辑执行销毁。
更稳妥的使用场景,是在你完全控制并信任的私有服务器、内部房间中使用消息过期策略,用它减少数据库长期堆积和降低历史消息暴露面,而不是把它当成绝对安全边界。