如何通过GitHub Actions循环发送含变量的邮件通知
问题描述
需要将Client-Credentials-Watchdog.yaml配置为每日定时Cron任务,实现以下功能:
- 获取所有应用的凭证详情
- 筛选出有效期不足30天的凭证
- 向每个应用的所有者(对应
Get App by ID响应中的lastModifiedBy字段)发送包含凭证信息的邮件 - 遍历所有符合条件的应用,逐个发送通知
当前实现的问题:GitHub Actions工作流仅在末尾向硬编码邮箱发送单封邮件,无法动态循环给不同所有者发送对应通知。
解决方案
步骤1:修改Groovy脚本,收集待通知数据
修改Client-Credentials-Watchdog-script.groovy,在遍历过程中收集所有需要发送通知的条目,输出为JSON格式文件供后续Actions步骤读取:
#!/usr/bin/env groovy import groovy.json.JsonSlurper import groovy.json.JsonBuilder import java.time.Instant import java.time.ZoneId import java.time.format.DateTimeFormatter def host = "example.com" def USER = System.getenv("SECRET_API_KEY") def jsonSlurper = new JsonSlurper() def notifications = [] // 获取应用列表 def getAppsListResponse = ["bash", "-c", "curl -k -s -w '\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --request GET https://${host}/v1/organizations/org/apps"].execute().text println "*** GET Apps List Response = $getAppsListResponse ***" if (getAppsListResponse.contains('200')){ println "*** Success ***" def appsArray = getAppsListResponse.find(/\[.*\]/) def appIds = appsArray.replaceAll(/\[|\]/, '').split(',').collect { it.trim().replaceAll('"', '') } println "*** App IDs: $appIds ***" for(String appId : appIds){ println "*** Processing App ID: ${appId} ***" // 获取单个应用详情 def getAppByIDResponse = ["bash", "-c", "curl -k -s -w '\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --request GET https://${host}/v1/organizations/org/apps/${appId}"].execute().text if(getAppByIDResponse.contains('200')){ println "*** App found ***" def splitStatusCode = getAppByIDResponse.split('} 200') def appDetails = jsonSlurper.parseText(splitStatusCode[0] + '}') def ownerEmail = appDetails.lastModifiedBy def appDisplayName = appDetails.attributes.find { it.name == "DisplayName" }?.value ?: appDetails.name def thirtyDaysInMs = 30 * 24 * 60 * 60 * 1000 def currentUnixTime = Instant.now().toEpochMilli() def dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()) // 遍历凭证,筛选即将过期的条目 for (def credential : appDetails.credentials){ def expiresAtUnix = credential.expiresAt if((expiresAtUnix - currentUnixTime) <= thirtyDaysInMs){ def expiresAtFormatted = dateFormatter.format(Instant.ofEpochMilli(expiresAtUnix)) notifications.add([ to: ownerEmail, appName: appDisplayName, expiresAt: expiresAtFormatted, consumerKey: credential.consumerKey ]) println "*** Added notification for ${ownerEmail} - ${appDisplayName} ***" } else { println "*** Skip sending notification ***" } } } else { println "*** App not found ***" System.exit(1) } } // 将通知列表写入JSON文件 def jsonBuilder = new JsonBuilder(notifications) new File("notifications.json").write(jsonBuilder.toPrettyString()) println "*** Generated notifications.json with ${notifications.size} entries ***" } else { println "*** Failed to fetch apps list ***" System.exit(1) }
步骤2:修改GitHub Actions工作流,实现循环发送邮件
修改Client-Credentials-Watchdog.yaml,添加定时Cron触发,读取Groovy生成的notifications.json,通过jq解析后循环调用独立邮件工作流:
name: Client-Credentials-Watchdog on: workflow_dispatch: schedule: # 每日UTC时间0点执行(可根据时区调整,如北京时间16点改为'0 8 * * *') - cron: '0 0 * * *' jobs: build: runs-on: [abc] steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install dependencies run: | sudo apt-get update && sudo apt-get install -y groovy jq - name: Generate notification list env: SECRET_API_KEY: ${{ secrets.USER }} run: groovy Client-Credentials-Watchdog-script.groovy - name: Send notifications run: | # 遍历JSON中的每个通知条目 jq -c '.[]' notifications.json | while read -r item; do TO_EMAIL=$(echo "$item" | jq -r '.to') APP_NAME=$(echo "$item" | jq -r '.appName') EXPIRES_AT=$(echo "$item" | jq -r '.expiresAt') CONSUMER_KEY=$(echo "$item" | jq -r '.consumerKey') # 调用独立邮件工作流发送通知 gh workflow run send-single-email.yml \ -f to-email="$TO_EMAIL" \ -f subject="Action Required: Renew credentials for $APP_NAME" \ -f body="Please renew the credentials for app <b>$APP_NAME</b> (Consumer Key: $CONSUMER_KEY) which will expire on $EXPIRES_AT." done
步骤3:创建独立邮件发送工作流
新建send-single-email.yml文件,用于处理单封邮件的发送逻辑:
name: Send Single Email on: workflow_dispatch: inputs: to-email: description: 'Recipient email' required: true subject: description: 'Email subject' required: true body: description: 'Email body (HTML)' required: true jobs: send-email: runs-on: [abc] steps: - name: Send Email uses: xyz/action-send-email@v4 with: from-email: 'noreply-github@example.com' to-email: ${{ github.event.inputs.to-email }} subject: ${{ github.event.inputs.subject }} email-format: 'html' body: ${{ github.event.inputs.body }}
关键说明
- 定时任务:通过
schedule字段的Cron表达式设置每日执行时间,可根据业务需求调整时区。 - 数据传递:Groovy脚本生成结构化JSON文件,统一存储所有待发送通知的核心信息,避免重复调用API。
- 循环发送:使用
jq解析JSON条目,通过gh workflow run触发独立邮件工作流,实现动态遍历发送。 - 可读性优化:将Unix时间戳转换为可读的日期格式,提升邮件内容的友好性。
内容的提问来源于stack exchange,提问作者Reddy Rohit
相关产品推荐
相关产品推荐

