Skip to content

Commit 581588a

Browse files
committed
docs(api): member notify sends the body as written and supports dry_run
The email body is now exactly the sanitized html with no platform layout, sender line, session link, footer, or subject prefix. Attribution moves to the sender display name instead. Inline style attributes are kept as written; the previous CSS property allowlist is removed. Add a dry_run request field: when true, every check runs (validation, sanitize, membership, email, preference, per-turn duplicate, hourly rate) without sending, and the response includes the exact email in a new html field.
1 parent 9b3bd99 commit 581588a

4 files changed

Lines changed: 52 additions & 16 deletions

File tree

‎api-reference/openapi.en.json‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28970,12 +28970,17 @@
2897028970
"type": "string",
2897128971
"minLength": 1,
2897228972
"maxLength": 200,
28973-
"description": "Email subject. Required, 1–200 characters. Line breaks are replaced with a space; leading/trailing whitespace is trimmed."
28973+
"description": "Email subject, used as written. Required, 1–200 characters. Line breaks are replaced with a space; leading/trailing whitespace is trimmed."
2897428974
},
2897528975
"html": {
2897628976
"type": "string",
2897728977
"maxLength": 102400,
28978-
"description": "Email body as an HTML fragment (no `<html>`/`<head>`/`<body>` wrapper needed). Required, up to 102,400 bytes of raw UTF-8 input (larger messages are clipped by common email clients), and must be non-empty after sanitization. Sanitized server-side: `<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<form>`, `<input>`, `<button>`, `<svg>`, `<meta>`, `<link>`, and `<base>` tags and all `on*` event handlers are removed; image `src` values are kept only when they are `https` — non-`https` and `data:` image sources are dropped; links are restricted to `http`, `https`, and `mailto`. Inline `style` attributes keep only common text, color, spacing, border and sizing properties; properties that can move content outside the message body (such as `position` or negative margins) and CSS `url()` values are removed."
28978+
"description": "Email body as an HTML fragment (no `<html>`/`<head>`/`<body>` wrapper needed); recipients receive it as the whole email body. Required, up to 102,400 bytes of raw UTF-8 input (larger messages are clipped by common email clients), and must be non-empty after sanitization. Sanitized server-side: `<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<form>`, `<input>`, `<button>`, `<svg>`, `<meta>`, `<link>`, and `<base>` tags and all `on*` event handlers are removed; images are kept only when their `src` is `https` — images with any other or no `src`, including `data:`, are removed; links are restricted to `http`, `https`, and `mailto`. Inline `style` attributes are kept as written."
28979+
},
28980+
"dry_run": {
28981+
"type": "boolean",
28982+
"default": false,
28983+
"description": "Check without sending. When `true`, every check runs and the response returns the exact email in `html`, but nothing is queued and neither the hourly limit nor the per-turn duplicate check is consumed. Defaults to `false`."
2897928984
}
2898028985
}
2898128986
},
@@ -28988,7 +28993,11 @@
2898828993
"items": {
2898928994
"$ref": "#/components/schemas/MemberNotifyResultItem"
2899028995
},
28991-
"description": "One result per resolved recipient, in the same order as the resolved recipient list."
28996+
"description": "One result per resolved recipient, in the same order as the resolved recipient list. With `dry_run`, each result is what a real send would return."
28997+
},
28998+
"html": {
28999+
"type": "string",
29000+
"description": "Only present when `dry_run` is `true`: the complete email HTML exactly as recipients would receive it, after sanitization."
2899229001
}
2899329002
}
2899429003
},
@@ -60136,7 +60145,7 @@
6013660145
"Platform/Members"
6013760146
],
6013860147
"x-mint": {
60139-
"content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **200 requests/minute**; **10 requests/second** per account |\n| Permissions | None — callable only with an AI SRE session credential; any other credential is rejected with `AccessDenied` |\n\n## Usage\n\n- Recipients that are not active members of the caller's account, or that have no email address on file, are skipped rather than failing the whole request.\n- Whether email is included follows each recipient's own notification preferences for this kind of message; a recipient with no preference set defaults to receiving it.\n- The email is wrapped in the standard Flashduty notification layout, credited to the caller by name, with a link back to the originating AI SRE session.\n- At most 20 emails are delivered to the same recipient through this endpoint per hour; further deliveries to that recipient in the same window are skipped with `rate_limited`.\n- Retrying the same call within the same AI SRE session turn does not send a duplicate email to a recipient who already received one; the repeat is skipped with `duplicate`.\n- Every call is recorded in the account audit log.",
60148+
"content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **200 requests/minute**; **10 requests/second** per account |\n| Permissions | None — callable only with an AI SRE session credential; any other credential is rejected with `AccessDenied` |\n\n## Usage\n\n- Recipients that are not active members of the caller's account, or that have no email address on file, are skipped rather than failing the whole request.\n- Whether email is included follows each recipient's own notification preferences for this kind of message; a recipient with no preference set defaults to receiving it.\n- Recipients receive exactly the sanitized `html` as the email body, with nothing added around it. The sender name shows the caller's name followed by \"(via AI SRE)\".\n- Set `dry_run` to `true` to run every check and get the exact email back in `html` without sending: nothing is queued, and neither the hourly limit nor the per-turn duplicate check is consumed.\n- At most 20 emails are delivered to the same recipient through this endpoint per hour; further deliveries to that recipient in the same window are skipped with `rate_limited`.\n- Retrying the same call within the same AI SRE session turn does not send a duplicate email to a recipient who already received one; the repeat is skipped with `duplicate`.\n- Every call is recorded in the account audit log.",
6014060149
"href": "/en/api-reference/platform/members/member-notify",
6014160150
"metadata": {
6014260151
"sidebarTitle": "Notify members"

‎api-reference/openapi.zh.json‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28970,12 +28970,17 @@
2897028970
"type": "string",
2897128971
"minLength": 1,
2897228972
"maxLength": 200,
28973-
"description": "邮件主题。必填,1–200 个字符;换行会被替换为空格,首尾空白会被去除。"
28973+
"description": "邮件主题,按原样使用。必填,1–200 个字符;换行会被替换为空格,首尾空白会被去除。"
2897428974
},
2897528975
"html": {
2897628976
"type": "string",
2897728977
"maxLength": 102400,
28978-
"description": "邮件正文,HTML 片段(无需 `<html>`/`<head>`/`<body>` 包裹)。必填,原始 UTF-8 内容不超过 102,400 字节(更大的正文会被常见邮件客户端截断),且清洗后不能为空。服务端会进行清洗:`<script>`、`<style>`、`<iframe>`、`<object>`、`<embed>`、`<form>`、`<input>`、`<button>`、`<svg>`、`<meta>`、`<link>`、`<base>` 标签及所有 `on*` 事件处理属性会被移除;图片 `src` 仅保留 `https`,非 `https` 及 `data:` 图片来源会被移除;链接仅允许 `http`、`https`、`mailto`。内联 `style` 属性仅保留文本、颜色、间距、边框和尺寸等常见属性;可能使内容脱离邮件正文范围的属性(如 `position`、负值 margin)以及 CSS `url()` 取值会被移除。"
28978+
"description": "邮件正文,HTML 片段(无需 `<html>`/`<head>`/`<body>` 包裹),即收件人看到的完整邮件正文。必填,原始 UTF-8 内容不超过 102,400 字节(更大的正文会被常见邮件客户端截断),且清洗后不能为空。服务端会进行清洗:`<script>`、`<style>`、`<iframe>`、`<object>`、`<embed>`、`<form>`、`<input>`、`<button>`、`<svg>`、`<meta>`、`<link>`、`<base>` 标签及所有 `on*` 事件处理属性会被移除;图片仅在 `src` 为 `https` 时保留,其他来源或没有 `src` 的图片(包括 `data:`)会被移除;链接仅允许 `http`、`https`、`mailto`。内联 `style` 属性按原样保留。"
28979+
},
28980+
"dry_run": {
28981+
"type": "boolean",
28982+
"default": false,
28983+
"description": "仅检查不发送。为 `true` 时执行全部检查,并在响应的 `html` 中返回将要发送的完整邮件,但不会入队,也不占用每小时限额和同轮次去重。默认 `false`。"
2897928984
}
2898028985
}
2898128986
},
@@ -28988,7 +28993,11 @@
2898828993
"items": {
2898928994
"$ref": "#/components/schemas/MemberNotifyResultItem"
2899028995
},
28991-
"description": "每个已解析收件人对应一条结果,顺序与解析后的收件人列表一致。"
28996+
"description": "每个已解析收件人对应一条结果,顺序与解析后的收件人列表一致。`dry_run` 时为实际发送将得到的结果。"
28997+
},
28998+
"html": {
28999+
"type": "string",
29000+
"description": "仅当 `dry_run` 为 `true` 时返回:清洗后、收件人将收到的完整邮件 HTML。"
2899229001
}
2899329002
}
2899429003
},
@@ -60136,7 +60145,7 @@
6013660145
"平台/成员管理"
6013760146
],
6013860147
"x-mint": {
60139-
"content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ----- |\n| 速率限制 | 每个账户 **200 次/分钟**;**10 次/秒** |\n| 权限要求 | 无——仅可使用 AI SRE 会话凭据调用;使用其他凭据调用会返回 AccessDenied |\n\n## 使用说明\n\n- 不是调用方账户内活跃成员、或没有邮箱地址的收件人会被跳过,不会导致整个请求失败。\n- 是否发送邮件取决于每个收件人针对此类消息的通知偏好设置;未设置偏好的收件人默认会收到邮件。\n- 邮件采用 Flashduty 统一的通知邮件样式,署名为调用方,并附带返回发起该消息的 AI SRE 会话的链接。\n- 同一收件人通过该接口每小时最多收到 20 封邮件;超出后同一窗口内该收件人的后续投递会被跳过并返回 `rate_limited`。\n- 在同一个 AI SRE 会话轮次内重复调用,不会向已收到邮件的收件人重复发送;重复的收件人会被跳过并返回 `duplicate`。\n- 每次调用都会记录到账户审计日志。",
60148+
"content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ----- |\n| 速率限制 | 每个账户 **200 次/分钟**;**10 次/秒** |\n| 权限要求 | 无——仅可使用 AI SRE 会话凭据调用;使用其他凭据调用会返回 AccessDenied |\n\n## 使用说明\n\n- 不是调用方账户内活跃成员、或没有邮箱地址的收件人会被跳过,不会导致整个请求失败。\n- 是否发送邮件取决于每个收件人针对此类消息的通知偏好设置;未设置偏好的收件人默认会收到邮件。\n- 收件人收到的邮件正文就是清洗后的 `html`,平台不会在其前后添加任何内容;发件人名称显示为调用方姓名加“(通过 AI SRE)”。\n- 将 `dry_run` 设为 `true` 可执行全部检查并在 `html` 中返回将要发送的完整邮件,但不会发送:不会入队,也不占用每小时限额和同轮次去重。\n- 同一收件人通过该接口每小时最多收到 20 封邮件;超出后同一窗口内该收件人的后续投递会被跳过并返回 `rate_limited`。\n- 在同一个 AI SRE 会话轮次内重复调用,不会向已收到邮件的收件人重复发送;重复的收件人会被跳过并返回 `duplicate`。\n- 每次调用都会记录到账户审计日志。",
6014060149
"href": "/zh/api-reference/platform/members/member-notify",
6014160150
"metadata": {
6014260151
"sidebarTitle": "通知成员"

‎api-reference/platform.openapi.en.json‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,7 +2307,7 @@
23072307
"Platform/Members"
23082308
],
23092309
"x-mint": {
2310-
"content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **200 requests/minute**; **10 requests/second** per account |\n| Permissions | None — callable only with an AI SRE session credential; any other credential is rejected with `AccessDenied` |\n\n## Usage\n\n- Recipients that are not active members of the caller's account, or that have no email address on file, are skipped rather than failing the whole request.\n- Whether email is included follows each recipient's own notification preferences for this kind of message; a recipient with no preference set defaults to receiving it.\n- The email is wrapped in the standard Flashduty notification layout, credited to the caller by name, with a link back to the originating AI SRE session.\n- At most 20 emails are delivered to the same recipient through this endpoint per hour; further deliveries to that recipient in the same window are skipped with `rate_limited`.\n- Retrying the same call within the same AI SRE session turn does not send a duplicate email to a recipient who already received one; the repeat is skipped with `duplicate`.\n- Every call is recorded in the account audit log.",
2310+
"content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **200 requests/minute**; **10 requests/second** per account |\n| Permissions | None — callable only with an AI SRE session credential; any other credential is rejected with `AccessDenied` |\n\n## Usage\n\n- Recipients that are not active members of the caller's account, or that have no email address on file, are skipped rather than failing the whole request.\n- Whether email is included follows each recipient's own notification preferences for this kind of message; a recipient with no preference set defaults to receiving it.\n- Recipients receive exactly the sanitized `html` as the email body, with nothing added around it. The sender name shows the caller's name followed by \"(via AI SRE)\".\n- Set `dry_run` to `true` to run every check and get the exact email back in `html` without sending: nothing is queued, and neither the hourly limit nor the per-turn duplicate check is consumed.\n- At most 20 emails are delivered to the same recipient through this endpoint per hour; further deliveries to that recipient in the same window are skipped with `rate_limited`.\n- Retrying the same call within the same AI SRE session turn does not send a duplicate email to a recipient who already received one; the repeat is skipped with `duplicate`.\n- Every call is recorded in the account audit log.",
23112311
"href": "/en/api-reference/platform/members/member-notify",
23122312
"metadata": {
23132313
"sidebarTitle": "Notify members"
@@ -4553,12 +4553,17 @@
45534553
"type": "string",
45544554
"minLength": 1,
45554555
"maxLength": 200,
4556-
"description": "Email subject. Required, 1–200 characters. Line breaks are replaced with a space; leading/trailing whitespace is trimmed."
4556+
"description": "Email subject, used as written. Required, 1–200 characters. Line breaks are replaced with a space; leading/trailing whitespace is trimmed."
45574557
},
45584558
"html": {
45594559
"type": "string",
45604560
"maxLength": 102400,
4561-
"description": "Email body as an HTML fragment (no `<html>`/`<head>`/`<body>` wrapper needed). Required, up to 102,400 bytes of raw UTF-8 input (larger messages are clipped by common email clients), and must be non-empty after sanitization. Sanitized server-side: `<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<form>`, `<input>`, `<button>`, `<svg>`, `<meta>`, `<link>`, and `<base>` tags and all `on*` event handlers are removed; image `src` values are kept only when they are `https` — non-`https` and `data:` image sources are dropped; links are restricted to `http`, `https`, and `mailto`. Inline `style` attributes keep only common text, color, spacing, border and sizing properties; properties that can move content outside the message body (such as `position` or negative margins) and CSS `url()` values are removed."
4561+
"description": "Email body as an HTML fragment (no `<html>`/`<head>`/`<body>` wrapper needed); recipients receive it as the whole email body. Required, up to 102,400 bytes of raw UTF-8 input (larger messages are clipped by common email clients), and must be non-empty after sanitization. Sanitized server-side: `<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<form>`, `<input>`, `<button>`, `<svg>`, `<meta>`, `<link>`, and `<base>` tags and all `on*` event handlers are removed; images are kept only when their `src` is `https` — images with any other or no `src`, including `data:`, are removed; links are restricted to `http`, `https`, and `mailto`. Inline `style` attributes are kept as written."
4562+
},
4563+
"dry_run": {
4564+
"type": "boolean",
4565+
"default": false,
4566+
"description": "Check without sending. When `true`, every check runs and the response returns the exact email in `html`, but nothing is queued and neither the hourly limit nor the per-turn duplicate check is consumed. Defaults to `false`."
45624567
}
45634568
}
45644569
},
@@ -4571,7 +4576,11 @@
45714576
"items": {
45724577
"$ref": "#/components/schemas/MemberNotifyResultItem"
45734578
},
4574-
"description": "One result per resolved recipient, in the same order as the resolved recipient list."
4579+
"description": "One result per resolved recipient, in the same order as the resolved recipient list. With `dry_run`, each result is what a real send would return."
4580+
},
4581+
"html": {
4582+
"type": "string",
4583+
"description": "Only present when `dry_run` is `true`: the complete email HTML exactly as recipients would receive it, after sanitization."
45754584
}
45764585
}
45774586
},

0 commit comments

Comments
 (0)