slack-bot
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSlack Bot
Slack Bot
Send messages and rich content to Slack channels using Incoming Webhooks or the Slack Web API.
Build formatted announcements, marketing reports, metrics dashboards, and community updates
with Block Kit.
使用Incoming Webhook或Slack Web API向Slack频道发送消息和富内容。
借助Block Kit创建格式化的公告、营销报告、指标仪表板和社区更新。
Prerequisites
前提条件
Requires either or set in , , or
.
SLACK_WEBHOOK_URLSLACK_BOT_TOKEN.env.env.local~/.claude/.env.globalbash
source ~/.claude/.env.global 2>/dev/null
source .env 2>/dev/null
source .env.local 2>/dev/null
if [ -n "$SLACK_WEBHOOK_URL" ]; then
echo "SLACK_WEBHOOK_URL is set. Webhook mode available."
elif [ -n "$SLACK_BOT_TOKEN" ]; then
echo "SLACK_BOT_TOKEN is set. Web API mode available."
else
echo "Neither SLACK_WEBHOOK_URL nor SLACK_BOT_TOKEN is set."
echo "See the Setup Guide below to configure Slack credentials."
fiIf neither variable is set, instruct the user to follow the Setup Guide section below.
需要在、或中设置或其中一个。
.env.env.local~/.claude/.env.globalSLACK_WEBHOOK_URLSLACK_BOT_TOKENbash
source ~/.claude/.env.global 2>/dev/null
source .env 2>/dev/null
source .env.local 2>/dev/null
if [ -n "$SLACK_WEBHOOK_URL" ]; then
echo "SLACK_WEBHOOK_URL is set. Webhook mode available."
elif [ -n "$SLACK_BOT_TOKEN" ]; then
echo "SLACK_BOT_TOKEN is set. Web API mode available."
else
echo "Neither SLACK_WEBHOOK_URL nor SLACK_BOT_TOKEN is set."
echo "See the Setup Guide below to configure Slack credentials."
fi如果两个变量都未设置,请指导用户按照下方的设置指南进行配置。
Setup Guide
设置指南
Option A: Incoming Webhook (Simple)
选项A:Incoming Webhook(简易版)
Incoming Webhooks are the fastest way to post messages. They require no OAuth scopes and are
scoped to a single channel.
- Go to https://api.slack.com/apps and click Create New App > From scratch.
- Name the app (e.g., "Marketing Bot") and select your workspace.
- In the left sidebar, click Incoming Webhooks and toggle it On.
- Click Add New Webhook to Workspace at the bottom.
- Select the channel to post to and click Allow.
- Copy the Webhook URL (starts with ).
https://hooks.slack.com/services/... - Add it to your environment:
bash
echo 'SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxxx' >> .envLimitations: One webhook per channel. Cannot read messages, list channels, or reply to
threads programmatically (you must know the from a prior API response).
thread_tsIncoming Webhook是发送消息最快的方式,不需要OAuth权限范围,且仅针对单个频道。
- 访问https://api.slack.com/apps,点击**Create New App** > From scratch。
- 为应用命名(例如“Marketing Bot”)并选择你的工作区。
- 在左侧边栏中点击Incoming Webhooks,并将其切换为On。
- 点击底部的Add New Webhook to Workspace。
- 选择要发送消息的频道,然后点击Allow。
- 复制Webhook URL(以开头)。
https://hooks.slack.com/services/... - 将其添加到你的环境变量中:
bash
echo 'SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxxx' >> .env限制: 每个频道对应一个Webhook。无法以编程方式读取消息、列出频道或回复线程(你必须从之前的API响应中获取)。
thread_tsOption B: Bot Token (Full Featured)
选项B:Bot Token(全功能版)
Bot tokens give access to the full Slack Web API: post to any channel the bot is in, reply to
threads, list channels, upload files, and more.
- Go to https://api.slack.com/apps and click Create New App > From scratch.
- Name the app and select your workspace.
- In the left sidebar, click OAuth & Permissions.
- Under Bot Token Scopes, add these scopes:
- - Post messages
chat:write - - Post to channels without joining
chat:write.public - - List public channels
channels:read - - Upload files (optional, for images/reports)
files:write - - Add emoji reactions (optional)
reactions:write
- Click Install to Workspace at the top and authorize.
- Copy the Bot User OAuth Token (starts with ).
xoxb- - Add it to your environment:
bash
echo 'SLACK_BOT_TOKEN=xoxb-your-token-here' >> .env- Invite the bot to the channels it should post in: type in each channel.
/invite @YourBotName
Optional: Set a default channel for convenience:
bash
echo 'SLACK_DEFAULT_CHANNEL=#marketing' >> .envBot Token可访问完整的Slack Web API:向机器人所在的任何频道发送消息、回复线程、列出频道、上传文件等。
- 访问https://api.slack.com/apps,点击**Create New App** > From scratch。
- 为应用命名并选择你的工作区。
- 在左侧边栏中点击OAuth & Permissions。
- 在Bot Token Scopes下添加以下权限范围:
- - 发送消息
chat:write - - 无需加入即可向频道发送消息
chat:write.public - - 列出公开频道
channels:read - - 上传文件(可选,用于图片/报告)
files:write - - 添加表情反应(可选)
reactions:write
- 点击顶部的Install to Workspace并授权。
- 复制Bot User OAuth Token(以开头)。
xoxb- - 将其添加到你的环境变量中:
bash
echo 'SLACK_BOT_TOKEN=xoxb-your-token-here' >> .env- 邀请机器人加入它需要发送消息的频道:在每个频道中输入。
/invite @YourBotName
可选: 设置默认频道以方便使用:
bash
echo 'SLACK_DEFAULT_CHANNEL=#marketing' >> .envMethod 1: Incoming Webhooks
方法1:Incoming Webhooks
Send a Simple Text Message
发送简单文本消息
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello from the marketing bot!"
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello from the marketing bot!"
}'Send a Message with Username and Icon Override
发送带有用户名和图标覆盖的消息
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"text": "New blog post published!",
"username": "Marketing Bot",
"icon_emoji": ":mega:"
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"text": "New blog post published!",
"username": "Marketing Bot",
"icon_emoji": ":mega:"
}'Send a Message with Block Kit (Webhook)
使用Block Kit发送消息(Webhook版)
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New Product Launch"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Product X* is now live! Check out the announcement."
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Read the full announcement on our blog."
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Read More"
},
"url": "https://example.com/blog/launch"
}
}
]
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New Product Launch"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Product X* is now live! Check out the announcement."
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Read the full announcement on our blog."
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Read More"
},
"url": "https://example.com/blog/launch"
}
}
]
}'Method 2: Slack Web API (Bot Token)
方法2:Slack Web API(Bot Token版)
The Web API provides full control over message delivery, threading, channel management, and more.
Web API提供对消息传递、线程、频道管理等功能的完全控制。
API Base
API基础
All requests go to with the header .
https://slack.com/api/Authorization: Bearer {SLACK_BOT_TOKEN}所有请求都发送到,并携带请求头。
https://slack.com/api/Authorization: Bearer {SLACK_BOT_TOKEN}Post a Message to a Channel
向频道发送消息
bash
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"channel": "#marketing",
"text": "Weekly metrics report is ready!",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Weekly Marketing Metrics"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Here are the numbers for this week."
}
}
]
}'The response includes a (timestamp) field which identifies the message. Save this value
for threading replies:
tsbash
undefinedbash
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"channel": "#marketing",
"text": "Weekly metrics report is ready!",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Weekly Marketing Metrics"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Here are the numbers for this week."
}
}
]
}'响应中包含一个(时间戳)字段,用于标识该消息。保存此值以便后续回复线程:
tsbash
undefinedPost and capture the message timestamp for threading
发送消息并捕获时间戳用于线程回复
RESPONSE=$(curl -s -X POST "https://slack.com/api/chat.postMessage"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d '{ "channel": "#marketing", "text": "Thread parent message" }')
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d '{ "channel": "#marketing", "text": "Thread parent message" }')
MESSAGE_TS=$(echo "$RESPONSE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('ts',''))")
echo "Message timestamp: $MESSAGE_TS"
undefinedRESPONSE=$(curl -s -X POST "https://slack.com/api/chat.postMessage"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d '{ "channel": "#marketing", "text": "Thread parent message" }')
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d '{ "channel": "#marketing", "text": "Thread parent message" }')
MESSAGE_TS=$(echo "$RESPONSE" | python3 -c "import json,sys; print(json.load(sys.stdin).get('ts',''))")
echo "Message timestamp: $MESSAGE_TS"
undefinedReply to a Thread
回复线程
Use the parameter to reply inside an existing thread:
thread_tsbash
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"#marketing\",
\"thread_ts\": \"${MESSAGE_TS}\",
\"text\": \"This is a threaded reply with additional details.\"
}"To also broadcast the reply to the channel (so it appears in the main conversation as well),
add .
"reply_broadcast": true使用参数在现有线程中回复:
thread_tsbash
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"#marketing\",
\"thread_ts\": \"${MESSAGE_TS}\",
\"text\": \"This is a threaded reply with additional details.\"
}"如果希望回复同时显示在主频道对话中,可以添加。
"reply_broadcast": trueUpdate an Existing Message
更新现有消息
bash
curl -s -X POST "https://slack.com/api/chat.update" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"#marketing\",
\"ts\": \"${MESSAGE_TS}\",
\"text\": \"Updated message content.\",
\"blocks\": []
}"bash
curl -s -X POST "https://slack.com/api/chat.update" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"#marketing\",
\"ts\": \"${MESSAGE_TS}\",
\"text\": \"Updated message content.\",
\"blocks\": []
}"Delete a Message
删除消息
bash
curl -s -X POST "https://slack.com/api/chat.delete" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"#marketing\",
\"ts\": \"${MESSAGE_TS}\"
}"bash
curl -s -X POST "https://slack.com/api/chat.delete" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"#marketing\",
\"ts\": \"${MESSAGE_TS}\"
}"List Public Channels
列出公开频道
Useful for discovering which channel to post to:
bash
curl -s "https://slack.com/api/conversations.list?types=public_channel&limit=100" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for ch in data.get('channels', []):
members = ch.get('num_members', 0)
print(f\"#{ch['name']} | Members: {members} | ID: {ch['id']}\")
"用于发现要发送消息的频道:
bash
curl -s "https://slack.com/api/conversations.list?types=public_channel&limit=100" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for ch in data.get('channels', []):
members = ch.get('num_members', 0)
print(f\"#{ch['name']} | Members: {members} | ID: {ch['id']}\")
"Upload a File to a Channel
向频道上传文件
bash
curl -s -X POST "https://slack.com/api/files.uploadV2" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-F "file=@report.pdf" \
-F "filename=weekly-report.pdf" \
-F "channel_id=C0123456789" \
-F "initial_comment=Here is this week's marketing report."bash
curl -s -X POST "https://slack.com/api/files.uploadV2" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-F "file=@report.pdf" \
-F "filename=weekly-report.pdf" \
-F "channel_id=C0123456789" \
-F "initial_comment=Here is this week's marketing report."Add an Emoji Reaction
添加表情反应
bash
curl -s -X POST "https://slack.com/api/reactions.add" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"C0123456789\",
\"timestamp\": \"${MESSAGE_TS}\",
\"name\": \"white_check_mark\"
}"bash
curl -s -X POST "https://slack.com/api/reactions.add" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"channel\": \"C0123456789\",
\"timestamp\": \"${MESSAGE_TS}\",
\"name\": \"white_check_mark\"
}"Slack Block Kit Reference
Slack Block Kit参考
Block Kit is Slack's UI framework for building rich, interactive messages. Messages are composed
of an array of blocks, each with a specific type and structure.
Block Kit是Slack用于构建丰富交互式消息的UI框架。消息由一组块组成,每个块都有特定的类型和结构。
Block Types
块类型
| Block Type | Purpose | Supports mrkdwn |
|---|---|---|
| Large bold title text | No (plain_text only) |
| Primary content block with text and optional accessory | Yes |
| Horizontal line separator | N/A |
| Full-width image with alt text | N/A |
| Small, muted text and images (for metadata, timestamps) | Yes |
| Row of interactive elements (buttons, selects, date pickers) | N/A |
| Advanced formatted text (lists, quotes, code blocks) | N/A |
| 块类型 | 用途 | 支持mrkdwn |
|---|---|---|
| 大粗体标题文本 | 否(仅支持plain_text) |
| 包含文本和可选附件的主要内容块 | 是 |
| 水平分隔线 | 不适用 |
| 带替代文本的全宽图片 | 不适用 |
| 小型灰色文本和图片(用于元数据、时间戳) | 是 |
| 一行交互式元素(按钮、选择器、日期选择器) | 不适用 |
| 高级格式化文本(列表、引用、代码块) | 不适用 |
Header Block
标题块
json
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Weekly Marketing Report",
"emoji": true
}
}json
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Weekly Marketing Report",
"emoji": true
}
}Section Block
内容块
Plain text section:
json
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Traffic is up 23%* this week compared to last week.\nOrganic search drove most of the growth."
}
}Section with fields (two-column layout):
json
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Visitors*\n12,450"
},
{
"type": "mrkdwn",
"text": "*Signups*\n342"
},
{
"type": "mrkdwn",
"text": "*MRR*\n$28,500"
},
{
"type": "mrkdwn",
"text": "*Churn*\n1.2%"
}
]
}Section with a button accessory:
json
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "New blog post: *How We Grew 10x in 6 Months*"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Read Post"
},
"url": "https://example.com/blog/growth-story",
"action_id": "read_blog_post"
}
}Section with an image accessory:
json
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*New Feature: Dark Mode*\nOur most requested feature is finally here."
},
"accessory": {
"type": "image",
"image_url": "https://example.com/images/dark-mode-preview.png",
"alt_text": "Dark mode preview"
}
}纯文本内容块:
json
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Traffic is up 23%* this week compared to last week.\nOrganic search drove most of the growth."
}
}带字段的内容块(两列布局):
json
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Visitors*\n12,450"
},
{
"type": "mrkdwn",
"text": "*Signups*\n342"
},
{
"type": "mrkdwn",
"text": "*MRR*\n$28,500"
},
{
"type": "mrkdwn",
"text": "*Churn*\n1.2%"
}
]
}带按钮附件的内容块:
json
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "New blog post: *How We Grew 10x in 6 Months*"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Read Post"
},
"url": "https://example.com/blog/growth-story",
"action_id": "read_blog_post"
}
}带图片附件的内容块:
json
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*New Feature: Dark Mode*\nOur most requested feature is finally here."
},
"accessory": {
"type": "image",
"image_url": "https://example.com/images/dark-mode-preview.png",
"alt_text": "Dark mode preview"
}
}Divider Block
分隔线块
json
{
"type": "divider"
}json
{
"type": "divider"
}Image Block
图片块
json
{
"type": "image",
"image_url": "https://example.com/images/chart.png",
"alt_text": "Weekly traffic chart",
"title": {
"type": "plain_text",
"text": "Traffic Overview"
}
}json
{
"type": "image",
"image_url": "https://example.com/images/chart.png",
"alt_text": "Weekly traffic chart",
"title": {
"type": "plain_text",
"text": "Traffic Overview"
}
}Context Block
上下文块
json
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Posted by *Marketing Team* | Feb 10, 2026"
},
{
"type": "image",
"image_url": "https://example.com/logo-small.png",
"alt_text": "Company logo"
}
]
}json
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Posted by *Marketing Team* | Feb 10, 2026"
},
{
"type": "image",
"image_url": "https://example.com/logo-small.png",
"alt_text": "Company logo"
}
]
}Actions Block (Buttons)
操作块(按钮)
json
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Approve"
},
"style": "primary",
"action_id": "approve_action",
"value": "approved"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Reject"
},
"style": "danger",
"action_id": "reject_action",
"value": "rejected"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Details"
},
"url": "https://example.com/details",
"action_id": "view_details"
}
]
}Button styles: (green), (red), or omit for default (gray).
"primary""danger"Note on interactivity: Buttons with (no ) require a Request URL configured
in your Slack App settings under Interactivity & Shortcuts to receive the button click
payload. Buttons with a field open the link directly and do not require a backend.
action_idurlurljson
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Approve"
},
"style": "primary",
"action_id": "approve_action",
"value": "approved"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Reject"
},
"style": "danger",
"action_id": "reject_action",
"value": "rejected"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Details"
},
"url": "https://example.com/details",
"action_id": "view_details"
}
]
}按钮样式:(绿色)、(红色),或省略使用默认样式(灰色)。
"primary""danger"交互性说明: 带有(无)的按钮需要在Slack应用设置的Interactivity & Shortcuts中配置请求URL,以接收按钮点击负载。带有字段的按钮会直接打开链接,不需要后端支持。
action_idurlurlBlock Kit Limits
Block Kit限制
| Limit | Value |
|---|---|
| Blocks per message | 50 |
| Characters per text block | 3,000 |
| Characters per header | 150 |
| Fields per section | 10 |
| Elements per actions block | 25 |
| Elements per context block | 10 |
| 限制 | 数值 |
|---|---|
| 每条消息的块数量 | 50 |
| 每个文本块的字符数 | 3,000 |
| 每个标题的字符数 | 150 |
| 每个内容块的字段数量 | 10 |
| 每个操作块的元素数量 | 25 |
| 每个上下文块的元素数量 | 10 |
Block Kit Builder
Block Kit构建器
Use the visual builder to design and preview messages before coding them:
https://app.slack.com/block-kit-builder
使用可视化构建器在编写代码前设计和预览消息:
https://app.slack.com/block-kit-builder
Slack mrkdwn Formatting Guide
Slack mrkdwn格式指南
Slack uses its own markdown variant called mrkdwn. It differs from standard Markdown in
several ways.
| Formatting | Syntax | Example |
|---|---|---|
| Bold | | bold text |
| Italic | | italic text |
| Strikethrough | | |
| Code (inline) | | |
| Code block | | Multi-line code block |
| Blockquote | | Quoted text |
| Link | | Clickable link |
| User mention | | @username |
| Channel mention | | #channel |
| Emoji | | :rocket: |
| Bulleted list | Start line with | Bullet point |
| Numbered list | Start line with | Numbered item |
| Line break | | New line |
Important differences from standard Markdown:
- Bold uses single asterisks , not double
*bold*.**bold** - Italic uses underscores , not single asterisks.
_italic_ - Links use format with a pipe, not
<url|text>.[text](url) - Headers do not exist in mrkdwn. Use the block type instead.
header - Images cannot be inlined in mrkdwn. Use the block or
imageinstead.accessory
Slack使用自己的markdown变体mrkdwn,与标准Markdown有一些区别。
| 格式 | 语法 | 示例 |
|---|---|---|
| 粗体 | | bold text |
| 斜体 | | italic text |
| 删除线 | | |
| 行内代码 | | |
| 代码块 | | 多行代码块 |
| 引用 | | 引用文本 |
| 链接 | | 可点击链接 |
| 提及用户 | | @username |
| 提及频道 | | #channel |
| 表情 | | :rocket: |
| 项目符号列表 | 行首使用 | 项目符号 |
| 编号列表 | 行首使用 | 编号项 |
| 换行 | JSON字符串中使用 | 新行 |
与标准Markdown的主要区别:
- 粗体使用单个星号,而非双个
*bold*。**bold** - 斜体使用下划线,而非单个星号。
_italic_ - 链接使用格式,带有管道符,而非
<url|text>。[text](url) - mrkdwn中没有标题,使用块类型替代。
header - mrkdwn中无法嵌入图片,使用块或
image替代。accessory
Message Templates
消息模板
Template 1: Product Announcement
模板1:产品公告
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":rocket: New Feature: [Feature Name]",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "We just shipped *[Feature Name]* — here is what it does and why it matters.\n\n:point_right: *What it does:* [One-sentence description]\n:point_right: *Why it matters:* [Key benefit for users]\n:point_right: *How to try it:* [Quick instructions or link]"
}
},
{
"type": "image",
"image_url": "https://example.com/feature-screenshot.png",
"alt_text": "Feature screenshot"
},
{
"type": "divider"
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": ":newspaper: Read Announcement",
"emoji": true
},
"url": "https://example.com/blog/feature-launch",
"action_id": "read_announcement"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": ":play_or_pause_button: Watch Demo",
"emoji": true
},
"url": "https://example.com/demo",
"action_id": "watch_demo"
}
]
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Posted by *Product Team* | :speech_balloon: Reply in thread with questions"
}
]
}
]
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":rocket: New Feature: [Feature Name]",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "We just shipped *[Feature Name]* — here is what it does and why it matters.\n\n:point_right: *What it does:* [One-sentence description]\n:point_right: *Why it matters:* [Key benefit for users]\n:point_right: *How to try it:* [Quick instructions or link]"
}
},
{
"type": "image",
"image_url": "https://example.com/feature-screenshot.png",
"alt_text": "Feature screenshot"
},
{
"type": "divider"
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": ":newspaper: Read Announcement",
"emoji": true
},
"url": "https://example.com/blog/feature-launch",
"action_id": "read_announcement"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": ":play_or_pause_button: Watch Demo",
"emoji": true
},
"url": "https://example.com/demo",
"action_id": "watch_demo"
}
]
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Posted by *Product Team* | :speech_balloon: Reply in thread with questions"
}
]
}
]
}'Template 2: Weekly Metrics Report
模板2:每周指标报告
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":bar_chart: Weekly Marketing Metrics — Feb 3-9, 2026",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Here is this week'\''s performance snapshot."
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":globe_with_meridians: *Website Traffic*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Sessions*\n45,230 (:arrow_up: 12%)"
},
{
"type": "mrkdwn",
"text": "*Unique Visitors*\n31,870 (:arrow_up: 8%)"
},
{
"type": "mrkdwn",
"text": "*Bounce Rate*\n42.3% (:arrow_down: 2.1%)"
},
{
"type": "mrkdwn",
"text": "*Avg. Session Duration*\n3m 42s (:arrow_up: 15s)"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":money_with_wings: *Conversion Metrics*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Signups*\n487 (:arrow_up: 18%)"
},
{
"type": "mrkdwn",
"text": "*Trial-to-Paid*\n12.4% (:arrow_up: 1.2%)"
},
{
"type": "mrkdwn",
"text": "*MRR*\n$52,300 (:arrow_up: $3,200)"
},
{
"type": "mrkdwn",
"text": "*Churn*\n1.8% (:arrow_down: 0.3%)"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":email: *Email Performance*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Emails Sent*\n12,400"
},
{
"type": "mrkdwn",
"text": "*Open Rate*\n34.2%"
},
{
"type": "mrkdwn",
"text": "*Click Rate*\n4.8%"
},
{
"type": "mrkdwn",
"text": "*Unsubscribes*\n23"
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:bulb: Key Takeaways*\n- Organic traffic up 15% after publishing 3 new blog posts\n- Email welcome sequence A/B test: Variant B outperformed by 22%\n- Trial signup spike on Thursday correlated with Product Hunt feature"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Full Dashboard",
"emoji": true
},
"url": "https://analytics.example.com/dashboard",
"action_id": "view_dashboard"
}
]
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Auto-generated by Marketing Bot | Data from Google Analytics + Stripe"
}
]
}
]
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":bar_chart: Weekly Marketing Metrics — Feb 3-9, 2026",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Here is this week'\''s performance snapshot."
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":globe_with_meridians: *Website Traffic*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Sessions*\n45,230 (:arrow_up: 12%)"
},
{
"type": "mrkdwn",
"text": "*Unique Visitors*\n31,870 (:arrow_up: 8%)"
},
{
"type": "mrkdwn",
"text": "*Bounce Rate*\n42.3% (:arrow_down: 2.1%)"
},
{
"type": "mrkdwn",
"text": "*Avg. Session Duration*\n3m 42s (:arrow_up: 15s)"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":money_with_wings: *Conversion Metrics*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Signups*\n487 (:arrow_up: 18%)"
},
{
"type": "mrkdwn",
"text": "*Trial-to-Paid*\n12.4% (:arrow_up: 1.2%)"
},
{
"type": "mrkdwn",
"text": "*MRR*\n$52,300 (:arrow_up: $3,200)"
},
{
"type": "mrkdwn",
"text": "*Churn*\n1.8% (:arrow_down: 0.3%)"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":email: *Email Performance*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Emails Sent*\n12,400"
},
{
"type": "mrkdwn",
"text": "*Open Rate*\n34.2%"
},
{
"type": "mrkdwn",
"text": "*Click Rate*\n4.8%"
},
{
"type": "mrkdwn",
"text": "*Unsubscribes*\n23"
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:bulb: Key Takeaways*\n- Organic traffic up 15% after publishing 3 new blog posts\n- Email welcome sequence A/B test: Variant B outperformed by 22%\n- Trial signup spike on Thursday correlated with Product Hunt feature"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Full Dashboard",
"emoji": true
},
"url": "https://analytics.example.com/dashboard",
"action_id": "view_dashboard"
}
]
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Auto-generated by Marketing Bot | Data from Google Analytics + Stripe"
}
]
}
]
}'Template 3: Blog Post Share
模板3:博客文章分享
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":pencil: New Blog Post Published",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*<https://example.com/blog/post-slug|Blog Post Title Here>*\n\nA brief summary of what the post covers — keep it to 2-3 sentences that capture the key value and make people want to click through."
},
"accessory": {
"type": "image",
"image_url": "https://example.com/blog/post-og-image.png",
"alt_text": "Blog post cover image"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": ":bust_in_silhouette: Author: *Jane Smith* | :clock1: 6 min read | :label: SEO, Growth"
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":mega: *Help us amplify!* Share this post on your socials. Here are ready-to-use snippets:\n\n*Twitter/X:* _Just published: [title]. [Key insight from the post]. Link in reply._\n\n*LinkedIn:* _We just published a deep dive on [topic]. Here is the #1 takeaway: [insight]._"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Read the Post",
"emoji": true
},
"style": "primary",
"url": "https://example.com/blog/post-slug",
"action_id": "read_post"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Share on Twitter",
"emoji": true
},
"url": "https://twitter.com/intent/tweet?text=Check%20out%20this%20post&url=https://example.com/blog/post-slug",
"action_id": "share_twitter"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Share on LinkedIn",
"emoji": true
},
"url": "https://www.linkedin.com/sharing/share-offsite/?url=https://example.com/blog/post-slug",
"action_id": "share_linkedin"
}
]
}
]
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":pencil: New Blog Post Published",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*<https://example.com/blog/post-slug|Blog Post Title Here>*\n\nA brief summary of what the post covers — keep it to 2-3 sentences that capture the key value and make people want to click through."
},
"accessory": {
"type": "image",
"image_url": "https://example.com/blog/post-og-image.png",
"alt_text": "Blog post cover image"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": ":bust_in_silhouette: Author: *Jane Smith* | :clock1: 6 min read | :label: SEO, Growth"
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":mega: *Help us amplify!* Share this post on your socials. Here are ready-to-use snippets:\n\n*Twitter/X:* _Just published: [title]. [Key insight from the post]. Link in reply._\n\n*LinkedIn:* _We just published a deep dive on [topic]. Here is the #1 takeaway: [insight]._"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Read the Post",
"emoji": true
},
"style": "primary",
"url": "https://example.com/blog/post-slug",
"action_id": "read_post"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Share on Twitter",
"emoji": true
},
"url": "https://twitter.com/intent/tweet?text=Check%20out%20this%20post&url=https://example.com/blog/post-slug",
"action_id": "share_twitter"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Share on LinkedIn",
"emoji": true
},
"url": "https://www.linkedin.com/sharing/share-offsite/?url=https://example.com/blog/post-slug",
"action_id": "share_linkedin"
}
]
}
]
}'Template 4: Team Update / Standup
模板4:团队更新/站会
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":clipboard: Marketing Team Update — Monday, Feb 10",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:white_check_mark: Completed Last Week*\n- Launched email welcome sequence v2\n- Published 3 blog posts (SEO, product, case study)\n- Set up Google Ads remarketing campaign\n- Shipped landing page A/B test (Variant B live)"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:construction: In Progress*\n- Content calendar for March (70% done)\n- Competitor analysis report (due Wednesday)\n- Social media campaign for Product Hunt launch"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:dart: This Week'\''s Priorities*\n1. Finalize Product Hunt launch assets\n2. Send weekly newsletter (Thursday 9am)\n3. Review and approve Q1 ad spend budget\n4. Onboard new content writer"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:warning: Blockers*\n- Waiting on design team for Product Hunt gallery images\n- Need legal review on new case study before publishing"
}
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": ":speech_balloon: Reply in thread with your own updates or questions"
}
]
}
]
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":clipboard: Marketing Team Update — Monday, Feb 10",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:white_check_mark: Completed Last Week*\n- Launched email welcome sequence v2\n- Published 3 blog posts (SEO, product, case study)\n- Set up Google Ads remarketing campaign\n- Shipped landing page A/B test (Variant B live)"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:construction: In Progress*\n- Content calendar for March (70% done)\n- Competitor analysis report (due Wednesday)\n- Social media campaign for Product Hunt launch"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:dart: This Week'\''s Priorities*\n1. Finalize Product Hunt launch assets\n2. Send weekly newsletter (Thursday 9am)\n3. Review and approve Q1 ad spend budget\n4. Onboard new content writer"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*:warning: Blockers*\n- Waiting on design team for Product Hunt gallery images\n- Need legal review on new case study before publishing"
}
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": ":speech_balloon: Reply in thread with your own updates or questions"
}
]
}
]
}'Template 5: Incident / Urgent Notification
模板5:事件/紧急通知
bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":rotating_light: Marketing Alert",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Issue:* [Brief description of the problem]\n*Impact:* [Who/what is affected]\n*Status:* :red_circle: Active\n*Owner:* <@U0123456>"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Details:*\n[Longer explanation. What happened, when it started, what we know so far.]"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Next Steps:*\n1. [Action item 1]\n2. [Action item 2]\n3. [Action item 3]"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Status Page"
},
"url": "https://status.example.com",
"action_id": "status_page"
}
]
}
]
}'bash
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":rotating_light: Marketing Alert",
"emoji": true
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Issue:* [Brief description of the problem]\n*Impact:* [Who/what is affected]\n*Status:* :red_circle: Active\n*Owner:* <@U0123456>"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Details:*\n[Longer explanation. What happened, when it started, what we know so far.]"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Next Steps:*\n1. [Action item 1]\n2. [Action item 2]\n3. [Action item 3]"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Status Page"
},
"url": "https://status.example.com",
"action_id": "status_page"
}
]
}
]
}'Workflows
工作流
Workflow 1: Post a Marketing Announcement
工作流1:发布营销公告
When the user asks to post an announcement, product update, or news to Slack:
- Gather details - Ask for the announcement title, body, link, image URL, and target channel.
- Choose a template - Select from the templates above or build a custom Block Kit payload.
- Build the payload - Construct the JSON with proper mrkdwn formatting.
- Preview - Show the user the full JSON payload and describe how it will render.
- Confirm - Ask the user to approve before sending.
- Send - Execute the curl command.
- Report - Show the API response. For Web API, capture the for threading.
ts
当用户要求在Slack上发布公告、产品更新或新闻时:
- 收集详情 - 询问公告标题、正文、链接、图片URL和目标频道。
- 选择模板 - 从上述模板中选择或构建自定义Block Kit负载。
- 构建负载 - 使用正确的mrkdwn格式构造JSON。
- 预览 - 向用户展示完整的JSON负载,并描述其呈现效果。
- 确认 - 在发送前请求用户批准。
- 发送 - 执行curl命令。
- 报告 - 展示API响应。对于Web API,捕获用于线程回复。
ts
Workflow 2: Post Weekly Metrics
工作流2:发布每周指标
When the user asks to send a metrics report or dashboard to Slack:
- Collect metrics - Ask for the numbers or help pull them from analytics tools.
- Format with fields - Use section blocks with for the two-column metric layout.
fields - Add context - Include week-over-week comparisons with arrow emoji.
- Add takeaways - Summarize 2-3 key insights in a section block.
- Include a dashboard link - Add a button to the full analytics dashboard.
- Send and thread - Post the main report, then thread detailed breakdowns as replies.
当用户要求在Slack上发送指标报告或仪表板时:
- 收集指标 - 询问具体数值或协助从分析工具中获取。
- 使用字段格式化 - 使用带有的内容块实现两列指标布局。
fields - 添加上下文 - 包含周环比数据,并使用箭头表情。
- 添加关键结论 - 在内容块中总结2-3个关键见解。
- 添加仪表板链接 - 添加指向完整分析仪表板的按钮。
- 发送并回复线程 - 发布主报告,然后在线程中回复详细的细分内容。
Workflow 3: Share a Blog Post
工作流3:分享博客文章
When a new blog post needs to be distributed to the team:
- Get the URL - Ask for the blog post URL, or fetch the latest from the blog.
- Extract metadata - Use WebFetch to pull the title, description, author, and OG image.
- Build the share message - Use Template 3 with social amplification snippets.
- Add share buttons - Include Twitter and LinkedIn intent URLs pre-populated with the post.
- Post to the channel - Send to the team marketing channel.
当需要向团队分发新博客文章时:
- 获取URL - 询问博客文章URL,或从博客中获取最新文章。
- 提取元数据 - 使用WebFetch获取标题、描述、作者和OG图片。
- 构建分享消息 - 使用模板3,并添加社交推广片段。
- 添加分享按钮 - 包含预填充文章信息的Twitter和LinkedIn意图URL。
- 发布到频道 - 发送到团队营销频道。
Workflow 4: Community Engagement
工作流4:社区互动
For managing Slack community channels (public communities, customer channels):
- Welcome messages - Post a welcome message with rules and resources when new members join.
- Scheduled updates - Post weekly roundups of popular discussions or new resources.
- Event announcements - Share upcoming webinars, AMAs, or meetups with RSVP buttons.
- Polls and feedback - Use actions blocks with buttons to collect quick feedback.
- Thread management - Reply to existing threads with updates or answers.
用于管理Slack社区频道(公共社区、客户频道):
- 欢迎消息 - 当新成员加入时,发布包含规则和资源的欢迎消息。
- 定时更新 - 每周发布热门讨论或新资源的汇总。
- 活动公告 - 分享即将到来的网络研讨会、AMA或线下聚会,并附带RSVP按钮。
- 投票和反馈 - 使用操作块和按钮收集快速反馈。
- 线程管理 - 在现有线程中回复更新或解答问题。
Sending Messages with Dynamic Content
发送动态内容消息
Build Payloads with Shell Variables
使用Shell变量构建负载
bash
TITLE="Product X v2.0 Released"
DESCRIPTION="Version 2.0 includes dark mode, API improvements, and 3x faster performance."
LINK="https://example.com/changelog/v2"
IMAGE_URL="https://example.com/images/v2-banner.png"
CHANNEL="#announcements"
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "$(python3 -c "
import json
payload = {
'channel': '${CHANNEL}',
'text': '${TITLE}',
'blocks': [
{
'type': 'header',
'text': {'type': 'plain_text', 'text': '${TITLE}', 'emoji': True}
},
{
'type': 'section',
'text': {'type': 'mrkdwn', 'text': '${DESCRIPTION}'}
},
{
'type': 'image',
'image_url': '${IMAGE_URL}',
'alt_text': '${TITLE}'
},
{
'type': 'actions',
'elements': [{
'type': 'button',
'text': {'type': 'plain_text', 'text': 'Learn More'},
'url': '${LINK}',
'style': 'primary',
'action_id': 'learn_more'
}]
}
]
}
print(json.dumps(payload))
")"bash
TITLE="Product X v2.0 Released"
DESCRIPTION="Version 2.0 includes dark mode, API improvements, and 3x faster performance."
LINK="https://example.com/changelog/v2"
IMAGE_URL="https://example.com/images/v2-banner.png"
CHANNEL="#announcements"
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d "$(python3 -c "
import json
payload = {
'channel': '${CHANNEL}',
'text': '${TITLE}',
'blocks': [
{
'type': 'header',
'text': {'type': 'plain_text', 'text': '${TITLE}', 'emoji': True}
},
{
'type': 'section',
'text': {'type': 'mrkdwn', 'text': '${DESCRIPTION}'}
},
{
'type': 'image',
'image_url': '${IMAGE_URL}',
'alt_text': '${TITLE}'
},
{
'type': 'actions',
'elements': [{
'type': 'button',
'text': {'type': 'plain_text', 'text': 'Learn More'},
'url': '${LINK}',
'style': 'primary',
'action_id': 'learn_more'
}]
}
]
}
print(json.dumps(payload))
")"Build Payloads from a JSON File
从JSON文件构建负载
For complex messages, write the payload to a file first:
bash
undefined对于复杂消息,先将负载写入文件:
bash
undefinedWrite the payload
写入负载
cat > /tmp/slack-message.json << 'PAYLOAD'
{
"channel": "#marketing",
"text": "Fallback text for notifications",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Message Title"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Message body with bold and italic formatting."
}
}
]
}
PAYLOAD
cat > /tmp/slack-message.json << 'PAYLOAD'
{
"channel": "#marketing",
"text": "Fallback text for notifications",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Message Title"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Message body with bold and italic formatting."
}
}
]
}
PAYLOAD
Send it
发送消息
curl -s -X POST "https://slack.com/api/chat.postMessage"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d @/tmp/slack-message.json
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d @/tmp/slack-message.json
---curl -s -X POST "https://slack.com/api/chat.postMessage"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d @/tmp/slack-message.json
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d @/tmp/slack-message.json
---Scheduled Messages
定时消息
Post a message at a specific future time using :
chat.scheduleMessagebash
undefined使用在特定未来时间发送消息:
chat.scheduleMessagebash
undefinedSchedule a message for a specific Unix timestamp
为特定Unix时间戳安排消息
Use: date -d "2026-02-12 09:00:00" +%s (Linux) or date -j -f "%Y-%m-%d %H:%M:%S" "2026-02-12 09:00:00" +%s (macOS)
使用:date -d "2026-02-12 09:00:00" +%s(Linux)或date -j -f "%Y-%m-%d %H:%M:%S" "2026-02-12 09:00:00" +%s(macOS)
SEND_AT=$(date -j -f "%Y-%m-%d %H:%M:%S" "2026-02-12 09:00:00" +%s 2>/dev/null || date -d "2026-02-12 09:00:00" +%s)
curl -s -X POST "https://slack.com/api/chat.scheduleMessage"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d "{ "channel": "#marketing", "post_at": ${SEND_AT}, "text": "Good morning team! Here is today's marketing agenda.", "blocks": [] }"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d "{ "channel": "#marketing", "post_at": ${SEND_AT}, "text": "Good morning team! Here is today's marketing agenda.", "blocks": [] }"
List scheduled messages:
```bash
curl -s "https://slack.com/api/chat.scheduledMessages.list" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" | \
python3 -c "
import json, sys, datetime
data = json.load(sys.stdin)
for msg in data.get('scheduled_messages', []):
ts = datetime.datetime.fromtimestamp(msg['post_at']).strftime('%Y-%m-%d %H:%M')
print(f\"ID: {msg['id']} | Channel: {msg['channel_id']} | Scheduled: {ts}\")
"Delete a scheduled message:
bash
curl -s -X POST "https://slack.com/api/chat.deleteScheduledMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"channel": "C0123456789",
"scheduled_message_id": "Q0123456789"
}'SEND_AT=$(date -j -f "%Y-%m-%d %H:%M:%S" "2026-02-12 09:00:00" +%s 2>/dev/null || date -d "2026-02-12 09:00:00" +%s)
curl -s -X POST "https://slack.com/api/chat.scheduleMessage"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d "{ "channel": "#marketing", "post_at": ${SEND_AT}, "text": "Good morning team! Here is today's marketing agenda.", "blocks": [] }"
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
-H "Content-Type: application/json"
-d "{ "channel": "#marketing", "post_at": ${SEND_AT}, "text": "Good morning team! Here is today's marketing agenda.", "blocks": [] }"
列出定时消息:
```bash
curl -s "https://slack.com/api/chat.scheduledMessages.list" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" | \
python3 -c "
import json, sys, datetime
data = json.load(sys.stdin)
for msg in data.get('scheduled_messages', []):
ts = datetime.datetime.fromtimestamp(msg['post_at']).strftime('%Y-%m-%d %H:%M')
print(f\"ID: {msg['id']} | Channel: {msg['channel_id']} | Scheduled: {ts}\")
"删除定时消息:
bash
curl -s -X POST "https://slack.com/api/chat.deleteScheduledMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"channel": "C0123456789",
"scheduled_message_id": "Q0123456789"
}'Multi-Channel Posting
多频道发布
Post the same message to multiple channels:
bash
CHANNELS=("#marketing" "#general" "#product")
MESSAGE='{"text":"Big announcement coming tomorrow!","blocks":[{"type":"section","text":{"type":"mrkdwn","text":":mega: *Big announcement coming tomorrow!* Stay tuned."}}]}'
for CHANNEL in "${CHANNELS[@]}"; do
echo "Posting to ${CHANNEL}..."
echo "$MESSAGE" | python3 -c "
import json, sys
msg = json.load(sys.stdin)
msg['channel'] = '${CHANNEL}'
print(json.dumps(msg))
" | curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d @- | python3 -c "
import json, sys
r = json.load(sys.stdin)
if r.get('ok'):
print(f' Sent. ts={r[\"ts\"]}')
else:
print(f' Error: {r.get(\"error\", \"unknown\")}')
"
done向多个频道发送相同消息:
bash
CHANNELS=("#marketing" "#general" "#product")
MESSAGE='{"text":"Big announcement coming tomorrow!","blocks":[{"type":"section","text":{"type":"mrkdwn","text":":mega: *Big announcement coming tomorrow!* Stay tuned."}}]}'
for CHANNEL in "${CHANNELS[@]}"; do
echo "Posting to ${CHANNEL}..."
echo "$MESSAGE" | python3 -c "
import json, sys
msg = json.load(sys.stdin)
msg['channel'] = '${CHANNEL}'
print(json.dumps(msg))
" | curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d @- | python3 -c "
import json, sys
r = json.load(sys.stdin)
if r.get('ok'):
print(f' Sent. ts={r[\"ts\"]}')
else:
print(f' Error: {r.get(\"error\", \"unknown\")}')
"
doneError Handling
错误处理
Common API Errors
常见API错误
| Error | Cause | Fix |
|---|---|---|
| Bad or expired token | Regenerate the bot token in Slack App settings |
| Bot not in channel or wrong channel name | Invite bot with |
| Bot needs to join the channel first | Invite the bot or use |
| Over 50 blocks | Split the message into multiple posts or thread replies |
| Text exceeds 40,000 characters | Shorten the message or split into parts |
| Too many requests | Wait the number of seconds in the |
| Token lacks required permission | Add the scope in OAuth & Permissions and reinstall the app |
| 错误 | 原因 | 解决方法 |
|---|---|---|
| 令牌错误或过期 | 在Slack应用设置中重新生成Bot令牌 |
| 机器人未加入频道或频道名称错误 | 使用 |
| 机器人需要先加入频道 | 邀请机器人或使用 |
| 超过50个块 | 将消息拆分为多个帖子或线程回复 |
| 文本超过40,000字符 | 缩短消息或拆分为多个部分 |
| 请求过于频繁 | 等待 |
| 令牌缺少必要的权限 | 在OAuth & Permissions中添加权限范围并重新安装应用 |
Validate a Response
验证响应
bash
RESPONSE=$(curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"channel":"#marketing","text":"Test message"}')
python3 -c "
import json, sys
r = json.loads('${RESPONSE}'.replace(\"'\", \"\"))
if r.get('ok'):
print(f'Message sent successfully. ts={r[\"ts\"]} channel={r[\"channel\"]}')
else:
print(f'Error: {r.get(\"error\", \"unknown\")}')
if r.get('response_metadata', {}).get('messages'):
for m in r['response_metadata']['messages']:
print(f' Detail: {m}')
" 2>/dev/null || echo "$RESPONSE"A more robust approach using a temp file:
bash
RESPONSE_FILE=$(mktemp)
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"channel":"#marketing","text":"Test message"}' \
-o "$RESPONSE_FILE"
python3 -c "
import json
with open('${RESPONSE_FILE}') as f:
r = json.load(f)
if r.get('ok'):
print(f'Sent. ts={r[\"ts\"]}')
else:
print(f'Error: {r.get(\"error\")}')
"
rm -f "$RESPONSE_FILE"bash
RESPONSE=$(curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"channel":"#marketing","text":"Test message"}')
python3 -c "
import json, sys
r = json.loads('${RESPONSE}'.replace(\"'\", \"\"))
if r.get('ok'):
print(f'Message sent successfully. ts={r[\"ts\"]} channel={r[\"channel\"]}')
else:
print(f'Error: {r.get(\"error\", \"unknown\")}')
if r.get('response_metadata', {}).get('messages'):
for m in r['response_metadata']['messages']:
print(f' Detail: {m}')
" 2>/dev/null || echo "$RESPONSE"使用临时文件的更可靠方法:
bash
RESPONSE_FILE=$(mktemp)
curl -s -X POST "https://slack.com/api/chat.postMessage" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"channel":"#marketing","text":"Test message"}' \
-o "$RESPONSE_FILE"
python3 -c "
import json
with open('${RESPONSE_FILE}') as f:
r = json.load(f)
if r.get('ok'):
print(f'Sent. ts={r[\"ts\"]}')
else:
print(f'Error: {r.get(\"error\")}')
"
rm -f "$RESPONSE_FILE"Tips
提示
- Always include a field alongside
text— it serves as the fallback for notifications, accessibility readers, and clients that do not support Block Kit.blocks - Use the Block Kit Builder at https://app.slack.com/block-kit-builder to visually design and preview messages before building the curl commands.
- For production workflows, use (Web API) over webhooks. It returns a message
chat.postMessageyou can use for threading, updating, and deleting.ts - Thread long reports. Post a summary as the parent message and details as threaded replies to keep channels clean.
- Use codes in
:emoji:fields withplain_textto render emoji in headers and button labels."emoji": true - Escape special characters in mrkdwn: becomes
&,&becomes<,<becomes>.> - Rate limits: Slack allows roughly 1 message per second per channel. For bulk posting, add a 1-second delay between requests.
- When posting metrics, use section for the two-column layout rather than trying to format tables in mrkdwn (Slack does not support tables).
fields - Always show the user the full message payload and ask for confirmation before posting.
- 始终在旁边包含
blocks字段——它作为通知、辅助功能阅读器和不支持Block Kit的客户端的回退内容。text - 在构建curl命令之前,使用Block Kit构建器(https://app.slack.com/block-kit-builder)可视化设计和预览消息。
- 对于生产工作流,优先使用Web API的而非Webhook,它会返回消息
chat.postMessage,可用于线程回复、更新和删除。ts - 对长报告使用线程回复。发布摘要作为父消息,详细内容作为线程回复,以保持频道整洁。
- 在字段中使用
plain_text代码并设置:emoji:,以在标题和按钮标签中渲染表情。"emoji": true - 转义mrkdwn中的特殊字符:变为
&,&变为<,<变为>。> - 速率限制:Slack允许每个频道大约每秒1条消息。对于批量发布,在请求之间添加1秒延迟。
- 发布指标时,使用内容块的实现两列布局,而不是尝试在mrkdwn中格式化表格(Slack不支持表格)。
fields - 在发布前始终向用户展示完整的消息负载并请求确认。