一、邮件通知Hook的设计
邮件通知Hook是Claude Code Hooks体系中最常用的通信类Hook之一,其核心作用是在特定事件发生后自动触发邮件发送,将关键信息及时推送到相关人员手中。与轮询式检查不同,邮件Hook采用事件驱动模型,只在真正需要时发送邮件,既避免了信息过载,又确保了重要通知的及时送达。
邮件通知Hook适用于多种场景:构建部署状态变更通知、代码审查请求与结果通知、定时汇总报告(周报/月报)、异常与错误告警、审批流程通知等。通过合理设计邮件模板和触发条件,可以构建一套完整的自动化通知体系。
事件驱动
基于Claude Code Hook系统,在after/before事件触发时自动执行邮件发送脚本
多协议支持
支持SMTP协议直连发送、系统mail命令、sendmail命令等多种发送方式
模板引擎
内置邮件模板管理,支持HTML富文本格式,不同事件类型使用差异化模板
多收件人
支持单发、群发、动态收件人列表,灵活适配团队协作场景
设计原则:邮件通知Hook应遵循"必要、及时、可读"三大原则。必要指只在关键事件发生时发送;及时指邮件应在事件发生后尽快送达;可读指邮件内容结构化、重点突出、方便阅读。
二、邮件发送配置
邮件通知Hook的底层依赖邮件发送通道的配置。Claude Code本身不内置邮件发送功能,而是通过Hook脚本调用系统命令或第三方库来实现。常用的发送方式有三种:SMTP协议直连、系统mail命令、Python smtplib库。
2.1 配置SMTP服务器参数
SMTP(Simple Mail Transfer Protocol)是邮件发送的核心协议。配置SMTP需要准备以下参数:SMTP服务器地址和端口、发件人邮箱地址和授权密码(或API密钥)、SSL/TLS加密方式。常见邮件服务商的SMTP配置如下:
| 邮件服务商 | SMTP服务器 | SSL端口 | TLS端口 |
| Gmail | smtp.gmail.com | 465 | 587 |
| QQ邮箱 | smtp.qq.com | 465 | 587 |
| 163邮箱 | smtp.163.com | 465 | 587 |
| Outlook | smtp-mail.outlook.com | 465 | 587 |
| 企业微信邮箱 | smtp.exmail.qq.com | 465 | 587 |
为提高安全性,建议将SMTP配置存入环境变量而非直接写在脚本中:
# 在 ~/.bashrc 或 .env 文件中配置
export SMTP_SERVER="smtp.qq.com"
export SMTP_PORT="465"
export SMTP_USER="your@email.com"
export SMTP_PASS="your-authorization-code"
export NOTIFY_TO="team@example.com"
2.2 使用mail/sendmail命令发送
Linux系统自带的mail命令是最轻量的发送方式,适合快速集成。安装方法:
# Ubuntu/Debian
sudo apt-get install -y mailutils
# CentOS/RHEL
sudo yum install -y mailx
配置系统mail发送(/etc/mail.rc 或 ~/.mailrc):
set smtp=smtps://smtp.qq.com:465
set smtp-auth=login
set smtp-auth-user=your@email.com
set smtp-auth-password=your-authorization-code
set ssl-verify=ignore
Hook脚本中使用mail命令发送邮件:
#!/bin/bash
# mail-notify.sh - 邮件通知Hook脚本
SUBJECT="[Claude Code] 构建通知 - $(date +'%Y-%m-%d %H:%M')"
TO="team@example.com"
# 构建邮件正文
BODY="项目构建状态:${BUILD_STATUS}
构建时间:$(date)
构建版本:${VERSION}
提交信息:${COMMIT_MESSAGE}
详情请查看:${BUILD_URL}"
# 发送邮件
echo "$BODY" | mail -s "$SUBJECT" "$TO"
2.3 使用Python smtplib发送
Python的smtplib库提供了更灵活的邮件发送能力,支持HTML格式、附件、多收件人等高级功能。
#!/usr/bin/env python3
# smtp_notify.py - Python SMTP邮件发送脚本
import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
def send_email(subject, html_body, to_list):
smtp_server = os.environ.get('SMTP_SERVER', 'smtp.qq.com')
smtp_port = int(os.environ.get('SMTP_PORT', '465'))
smtp_user = os.environ.get('SMTP_USER', '')
smtp_pass = os.environ.get('SMTP_PASS', '')
from_addr = smtp_user
msg = MIMEMultipart('alternative')
msg['From'] = Header(from_addr)
msg['To'] = ', '.join(to_list)
msg['Subject'] = Header(subject, 'utf-8')
# 纯文本备用内容
text_part = MIMEText('请使用支持HTML的邮件客户端查看', 'plain', 'utf-8')
msg.attach(text_part)
# HTML正文
html_part = MIMEText(html_body, 'html', 'utf-8')
msg.attach(html_part)
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(smtp_user, smtp_pass)
server.sendmail(from_addr, to_list, msg.as_string())
print(f"邮件发送成功: {subject}")
except Exception as e:
print(f"邮件发送失败: {e}")
raise
if __name__ == '__main__':
send_email('测试邮件', '<h1>Hello</h1><p>这是一封测试邮件</p>',
['dev@example.com'])
2.4 支持HTML格式邮件模板
HTML格式邮件可以大幅提升可读性。建议使用简单的内联样式HTML模板,避免依赖外部CSS文件(邮件客户端通常会剥离外部样式)。
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background: #f5f5f5;">
<div style="background: white; border-radius: 8px; padding: 30px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
<h2 style="color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px;">
{title}
</h2>
<p style="color: #555; line-height: 1.6;">
{content}
</p>
<div style="background: #f8f9fa; border-left: 4px solid #3498db; padding: 15px; margin: 15px 0;">
{details}
</div>
<p style="color: #999; font-size: 12px; text-align: center; margin-top: 20px;">
本邮件由 Claude Code Hooks 自动发送
</p>
</div>
</body>
</html>
'''
提示:使用Python脚本的优势在于可以灵活控制邮件格式、添加附件、嵌入图片(CID方式),以及动态构建复杂邮件内容。推荐将邮件发送逻辑封装为独立的Python模块,在各Hook脚本中复用。
三、构建/部署状态邮件Hook(after)
构建/部署状态邮件是CI/CD流程中最重要的通知类型之一。通过在Claude Code的after事件Hook中插入邮件发送逻辑,可以在每次构建或部署完成后自动通知相关人员。
3.1 构建完成后自动发送状态邮件
在Hook配置中注册after事件,构建脚本执行完毕后触发邮件通知:
{
"hooks": {
"after": [
{
"match": "build:*",
"command": "bash hooks/build-notify.sh"
}
]
}
}
#!/bin/bash
# hooks/build-notify.sh - 构建状态通知Hook
BUILD_STATUS=$? # 获取上一条命令的退出状态码
PROJECT_NAME=$(basename $(pwd))
BUILD_TIME=$(date '+%Y-%m-%d %H:%M:%S')
COMMIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
if [ $BUILD_STATUS -eq 0 ]; then
STATUS_ICON="✅"
STATUS_TEXT="成功"
COLOR="green"
else
STATUS_ICON="❌"
STATUS_TEXT="失败"
COLOR="red"
fi
SUBJECT="${STATUS_ICON} [${PROJECT_NAME}] 构建${STATUS_TEXT} - ${BRANCH}@${COMMIT_HASH}"
# 使用Python脚本发送HTML格式邮件
python3 hooks/send_build_email.py \
--subject "$SUBJECT" \
--project "$PROJECT_NAME" \
--status "$STATUS_TEXT" \
--branch "$BRANCH" \
--commit "$COMMIT_HASH" \
--time "$BUILD_TIME" \
--exit-code $BUILD_STATUS
3.2 包含构建环境和版本信息
邮件正文应包含充分的上下文信息,方便接收者快速了解构建情况。建议包含以下字段:项目名称、构建版本号、代码分支和提交哈希、构建触发者、构建持续时长、构建环境(测试/预发/生产)、构建产物下载链接(如有)。
def build_status_email(project, status, branch, commit, build_time,
duration, trigger, environment, artifacts_url):
"""构建状态邮件HTML生成"""
color = "#27ae60" if status == "成功" else "#e74c3c"
icon = "✅" if status == "成功" else "❌"
html = f'''
<h2 style="color: {color};">{icon} {project} 构建{status}</h2>
<table style="width:100%; border-collapse: collapse;">
<tr><td style="padding:8px; font-weight:bold;">版本</td>
<td style="padding:8px;">{commit}</td></tr>
<tr><td style="padding:8px; font-weight:bold;">分支</td>
<td style="padding:8px;">{branch}</td></tr>
<tr><td style="padding:8px; font-weight:bold;">构建时间</td>
<td style="padding:8px;">{build_time}</td></tr>
<tr><td style="padding:8px; font-weight:bold;">耗时</td>
<td style="padding:8px;">{duration}s</td></tr>
<tr><td style="padding:8px; font-weight:bold;">触发者</td>
<td style="padding:8px;">{trigger}</td></tr>
<tr><td style="padding:8px; font-weight:bold;">环境</td>
<td style="padding:8px;">{environment}</td></tr>
</table>
<p><a href="{artifacts_url}" style="background: #3498db; color: white;
padding: 10px 20px; text-decoration: none; border-radius: 5px;">
查看构建详情 →</a></p>
'''
return html
3.3 添加构建日志链接
构建日志链接是故障排查的关键入口。建议在邮件中同时提供构建日志URL和构建产物下载链接。如果使用Jenkins、GitLab CI或GitHub Actions,可以直接集成其API获取构建详情页地址。
注意:构建失败邮件应包含错误日志的关键片段(如编译错误的前10行),帮助开发者快速定位问题,不必登录CI系统即可了解大致原因。但要注意避免在邮件中泄露敏感信息(如密码、Token等)。
3.4 成功/失败的不同邮件模板
构建成功和失败的邮件应当使用差异化的模板,突出各自关注的重点信息:
成功模板
绿色主题,突出版本号、产物链接、部署说明,鼓励团队成员更新使用
失败模板
红色主题,突出错误摘要、失败步骤、日志链接、建议操作,推动快速修复
四、代码审查请求邮件Hook
代码审查(Code Review)是保证代码质量的重要环节。通过邮件通知Hook,可以在PR/MR创建时自动发送审查请求邮件,并跟踪审查进度。
4.1 PR/MR创建时自动发送审查请求邮件
在Git平台Webhook或Claude Code的特定事件中注册Hook,当PR/MR创建时自动触发:
#!/bin/bash
# review-request.sh - 代码审查请求通知Hook
# 从环境变量或参数获取PR信息
PR_TITLE="${1}"
PR_URL="${2}"
PR_AUTHOR="${3}"
PR_DESCRIPTION="${4}"
CHANGED_FILES="${5}"
REVIEWERS="${6}"
SUBJECT="[Code Review] ${PR_TITLE} - 来自 ${PR_AUTHOR}"
python3 hooks/send_review_email.py \
--subject "$SUBJECT" \
--title "$PR_TITLE" \
--url "$PR_URL" \
--author "$PR_AUTHOR" \
--description "$PR_DESCRIPTION" \
--files "$CHANGED_FILES" \
--reviewers "$REVIEWERS" \
--deadline "$(date -d '+2 days' '+%Y-%m-%d')"
4.2 包含变更摘要和文件列表
审查请求邮件应包含足够的上下文信息,帮助审查者快速了解变更范围:
def review_request_email(title, url, author, description,
files, additions, deletions):
"""审查请求邮件HTML生成"""
file_rows = ''.join(
f'<tr><td>{f["name"]}</td>'
f'<td style="color:#27ae60;">+{f["additions"]}</td>'
f'<td style="color:#e74c3c;">-{f["deletions"]}</td></tr>'
for f in files
)
html = f'''
<h2>📝 代码审查请求</h2>
<h3>{title}</h3>
<p>作者:{author} |
变更:+{additions}/-{deletions} 行</p>
<hr>
<h4>变更描述</h4>
<p>{description}</p>
<h4>变更文件({len(files)} 个)</h4>
<table style="width:100%; border-collapse: collapse;">
<tr style="background:#f0f0f0;">
<th>文件名</th><th>新增</th><th>删除</th>
</tr>
{file_rows}
</table>
<p style="margin-top:20px;">
<a href="{url}" style="background:#3498db; color:white;
padding:10px 20px; text-decoration:none; border-radius:5px;">
前往审查 →
</a>
</p>
'''
return html
4.3 设置审查截止日期
为审查设置合理的截止日期有助于推动审查流程。建议在邮件中明确标注截止时间,并在截止时间前发送提醒邮件。提醒逻辑可通过定时任务(cron)配合Claude Code Hook实现。
最佳实践:小型变更(<100行)的审查截止时间建议为1个工作日内;中型变更(100-500行)为2个工作日内;大型变更(>500行)建议拆分审查,每个部分的截止时间为2个工作日内。
4.4 Review完成后发送确认邮件
代码审查完成后(approve或merge),应通知相关方。对PR作者而言,确认变更已合并;对其他团队成员而言,了解代码库的最新变更。
#!/bin/bash
# review-complete.sh - 审查完成通知Hook
REVIEW_ACTION="${1}" # approved / changes-requested / merged
PR_TITLE="${2}"
PR_AUTHOR="${3}"
REVIEWER="${4}"
PR_URL="${5}"
case "$REVIEW_ACTION" in
"approved")
SUBJECT="✅ [已批准] ${PR_TITLE}"
;;
"changes-requested")
SUBJECT="🔄 [需修改] ${PR_TITLE}"
;;
"merged")
SUBJECT="🎉 [已合并] ${PR_TITLE}"
;;
esac
python3 hooks/send_review_complete.py \
--subject "$SUBJECT" \
--action "$REVIEW_ACTION" \
--pr-title "$PR_TITLE" \
--author "$PR_AUTHOR" \
--reviewer "$REVIEWER" \
--url "$PR_URL"
五、定时报告邮件Hook
定时报告(周报/月报)是团队管理和项目进度跟踪的重要手段。结合Claude Code Hook与系统定时任务(cron),可以自动汇总开发数据并生成结构化报告邮件。
5.1 自动汇总周/月工作成果
通过cron定时触发Hook脚本,自动收集指定时间范围内的开发数据:
# crontab - 定时触发报告生成
# 每周一上午9点发送上周周报
0 9 * * 1 cd /path/to/project && bash hooks/weekly-report.sh
# 每月1日上午10点发送上月月报
0 10 1 * * cd /path/to/project && bash hooks/monthly-report.sh
#!/bin/bash
# weekly-report.sh - 周报生成与发送Hook
REPORT_TYPE="${1:-weekly}"
DATE_RANGE="${2:-last-week}"
echo "正在生成${REPORT_TYPE}报告..."
# 执行Python报告生成脚本
python3 hooks/generate_report.py \
--type "$REPORT_TYPE" \
--range "$DATE_RANGE" \
--output /tmp/report.html
# 发送邮件
python3 hooks/send_report_email.py \
--subject "[周报] 项目进度报告 - $(date +'%Y-%m-%d')" \
--html /tmp/report.html \
--to-list "manager@example.com,team@example.com"
5.2 包含Git统计和Issue进度
报告邮件应包含以下核心数据维度:
- Git提交统计:周期内总提交次数、参与人数、人均提交数、代码变更行数(新增/删除)
- 分支活跃度:各分支的提交分布、活跃分支Top5、新创建/已合并分支
- Issue/PR状态:周期内新增Issue数、已关闭Issue数、待处理Issue数、PR合并率
- 代码审查统计:审查请求数、平均审查时长、超时未审查数
- 构建/部署统计:构建总次数、成功率、平均构建时长、部署次数
- 异常汇总:构建失败次数、线上错误数、回滚次数
def generate_git_stats(repo_path, since_date):
"""获取指定时间范围内的Git统计数据"""
import subprocess
from datetime import datetime, timedelta
# 获取提交数量
result = subprocess.run(
['git', 'log', f'--since={since_date}',
'--oneline', '--no-merges'],
capture_output=True, text=True, cwd=repo_path
)
commits = result.stdout.strip().split('\n')
commit_count = len([c for c in commits if c])
# 获取代码变更行数
result = subprocess.run(
['git', 'log', f'--since={since_date}',
'--stat', '--no-merges'],
capture_output=True, text=True, cwd=repo_path
)
additions = 0
deletions = 0
for line in result.stdout.split('\n'):
if 'insertion' in line or 'additions' in line:
parts = line.split(',')
for part in parts:
if 'insertion' in part or 'additions' in part:
additions += int(part.strip().split()[0])
elif 'deletion' in part or 'deletions' in part:
deletions += int(part.strip().split()[0])
# 获取参与人数
result = subprocess.run(
['git', 'log', f'--since={since_date}',
'--format=%aE', '--no-merges'],
capture_output=True, text=True, cwd=repo_path
)
authors = set(result.stdout.strip().split('\n'))
return {
'commit_count': commit_count,
'author_count': len(authors),
'additions': additions,
'deletions': deletions,
}
5.3 支持多收件人分发
报告邮件通常需要发送给多个收件人或邮件组。支持灵活的收件人配置方式:
# config/email_recipients.yaml - 收件人配置
# 周报收件人
weekly:
to:
- "manager@example.com"
- "team-leads@example.com"
cc:
- "team@example.com"
bcc:
- "archive@example.com"
# 月报收件人(包含管理层)
monthly:
to:
- "manager@example.com"
- "vp@example.com"
cc:
- "team@example.com"
bcc:
- "archive@example.com"
- "stakeholders@example.com"
# 构建通知(动态收件人)
build_notify:
to: "{{trigger_author}}@example.com"
cc: "devops@example.com"
在Python脚本中读取YAML配置并发送:
import yaml
import os
def load_recipients(report_type='weekly'):
config_path = os.path.join(
os.path.dirname(__file__),
'config', 'email_recipients.yaml'
)
with open(config_path, 'r') as f:
config = yaml.safe_load(f)
return config.get(report_type, {})
def send_report(subject, html_body, report_type='weekly'):
recipients = load_recipients(report_type)
to_list = recipients.get('to', [])
cc_list = recipients.get('cc', [])
bcc_list = recipients.get('bcc', [])
# 构建邮件
msg = MIMEMultipart('mixed')
msg['To'] = ', '.join(to_list)
msg['Cc'] = ', '.join(cc_list)
msg['Subject'] = Header(subject, 'utf-8')
html_part = MIMEText(html_body, 'html', 'utf-8')
msg.attach(html_part)
# 发送(包括CC和BCC)
all_recipients = to_list + cc_list + bcc_list
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(smtp_user, smtp_pass)
server.sendmail(from_addr, all_recipients, msg.as_string())
5.4 邮件模板可定制化
为不同类型的报告设计独立的HTML模板,支持通过配置文件切换:
# config/email_templates.yaml - 邮件模板配置
templates:
weekly:
subject: "[周报] {{project}} 进度报告 {{date}}"
header_color: "#3498db"
sections:
- name: git_stats
title: "Git提交统计"
enabled: true
- name: issue_progress
title: "Issue进度"
enabled: true
- name: review_status
title: "代码审查状态"
enabled: true
- name: build_status
title: "构建/部署状态"
enabled: false
monthly:
subject: "[月报] {{project}} 月度总结 {{date}}"
header_color: "#9b59b6"
sections:
- name: git_stats
title: "Git提交统计"
enabled: true
- name: issue_progress
title: "Issue进度"
enabled: true
- name: review_status
title: "代码审查状态"
enabled: true
- name: build_status
title: "构建/部署状态"
enabled: true
- name: performance
title: "性能指标"
enabled: true
- name: team_health
title: "团队健康度"
enabled: false
核心要点总结:邮件通知Hook是Claude Code Hooks体系中的关键组件,通过合理配置SMTP参数、设计差异化邮件模板、灵活支持多收件人分发,可以实现构建状态通知、代码审查请求、定时报告邮件等场景的全面自动化。邮件发送的核心在于可靠性,建议同时配置主备邮件通道,并加入发送失败的重试机制和告警通知,确保关键信息不丢失。