-
Notifications
You must be signed in to change notification settings - Fork 0
Feature Notifications zh
English · Tiếng Việt · 中文
自 1.3.0 起,SkimMail 可以在出事时主动告诉你,而不用你一直盯着:某个账户停止 同步、某条出口挂了、某个 OAuth 登录快要过期——而自 1.4.0 起,还包括你的规则认 为值得说一声的任何事。投递走的是你配置一次、各个功能共用的通知渠道。
这是两个不同的问题,值得分开谈,因为它们的失败方式不一样。
运维告警(“Watchtower”)回答的是:这台服务器还在干活吗? 一个三周前就悄悄停 止同步的自建邮件阅读器,比一个明显宕掉的更糟,而没人会盯着一个自己没理由打开的仪 表盘。
推送通知回答的是:有我在乎的东西到了吗? 那是另一批受众——手机前的你——也是另 一条投递路径。
- 设置 ▸ Notifications —— 推送偏好、通知渠道,以及每个渠道对哪些 Watchtower 事件触发。读设置是 viewer 级;改设置是 operator 级。
- 规则也路由进同一批渠道:设置 ▸ Rules。见规则与信号。
以上这些设置都是实例级的,不是按用户的:这个实例的每个用户共用同一组渠道和同 一份推送偏好。
| Watchtower 告警 | 推送 | |
|---|---|---|
| 回答 | 服务器还在工作吗? | 有邮件到了吗? |
| 发往 | 渠道(聊天、webhook) | 浏览器和设备 |
| 触发于 | auto-stop、出口失效、OAuth 失败 | 新邮件,或某条规则的推送动作 |
| 静默时段 | 不适用 | 适用 |
| 需要 | 一个渠道 | 一个已订阅的浏览器或一台 FCM 设备 |
告警不会被静默时段压住,这是刻意的:静默时段说的是邮件,而一个凌晨两点停掉的账户, 到早上八点还停着。
设置 ▸ Notifications ▸ Notification channels。 六种类型:
| 类型 | 你要提供什么 | 机密怎么保存 |
|---|---|---|
| Webhook | 一个 http(s) URL,外加可选的 HMAC 签名密钥 |
URL 明文,密钥加密 |
| Telegram | 一个 bot token 和一个 chat ID | token 加密 |
| Slack | 一个 incoming-webhook URL | URL 本身就是凭据——加密保存 |
| Discord | 一个 incoming-webhook URL | 加密保存 |
| Microsoft Teams | 一个 Workflows(Power Automate)URL | 加密保存 |
| Google Chat | 一个 incoming-webhook URL | 加密保存 |
所有保存的机密都是只写的:API 只说明有没有,从不说明是什么,保存时留空则保留 原值。如果某条投递错误里恰好带了凭据——比如 URL 里的 bot token——它会在错误抵达日志 或 API 之前被抹掉。
聊天类渠道收到的是纯文本渲染,这是刻意的:不用 markdown、不用 parse mode,这样 账户名或服务商的错误串里带格式字符时,也不会把消息弄坏或改形。Teams 收到的是 Adaptive Card 信封,因为旧的 O365 connector 格式已经停用。
每个渠道都有自己的 enabled 开关、自己的 Alert me when 选项,以及一个 Send test 按钮,它发一条合成事件并报告 HTTP 状态码和往返时间。测试之前请先保存 渠道。
三个事件,每个渠道上各自独立开关:
| 事件 | 何时触发 | 默认 |
|---|---|---|
account_down |
断路器在连续失败后自动停掉一个账户 | 开 |
proxy_down |
被自动停掉的账户所用的出口已推导为 down | 开 |
oauth_expiring |
被停掉的 Gmail/Outlook 账户的失败看起来像认证失败 | 关 |
三者都是 auto-stop 断路器的后果,所以它们在账户被停掉的那一刻触发,而不是每次
同步失败都触发——触发条件见同步与同步健康。此外
proxy_down 还会按出口去重,冷却 30 分钟,免得一条驮着八个账户的死代理产生八条
告警。
oauth_expiring 默认关闭,因为它是个更软的信号:它是从服务商错误文本推断出来的,
而且它总是伴随同一账户的 account_down 一起到来。
Webhook 渠道收到的是一个 JSON POST:
{
"event": "account_down",
"source": "watchtower",
"message": "me@example.com stopped syncing after 3 failed attempts",
"account": "me@example.com",
"account_id": 4,
"error": "dial tcp: i/o timeout",
"failures": 3,
"app": "SkimMail",
"timestamp": 1757808000
}上述三个事件的 source 是 watchtower,规则命中则是 rule,其 event 为
rule_hit。proxy_down 里出现的是 proxy 和 proxy_id,而不是账户字段。
设置了签名密钥后,每次投递会带上:
X-SkimMail-Signature: sha256=<hex HMAC-SHA256 of the exact request body>
User-Agent: SkimMail-Watchtower
投递最多重试三次——只在网络错误或 5xx 时,退避按每次递增一秒。4xx 是终态: 被拒绝的负载是配置问题,不是暂时性问题。每个请求 10 秒超时,整个 fan-out 20 秒超 时。
投递从服务器直连发出,绝不走某个账户的出口。 webhook 指向的是你自己的 endpoint;把它路由过某个邮箱的 proxy,既出人意料,又会把“有告警”这件事泄露给那个 proxy。见连接与按账户出口。
两条彼此独立的通道,可用其一或两者:
-
Web Push(自 1.5.0)—— 标准 VAPID,不需要任何厂商账号。密钥对在首次启动时
生成并持久化,所以没什么要配置的。用
VAPID_PUBLIC+VAPID_PRIVATE(要么都 设,要么都不设)覆盖它,用VAPID_SUBJECT设置联系人。浏览器仍然需要一个 HTTPS 源和每台设备的一次授权,所以一个纯http://的局域网地址无法订阅——把 SkimMail 放到 TLS 后面,或者用一个 tunnel 插件。 -
FCM 用于移动端 —— 除非你设置
FIREBASE_ENABLED=true并让FIREBASE_CREDENTIALS指向一份 service-account JSON,否则它是关闭的。
被推送服务报告为已失效的订阅或设备 token,会在下一次发送时被自动删除,所以被吊 销的浏览器不会越积越多。
打开着的 SkimMail 标签页里的实时更新完全不用这一套:它们走应用本来就握着的 WebSocket,规则的应用内 toast 也是同一条路。
推送有一条闸门链,每一环都必须通过:
- 存在一条通道(Web Push 或 FCM);
- Enable push notifications 已打开——它默认是关的;
- 该账户在 Active accounts 里,或者那个列表为空,即代表全部;
- 当前时间在静默时段之外(任一端为
-1即关闭;窗口可以跨零点,所以 22 → 7 就是一夜); - 内容设置决定文字。
内容设置的优先顺序:Hide content 覆盖一切,给出一条通用消息。否则 Show sender 和 Show subject 各加各的部分,两个都关时你同样得到一条通用消 息。
规则的推送动作走的就是这同一条链,包括静默时段和内容设置——规则无法穿透静默窗 口推送。规则发往渠道则不同:它按渠道 id 明确路由,不会被该渠道的 Watchtower 事件开关过滤。只有渠道自身的启用开关起作用。
| 起始版本 | 1.3.0(渠道 1.4.0,Web Push 1.5.0) |
| 角色 | 读需 viewer,改需 operator |
| 渠道类型 | 6 种 |
| 渠道数量上限 | 50 |
| Webhook 重试 | 3 次;仅限 5xx 与网络错误 |
| 超时 | 每次尝试 10 秒,每次 fan-out 20 秒 |
proxy_down 冷却 |
每个出口 30 分钟 |
| 每次同步的规则命中 | 每账户 20 条,超出后丢弃并写一行日志 |
- 作用范围是实例,不是用户。 渠道、推送偏好和静默时段由登录这台服务器的所有人 共用。
- 没有投递历史。 失败写进日志;没有任何机制把失败的告警排队稍后重发。
- “Only notify for priority mail” 被保存了,但还没人用它。 它是为 AI 分类准备 的,而本版本没有 AI,所以今天没有任何代码读这个设置。
- 它默认不逐封通知。 推送在你打开之前是关的,即使打开,它说的也是“有新邮件”, 而不是“邮件在此”。
- 它不存储也不转发你的邮件。 聊天渠道收到的是关于一个事件的一行渲染文本;邮件 正文绝不会经由这条路离开服务器。
- 遇到 4xx 它不再重试,而且它不排队。告警触发时正好挂掉的 endpoint 就错过了那 条告警。
- 它不为每一次同步失败告警——只有断路器停掉账户时才会。短暂的失败体现在同步健康 看板上,而不是通知里。
- 它不发邮件。 SkimMail 没有外发邮件通道,所以没有“出事给我发邮件”这个选项。
-
同步与同步健康 —— 产生
account_down的 auto-stop - 规则与信号 —— 另一个路由进这些渠道的生产者
-
连接与按账户出口 ——
proxy_down信号,以及投递为何直 连 -
配置 ——
FIREBASE_ENABLED、VAPID_PUBLIC、VAPID_PRIVATE、VAPID_SUBJECT - 用户与角色 —— 谁能改这些设置
SkimMail · skimmail@base101.app · 2026-09-14 · commit 76610cb