2 Commits
Author SHA1 Message Date
beforegolive 07ef51040a feat(notify-all): Bark + email 合一 meta-composite,业务侧 1 行 yaml
lint / yamllint (push) Successful in 12s
2026-07-16 08:56:13 +08:00
beforegolive 3f9fa1f9c9 fix(notify-email): 修 smtps:// 下 -H + --upload-file - 不生效的 bug
lint / yamllint (push) Successful in 5m27s
curl 在 smtps:// 模式下,'-H' 头部和 '--upload-file -' body 同时给时,
实际 DATA 段几乎为空(实测 97 bytes 上行 vs 完整邮件 289 bytes),
收件人看不到 Subject 和 body。

改为:把整封邮件(From/To/Subject/MIME-Version/Content-Type/Date + 空行 +
body)拼好后从 stdin 给 curl --upload-file -,不再用 -H。

实测:上行 289 bytes,subject / body 完整到达。
2026-07-15 13:32:42 +08:00
3 changed files with 180 additions and 5 deletions
+72
View File
@@ -0,0 +1,72 @@
# notify-all
Bark iOS push + SMTP email in **one step**. Designed for zero-config when paired with
**org-level** (or instance-level) secrets on Gitea.
## Usage (极简 / recommended)
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "your build steps"
notify:
needs: build
if: always()
runs-on: ubuntu-latest
steps:
- name: notify
uses: http://gitea:3000/gitea_admin/ci-actions/notify-all@v1
with:
status: ${{ needs.build.result }}
```
That's it — Bark 推送 + 邮件发送全自动,body/title/subject 自动从 `github.*` + `inputs.status` 拼,
secret 走 org-levelgitea_admin org 已配)。
## 必传
| Input | 来源 | 说明 |
|---|---|---|
| `status` | caller → `${{ needs.build.result }}` | 唯一必传,用于拼 body / subject |
## 可选 inputs(全部有默认值)
| Input | Default | 说明 |
|---|---|---|
| `title` | `[${{ github.repository }}] ${{ github.workflow }}` | Bark 推送标题 |
| `body` | 自动拼 status / branch / commit / sha / actor / run | 通知正文(Bark + Email 共用) |
| `email_subject` | `[gitea-ci] ${{ github.repository }} - ${{ inputs.status }}` | 邮件主题 |
| `bark_device_key` | `${{ secrets.BARK_DEVICE_KEY }}` | Bark keyorg secret |
| `bark_server` | `https://api.day.app` | Bark server(自建时改) |
| `bark_group` | `gitea-ci` | Bark 分组 |
| `bark_level` | `active` | active / timeSensitive / passive / default |
| `smtp_host` | `smtp.163.com` | SMTP host |
| `smtp_port` | `465` | SMTP SSL 端口 |
| `smtp_user` | `${{ secrets.EMAIL_USER }}` | 发件邮箱(org secret |
| `smtp_pass` | `${{ secrets.EMAIL_SMTP_PASS }}` | SMTP 授权码(org secret |
| `to` | `${{ secrets.EMAIL_TO }}` | 收件邮箱(org secret |
## 依赖的 org-level secretgitea_admin org 已配)
- `BARK_DEVICE_KEY`
- `EMAIL_USER`
- `EMAIL_SMTP_PASS`
- `EMAIL_TO`
业务 repo 不需要再配 secret。
## 内部实现
`notify-all` 是 composite action,内部 chain 调 sibling action
- `uses: ./notify-bark`
- `uses: ./notify-email`
v1.1.0 tag 下三个 action 自包含,runner 拉一次仓库就够。
## 失败处理
Bark / Email 任一失败 → `::warning::` 输出 → step 仍 Success → job 不阻塞。
(继承自 `notify-bark` / `notify-email``curl --retry 2` + `if !` 包裹逻辑。)
+99
View File
@@ -0,0 +1,99 @@
name: 'Notify All'
description: 'Bark push + email in one step. Zero-config when paired with org/instance-level secrets.'
author: 'gitea_admin'
# 设计要点(2026-07-15):
# - title / body / subject 等全用 github.* + inputs.status 自动拼,业务 repo 只需传 status
# - secret 默认走 org-levelgitea_admin org 已配 BARK_DEVICE_KEY / EMAIL_USER /
# EMAIL_SMTP_PASS / EMAIL_TO 4 个 secret),业务 repo 0 secret 配置
# - Bark + Email 两个 step 在内部 chain 调 sibling action./notify-bark / ./notify-email),
# 避免业务 repo 写两个 step
inputs:
status:
description: 'Build job status (caller passes ${{ needs.<job>.result }})'
required: true
title:
description: 'Notification title'
required: false
default: "[${{ github.repository }}] ${{ github.workflow }}"
body:
description: 'Notification body (auto-built if not provided)'
required: false
default: |
status: ${{ inputs.status }}
branch: ${{ github.ref_name }}
commit: ${{ github.event.head_commit.message }}
sha: ${{ github.event.head_commit.id }}
actor: ${{ github.actor }}
run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
email_subject:
description: 'Email subject'
required: false
default: "[gitea-ci] ${{ github.repository }} - ${{ inputs.status }}"
# ----- Bark 配置(默认走 org secret -----
bark_device_key:
description: 'Bark device key (org secret)'
required: false
default: ${{ secrets.BARK_DEVICE_KEY }}
bark_server:
description: 'Bark server URL'
required: false
default: 'https://api.day.app'
bark_group:
description: 'Bark group'
required: false
default: 'gitea-ci'
bark_level:
description: 'Bark level'
required: false
default: 'active'
# ----- Email 配置(默认走 org secret + smtp.163.com -----
smtp_host:
description: 'SMTP host'
required: false
default: 'smtp.163.com'
smtp_port:
description: 'SMTP SSL port'
required: false
default: '465'
smtp_user:
description: 'SMTP user (org secret)'
required: false
default: ${{ secrets.EMAIL_USER }}
smtp_pass:
description: 'SMTP auth code (org secret)'
required: false
default: ${{ secrets.EMAIL_SMTP_PASS }}
to:
description: 'Recipient(s), comma separated'
required: false
default: ${{ secrets.EMAIL_TO }}
runs:
using: 'composite'
steps:
# 链式调用 sibling actionv1.1.0 tag 下的 notify-bark / notify-email
# 同仓库相对引用,避免每个 step 都走完整 URL + 重新拉一次仓库
- name: Push to Bark
uses: ./notify-bark
with:
device_key: ${{ inputs.bark_device_key }}
server: ${{ inputs.bark_server }}
title: ${{ inputs.title }}
body: ${{ inputs.body }}
group: ${{ inputs.bark_group }}
level: ${{ inputs.bark_level }}
- name: Send email
uses: ./notify-email
with:
smtp_host: ${{ inputs.smtp_host }}
smtp_port: ${{ inputs.smtp_port }}
smtp_user: ${{ inputs.smtp_user }}
smtp_pass: ${{ inputs.smtp_pass }}
to: ${{ inputs.to }}
subject: ${{ inputs.email_subject }}
body: ${{ inputs.body }}
+9 -5
View File
@@ -53,16 +53,20 @@ runs:
RCPT_ARGS="$RCPT_ARGS --mail-rcpt $(printf '%s' "$addr" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" RCPT_ARGS="$RCPT_ARGS --mail-rcpt $(printf '%s' "$addr" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
done done
unset IFS unset IFS
# 整封邮件拼好(headers + 空行 + body)从 stdin 给 curl --upload-file -
# 避开 "-H + --upload-file -" 组合在 smtps:// 下不生效的 bugcurl 不会把 -H
# 头部合并进 DATA 段,结果只发空 body)。v1.0.0 是这么写的,1.0.1 改成全量 stdin。
# 同时给出一个明确的 Date 头部,避免 163 反垃圾系统把无 Date 的邮件归类。
DATE_HDR=$(date -R)
EMAIL=$(printf 'From: %s\nTo: %s\nSubject: %s\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nDate: %s\n\n%s' \
"$FROM_ADDR" "$TO_ADDR" "$SUBJECT" "$DATE_HDR" "$BODY")
# shellcheck disable=SC2086 # shellcheck disable=SC2086
if ! printf '%s' "$BODY" | curl -fsS --ssl \ if ! printf '%s' "$EMAIL" | curl -fsS --ssl \
--url "smtps://${SMTP_HOST}:${SMTP_PORT}" \ --url "smtps://${SMTP_HOST}:${SMTP_PORT}" \
--user "${SMTP_USER}:${SMTP_PASS}" \ --user "${SMTP_USER}:${SMTP_PASS}" \
--mail-from "${FROM_ADDR}" \ --mail-from "${FROM_ADDR}" \
$RCPT_ARGS \ $RCPT_ARGS \
-H "Subject: ${SUBJECT}" \
-H "From: ${FROM_ADDR}" \
-H "To: ${TO_ADDR}" \
-H "Content-Type: text/plain; charset=UTF-8" \
--max-time 15 --retry 2 \ --max-time 15 --retry 2 \
--upload-file -; then --upload-file -; then
echo "::warning::Email send failed (non-fatal)" echo "::warning::Email send failed (non-fatal)"