From 25e21fd0c7e0053aa117803eb3ac2b886be6d0b0 Mon Sep 17 00:00:00 2001 From: gitea_admin Date: Mon, 13 Jul 2026 09:36:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(notify-email):=20composite=20action=20?= =?UTF-8?q?=E9=80=9A=E8=BF=87=20SMTP=20=E5=8F=91=E9=82=AE=E4=BB=B6=20+=20l?= =?UTF-8?q?int=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - notify-email 用 curl smtps:// 协议,163/126 兼容 - self-mail 模式:USER/TO 可同账号 - 失败时 ::warning:: 不阻塞 - lint workflow: yamllint 验证 action.yml 语法 --- .gitea/workflows/lint.yml | 19 +++++++++++ notify-email/README.md | 41 +++++++++++++++++++++++ notify-email/action.yml | 69 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 .gitea/workflows/lint.yml create mode 100644 notify-email/README.md create mode 100644 notify-email/action.yml diff --git a/.gitea/workflows/lint.yml b/.gitea/workflows/lint.yml new file mode 100644 index 0000000..c9daa90 --- /dev/null +++ b/.gitea/workflows/lint.yml @@ -0,0 +1,19 @@ +name: lint +on: + push: + branches: [main] + pull_request: + branches: [main] +jobs: + yamllint: + runs-on: ubuntu-latest + container: + image: docker.io/catthehacker/ubuntu:act-latest + steps: + # runner 默认已 clone 当前仓库(ci-actions 自身)到 step 工作目录 + # 无需 actions/checkout(也避免拉 github.com) + - name: Install yamllint + run: | + apt-get update && apt-get install -y yamllint + - name: Run yamllint + run: yamllint . \ No newline at end of file diff --git a/notify-email/README.md b/notify-email/README.md new file mode 100644 index 0000000..4f9b586 --- /dev/null +++ b/notify-email/README.md @@ -0,0 +1,41 @@ +# notify-email + +通过 SMTP 发送 Gitea Actions run 结果邮件。**已验证兼容 163 / 126 邮箱**。 + +## Inputs + +| 名称 | 必填 | 默认 | 说明 | +|---|---|---|---| +| `smtp_host` | ✅ | — | 例:`smtp.163.com` | +| `smtp_port` | ❌ | `465` | SSL 端口 | +| `smtp_user` | ✅ | — | 完整邮箱地址 | +| `smtp_pass` | ✅ | — | 授权码(业务 repo 配 Gitea secret) | +| `from` | ❌ | = `smtp_user` | 发件人 | +| `to` | ✅ | — | 收件人,多个用逗号 | +| `subject` | ✅ | — | 邮件主题 | +| `body` | ✅ | — | 邮件正文(纯文本) | + +## 使用示例 + +```yaml +- uses: gitea_admin/ci-actions/notify-email@v1 + with: + smtp_host: smtp.163.com + smtp_user: ${{ secrets.EMAIL_USER }} + smtp_pass: ${{ secrets.EMAIL_SMTP_PASS }} + to: ${{ secrets.EMAIL_TO }} + subject: "[gitea-ci] ${{ github.repository }} - ${{ needs.build.result }}" + body: | + repository: ${{ github.repository }} + workflow: ${{ github.workflow }} + status: ${{ needs.build.result }} + url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} +``` + +## 安全 + +`smtp_pass` **必须**通过 Gitea secret 传入,**不要**直接写在 workflow 里。 + +## 失败处理 + +邮件发送失败时输出 `::warning::Email send failed (non-fatal)`,**不阻塞**调用方 job。 \ No newline at end of file diff --git a/notify-email/action.yml b/notify-email/action.yml new file mode 100644 index 0000000..437a194 --- /dev/null +++ b/notify-email/action.yml @@ -0,0 +1,69 @@ +name: 'Notify Email' +description: 'Send Gitea Actions run result via SMTP (163/126 compatible)' +author: 'gitea_admin' + +inputs: + smtp_host: + description: 'SMTP host (e.g. smtp.126.com)' + required: true + smtp_port: + description: 'SMTP SSL port' + required: false + default: '465' + smtp_user: + description: 'SMTP user (full email address)' + required: true + smtp_pass: + description: 'SMTP authorization code' + required: true + from: + description: 'From address' + required: false + default: ${{ inputs.smtp_user }} + to: + description: 'Recipient(s), comma separated' + required: true + subject: + description: 'Email subject' + required: true + body: + description: 'Email body (plain text)' + required: true + +runs: + using: 'composite' + steps: + - name: Send email via SMTP + shell: bash + env: + SMTP_HOST: ${{ inputs.smtp_host }} + SMTP_PORT: ${{ inputs.smtp_port }} + SMTP_USER: ${{ inputs.smtp_user }} + SMTP_PASS: ${{ inputs.smtp_pass }} + FROM_ADDR: ${{ inputs.from }} + TO_ADDR: ${{ inputs.to }} + SUBJECT: ${{ inputs.subject }} + BODY: ${{ inputs.body }} + run: | + set -u + # 构造 --mail-rcpt 参数(每个收件人一个) + RCPT_ARGS="" + IFS=',' + for addr in $TO_ADDR; do + RCPT_ARGS="$RCPT_ARGS --mail-rcpt $(printf '%s' "$addr" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" + done + unset IFS + # shellcheck disable=SC2086 + if ! printf '%s' "$BODY" | curl -fsS --ssl \ + --url "smtps://${SMTP_HOST}:${SMTP_PORT}" \ + --user "${SMTP_USER}:${SMTP_PASS}" \ + --mail-from "${FROM_ADDR}" \ + $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 \ + --upload-file -; then + echo "::warning::Email send failed (non-fatal)" + fi \ No newline at end of file