# Public IPv4 Monitor 与邮件通知

本文档说明当前 public IPv4 monitor 与 SMTP 邮件通知能力的职责边界和运行方式。

## 当前范围

当前实现只覆盖一个很小的通知能力：

- 定期或手动检查当前公网 IPv4
- 将当前状态和变化历史持久化到 app DB
- 仅在公网 IPv4 发生变化时发送一封英文纯文本邮件

当前明确不包含：

- Namecheap API 自动更新
- IPv6 检查
- 错误告警邮件
- 重复提醒 / 升级告警
- Telegram / Slack / Discord 通知
- 完整通知中心或模板系统

## 数据存储

当前数据全部进入 app DB。

相关表：

- `public_ip_state`
  - 保存当前状态
  - 逻辑上通常只有一行
- `public_ip_history`
  - 保存首次发现和变化历史

当前不会把 public IP 状态放进 `app_config`。

## 检查结果语义

一次检查会返回以下四种结果之一：

- `first_seen`
- `unchanged`
- `changed`
- `error`

行为约束：

- `first_seen`：写入当前 IP 和首条 history，但不发通知邮件
- `unchanged`：只更新时间和状态，不写 history，不发邮件
- `changed`：更新 `previous_ipv4` / `current_ipv4` / `last_changed_at`，写入 history，并发送邮件
- `error`：保留已有有效 IP，不写伪 history，也不发邮件

## 手动检查与定时检查

手动检查入口：

- `GET /public-ip/check`

约束：

- 需要现有鉴权
- 响应不暴露 IP 本身
- 只返回非敏感检查结果

定时检查：

- 应用启动时注册 APScheduler job
- 默认每 4 小时执行一次
- 与手动检查复用同一套 public IP check + notify 逻辑

## SMTP 通知

当前通知发信复用现有 SMTP sender。

依赖的配置项：

- `SMTP_ENABLED`
- `SMTP_HOST`
- `SMTP_PORT`
- `SMTP_USERNAME`
- `SMTP_PASSWORD`
- `SMTP_FROM_NAME`
- `SMTP_FROM_ADDRESS`
- `SMTP_TO_ADDRESS`
- `SMTP_USE_STARTTLS`

其中：

- `SMTP_FROM_NAME` 用于邮件头显示名
- `From` 头会渲染成 `Name <mail@domain>`
- SMTP envelope sender 仍然使用纯邮箱地址，保持兼容性

## 通知触发条件

只有在 `changed` 时发邮件。

不会发邮件的情况：

- `first_seen`
- `unchanged`
- `error`

这使得同一 IP 状态不会被重复通知，因为在首次变更之后，后续重复检查会变成 `unchanged`。

## 邮件内容

当前邮件标题固定为：

- `Public IP changed`

正文为英文纯文本，至少包含：

- previous IP
- current IP
- detected time

当前正文还会附带一句 Namecheap trusted IP 的人工更新提示。

## 失败处理

当前通知发送是“尽力而为”的附加动作：

- public IP 状态持久化先完成
- 邮件发送失败不会回滚 public IP 状态
- 失败只记录 warning 日志

这样可以避免通知链路反过来影响主检查流程。