📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 6.8-8.9

1. 错误异常的基本描述 #

missing required email [to] field 是 Elasticsearch Watcher 在发送邮件通知时抛出的配置类异常。该错误表示 Watcher 在执行 email action 时,经过 account defaults 合并后,邮件对象的 to 字段仍然为空,导致无法构造合法的邮件消息,发送流程在真正调用 SMTP 之前就被中断。

常见现象 #

  • Watcher 执行历史中显示邮件 action 失败,错误信息为 missing required email [to] field
  • 预期的告警邮件未送达,但 SMTP 服务器侧没有任何连接或认证日志,因为邮件根本没有被构造出来。
  • Kibana 或 Elasticsearch 日志中可以看到对应 watch 的执行失败记录,但通常不会伴随网络层或 SMTP 层错误。
  • 如果 watch 配置了多个 action,只有 email action 失败,其他 action(如 webhook、index)可能正常执行。

典型报错示例:

{
  "type": "settings_exception",
  "reason": "missing required email [to] field"
}

完整异常栈通常类似下面这样:

SettingsException: missing required email [to] field
    at org.elasticsearch.xpack.watcher.actions.email.EmailAction.execute(EmailAction.java)
    at org.elasticsearch.xpack.watcher.execution.ExecutionService.executeInner(ExecutionService.java)
    Caused by: java.lang.IllegalArgumentException

2. 为什么会发生这个错误 #

Watcher 在发送邮件前,会先将 email account 中配置的 defaults 合并到当前 email action 的邮件对象上,然后再检查必填字段。关键源码逻辑如下:

// applying the defaults on missing emails fields
email = config.defaults.apply(email);
if (email.to == null) {
    throw new SettingsException("missing required email [to] field");
}
Transport transport = session.getTransport(SMTP_PROTOCOL);

整个处理流程是:watch 配置 → 模板渲染 → defaults 合并 → 必填字段校验 → SMTP 发送。错误发生在"必填字段校验"这一步,说明前面的所有环节都没有成功提供 to 字段。

常见原因包括:

  • email action 未配置 to 字段:watch 定义中 email.to 完全缺失,是最直接的原因。
  • account defaults 也未配置默认 to:即使 action 没有 to,如果对应的 email account 在 defaults.to 中提供了默认值,也可以正常发送;但如果两者都没有,就会报错。
  • 模板渲染结果为空to 字段使用了 Mustache 模板(如 {{ctx.payload._value}}),但模板渲染后结果为空字符串、null 或空数组,导致最终 to 仍为 null
  • 动态收件人来源数据缺失to 的值来自 watch 查询结果(如 {{#ctx.payload.hits.hits}}...{{/ctx.payload.hits.hits}}),但查询未返回任何数据,导致收件人列表为空。
  • 配置被后续逻辑覆盖:极少数情况下,自定义改造或插件逻辑在 defaults 合并后又将 to 字段清空。

3. 如何排查这个异常 #

建议按以下顺序定位问题:

  1. 检查 email action 配置:直接查看对应 watch 的 JSON 定义,确认 actions.<action_id>.email.to 是否存在且非空。
  2. 检查 email account 的 defaults:查看 elasticsearch.ymlxpack.notification.email.account.<account_name>.defaults.to 是否配置了默认收件人。
  3. 验证模板渲染结果:如果 to 使用了 Mustache 模板,通过 _execute API 手动执行 watch 并查看 data 输出,确认模板渲染后 to 字段的值。
  4. 检查 watch 数据来源:如果收件人来自查询结果,确认触发 watch 时的数据是否包含有效的收件人信息。
  5. 查看完整执行上下文:通过 Watcher history 查看该次执行的完整上下文,确认 actions.<action_id>.email 的最终解析结果。

4. 如何解决这个错误 #

方案一:在 email action 中显式配置 to #

这是最直接、最推荐的做法,确保无论 defaults 如何变化,每封邮件都有明确的收件人:

{
  "trigger": { "schedule": { "interval": "5m" } },
  "input": { "search": { "request": { "indices": ["logs-*"], "body": { "query": { "match_all": {} } } } } },
  "condition": { "compare": { "ctx.payload.hits.total": { "gt": 0 } } },
  "actions": {
    "send_email": {
      "email": {
        "to": ["ops@example.com", "alerts@example.com"],
        "subject": "Elasticsearch 告警:索引异常",
        "body": {
          "html": "<p>检测到 {{ctx.payload.hits.total}} 条异常日志,请及时处理。</p>"
        }
      }
    }
  }
}

方案二:在 email account defaults 中配置默认收件人 #

如果希望集中管理收件人,可以在 elasticsearch.yml 中配置默认收件人:

xpack.notification.email.account.my_account.email_defaults:
  from: "watcher@example.com"
  to: ["ops@example.com"]
xpack.notification.email.account.my_account.smtp:
  host: "smtp.example.com"
  port: 587
  user: "watcher@example.com"
  password: "xxxx"

方案三:使用动态收件人时增加兜底逻辑 #

to 来自查询结果时,建议在 watch 中增加条件判断,避免因数据缺失导致发送失败:

{
  "condition": {
    "compare": { "ctx.payload.hits.total": { "gt": 0 } }
  },
  "actions": {
    "send_email": {
      "email": {
        "to": ["{{#ctx.payload.hits.hits}} {{_source.email}} {{/ctx.payload.hits.hits}}"],
        "subject": "动态收件人告警",
        "body": { "text": "告警内容" }
      }
    }
  }
}

5. 预防建议 #

  • to 设为 watch 模板的必填参数:如果 watch 通过模板创建,在模板层面校验 to 字段不为空。
  • 对 defaults 和 watch 级配置做联合校验:在发布或更新 watch 前,验证最终的邮件对象同时具有 tofromsubject
  • 对动态收件人增加非空检查:使用脚本条件判断 to 字段渲染结果,为空时跳过邮件发送或改用其他通知方式。
  • 建立 watch 配置代码审查机制:邮件通知类 watch 的变更应重点审查收件人配置,避免无意中删除 to 字段。
  • 定期巡检 Watcher 执行历史:通过定时查询 watcher history 中最近失败的 email action,及时发现配置退化问题。
  • 修改 watch 后先通过 _execute API 测试,确认邮件能正常发送再启用实际调度。
  • 多个 email account 时注意 action 中引用的 account 名称必须与实际配置一致。
  • INFINI Console 集中查看集群告警、Watcher 执行状态、失败记录和通知渠道健康度。
  • INFINI Gateway 部署在 Elasticsearch 前端,对 Watcher 相关 REST 请求进行观测和审计。

6. 小结 #

missing required email [to] field 虽然是一个配置类错误,但背后往往涉及 watch 定义、模板渲染、defaults 合并和数据来源多个环节。排查时不应只盯着 to 字段本身,而应从"watch 配置 → 模板渲染 → defaults → 最终邮件对象"的完整链路去定位问题。修复后建议通过 _execute API 验证,并结合 INFINI Console 建立持续监控,确保告警通知链路长期可靠。

相关错误 #

附:日志上下文 #

下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:

// applying the defaults on missing emails fields
email = config.defaults.apply(email);
if (email.to == null) {
    throw new SettingsException("missing required email [to] field");
}
Transport transport = session.getTransport(SMTP_PROTOCOL);
String user = auth != null ? auth.user() : config.smtp.user;