diff --git a/.github/workflows/deploy-cloudflare.yml b/.github/workflows/deploy-cloudflare.yml
new file mode 100644
index 0000000..f949f9e
--- /dev/null
+++ b/.github/workflows/deploy-cloudflare.yml
@@ -0,0 +1,117 @@
+name: 🚀 Deploy cloud-mail to Cloudflare Workers
+
+on:
+ push:
+ branches: [ main ]
+ paths:
+ - "mail-worker/**"
+ - "mail-vue/**"
+ workflow_dispatch:
+
+jobs:
+ Deploy-cloud-mail:
+ name: 🏗️ Build and Deploy
+ runs-on: ubuntu-latest
+
+ env:
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ D1_DATABASE_ID: ${{ secrets.D1_DATABASE_ID }}
+ KV_NAMESPACE_ID: ${{ secrets.KV_NAMESPACE_ID }}
+ R2_BUCKET_NAME: ${{ secrets.R2_BUCKET_NAME }}
+ DOMAIN: ${{ secrets.DOMAIN }}
+ ADMIN: ${{ secrets.ADMIN }}
+ JWT_SECRET: ${{ secrets.JWT_SECRET }}
+ INIT_URL: ${{ secrets.INIT_URL }}
+
+ steps:
+ - name: ➡️ Checkout repository
+ uses: actions/checkout@v4
+
+ - name: 📦 Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+ cache: "npm"
+ cache-dependency-path: "./mail-worker/package-lock.json"
+
+ - name: 📥 Install dependencies
+ run: npm ci
+ working-directory: ./mail-worker
+
+ - name: 📡 Disable wrangler telemetry
+ working-directory: ./mail-worker
+ # 使用 -c 指定配置文件
+ run: npx wrangler telemetry disable -c wrangler-action.toml
+
+ - name: 🤫 Set Worker secrets (ignore if already exists)
+ working-directory: ./mail-worker
+ run: |
+ WORKER_NAME="cloud-mail"
+ CONFIG_FILE="wrangler-action.toml"
+ echo "🔒 Attempting to create/update secrets using '$CONFIG_FILE'."
+
+ for VAR in DOMAIN ADMIN JWT_SECRET; do
+ if [ -n "${!VAR}" ]; then
+ VAR_LOWER=$(echo "$VAR" | tr '[:upper:]' '[:lower:]')
+ echo ">> Processing secret: '$VAR_LOWER'"
+ (echo "${!VAR}" | npx wrangler secret put "$VAR_LOWER" --name "$WORKER_NAME" -c "$CONFIG_FILE") || true
+ else
+ echo "⚠️ Warning: GitHub Secret '$VAR' is not set. Skipping."
+ fi
+ done
+
+ echo "✨ Secret processing complete."
+
+ - name: 🛠️ Prepare Config and Deploy
+ working-directory: ./mail-worker
+ run: |
+ CONFIG_FILE="wrangler-action.toml"
+ echo "⚙️ Dynamically updating '$CONFIG_FILE' with binding IDs..."
+
+ # 确保 sed 命令作用于 wrangler-action.toml 文件
+ sed -i "s|\${D1_DATABASE_ID}|${D1_DATABASE_ID}|g" "$CONFIG_FILE"
+ sed -i "s|\${KV_NAMESPACE_ID}|${KV_NAMESPACE_ID}|g" "$CONFIG_FILE"
+ sed -i "s|\${R2_BUCKET_NAME}|${R2_BUCKET_NAME}|g" "$CONFIG_FILE"
+
+ echo "🚀 Configuration updated. Starting deployment..."
+ npx wrangler deploy -c "$CONFIG_FILE" | grep -v "https://.*\.workers\.dev" || true
+ echo "✅ Deployment command executed."
+
+ - name: 🗄️ Initialize Database (if INIT_URL is set)
+ run: |
+ if [ -z "$INIT_URL" ]; then
+ echo "✅ Deployment successful. INIT_URL not set, skipping initialization."
+ exit 0
+ fi
+
+ echo "⏳ Waiting 10 秒之前 before checking initialization status..."
+ sleep 10
+
+ HTTP_CODE=$(curl -s -w "%{http_code}" -o response.txt "$INIT_URL")
+ RESPONSE_BODY=$(cat response.txt)
+
+ echo "🔎 Checking response... (Status: $HTTP_CODE)"
+
+ if [ "$HTTP_CODE" = "200" ] && [ "$RESPONSE_BODY" = "初始化成功" ]; then
+ echo "🎉✅ Fresh initialization successful!"
+ elif [ "$HTTP_CODE" = "200" ]; then
+ echo "✅ Database is already initialized or in a stable state. Response: $RESPONSE_BODY"
+ else
+ echo "⚠️ Database initialization check failed with HTTP status: $HTTP_CODE. Please check your worker logs."
+ fi
+
+ - name: 📣 Notify Final Status
+ if: always()
+ run: |
+ if [ "${{ job.status }}" == "success" ]; then
+ echo "🎉🎉🎉 Hooray! Deployment completed successfully! 🎉🎉🎉"
+ else
+ echo "❌❌❌ Oh no! The deployment failed. Please check the logs above for errors. ❌❌❌"
+ fi
+
+ - name: Delete workflow runs
+ uses: GitRML/delete-workflow-runs@main
+ with:
+ retain_days: '3'
+ keep_minimum_runs: '0'
\ No newline at end of file
diff --git a/README.md b/README.md
index 3cc962c..ad92521 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
@@ -22,11 +22,11 @@
[**👉 小白保姆教程-界面部署**](https://doc.skymail.ink)
-|  |  |
-|---------------------|---------------------|
-|  |  |
-|  |  |
-|  |  |
+|  |  |
+|--------------------------|---------------------|
+|  |  |
+|  |  |
+|  |  |
@@ -153,16 +153,8 @@ jwt_secret = "" #登录身份令牌的密钥,随便填一串字符串
6. 部署完成登录网站,使用管理员账号可以在设置页面添加配置 R2域名 Turnstile密钥 等
-**邮件发送**
-
-1. 在 resend 官网注册后,点击左侧 Domains 添加并验证你的域名,等待验证完成
-2. 点击左侧 Api Keys 创建立api key, 复制token回到项目网站设置页面添加 resend token
-
-3. 点击左侧 Webhooks 添加回调地址 https://你的项目域名/api/webhooks
-
- 勾选✅ (email.bounced email.complained email.delivered email.delivery_delayed)
-
+[👉 使用 Github Action 部署](/doc/github-action.md)
**本地运行**
@@ -175,6 +167,14 @@ jwt_secret = "" #登录身份令牌的密钥,随便填一串字符串
3. 本地运行项目设置页面r2域名可设置为 http://127.0.0.1:8787/api/file
+**邮件发送**
+
+1. 在 resend 官网注册后,点击左侧 Domains 添加并验证你的域名,等待验证完成
+2. 点击左侧 Api Keys 创建立api key, 复制token回到项目网站设置页面添加 resend token
+
+3. 点击左侧 Webhooks 添加回调地址 https://你的项目域名/api/webhooks
+
+ 勾选✅ (email.bounced email.complained email.delivered email.delivery_delayed)
## 目录结构
diff --git a/demo/demo1.png b/doc/demo/demo1.png
similarity index 100%
rename from demo/demo1.png
rename to doc/demo/demo1.png
diff --git a/demo/demo2.png b/doc/demo/demo2.png
similarity index 100%
rename from demo/demo2.png
rename to doc/demo/demo2.png
diff --git a/demo/demo3.png b/doc/demo/demo3.png
similarity index 100%
rename from demo/demo3.png
rename to doc/demo/demo3.png
diff --git a/demo/demo4.png b/doc/demo/demo4.png
similarity index 100%
rename from demo/demo4.png
rename to doc/demo/demo4.png
diff --git a/demo/demo5.png b/doc/demo/demo5.png
similarity index 100%
rename from demo/demo5.png
rename to doc/demo/demo5.png
diff --git a/demo/demo6.png b/doc/demo/demo6.png
similarity index 100%
rename from demo/demo6.png
rename to doc/demo/demo6.png
diff --git a/demo/demo7.png b/doc/demo/demo7.png
similarity index 100%
rename from demo/demo7.png
rename to doc/demo/demo7.png
diff --git a/demo/demo8.png b/doc/demo/demo8.png
similarity index 100%
rename from demo/demo8.png
rename to doc/demo/demo8.png
diff --git a/demo/logo.png b/doc/demo/logo.png
similarity index 100%
rename from demo/logo.png
rename to doc/demo/logo.png
diff --git a/doc/github-action.md b/doc/github-action.md
new file mode 100644
index 0000000..8f71329
--- /dev/null
+++ b/doc/github-action.md
@@ -0,0 +1,38 @@
+## Github Action 部署
+
+**配置 Github 仓库**
+
+1. Fork 或克隆仓库 [https://github.com/eoao/cloud-mail](https://github.com/eoao/cloud-mail)
+2. 进入您的 GitHub 仓库设置
+3. 转到 Settings → Secrets and variables → Actions → New Repository secrets
+4. 添加以下 Secrets:
+
+| Secret 名称 | 必需 | 用途 |
+| ----------------------- | :--: | ----------------------------------------------------- |
+| `CLOUDFLARE_API_TOKEN` | ✅ | Cloudflare API 令牌(需要 Workers 和相关资源权限) |
+| `CLOUDFLARE_ACCOUNT_ID` | ✅ | Cloudflare 账户 ID |
+| `D1_DATABASE_ID` | ✅ | 您的 D1 数据库的 ID |
+| `KV_NAMESPACE_ID` | ✅ | 您的 KV 命名空间的 ID |
+| `R2_BUCKET_NAME` | ✅ | 您的 R2 存储桶的名称 |
+| `DOMAIN` | ✅ | 您要用于邮件服务的域名(例如 `["xx.xx"],多域名用,分隔`) |
+| `ADMIN` | ✅ | 您的管理员邮箱地址(例如 `admin@example.com`) |
+| `JWT_SECRET` | ✅ | 用于生成和验证 JWT 的随机长字符串 |
+| `INIT_URL` | ❌ | (可选)部署后用于初始化数据库的 Worker URL |
+
+---
+
+**获取 Cloudflare API 令牌**
+
+1. 访问 [Cloudflare Dashboard](https://dash.cloudflare.com/profile/api-tokens)
+2. 创建新的 API 令牌
+3. 选择"编辑 Cloudflare Workers"模板,并参照下表添加相应权限
+ 
+4. 保存令牌并复制到 GitHub Secrets 中的 `CLOUDFLARE_API_TOKEN`
+
+**获取 Cloudflare 账户 ID**
+1. 账户 ID 可以在 Cloudflare 仪表盘的账户设置中找到。
+2. 复制到 GitHub Secrets 中的 `CLOUDFLARE_ACCOUNT_ID`
+
+**运行工作流**
+1. 然后在Action页面手手动运行工作流,后续同步上游后会自动部署到 Cloudflare Workers。如未配置 `INIT_URL`,则需要手动访问 `https://你的项目域名/api/init/你的jwt_secret` 进行数据库初始化。
+2. 自动同步上游可使用bot或者手动点击Sync Upstream按钮。
\ No newline at end of file
diff --git a/mail-worker/wrangler-action.toml b/mail-worker/wrangler-action.toml
new file mode 100644
index 0000000..31bf19d
--- /dev/null
+++ b/mail-worker/wrangler-action.toml
@@ -0,0 +1,36 @@
+name = "cloud-mail"
+main = "src/index.js"
+compatibility_date = "2025-04-09"
+keep_vars = true
+
+[observability]
+enabled = true
+
+[[d1_databases]]
+binding = "db"
+database_name = "cloud-mail" # 数据库的名称
+database_id = "${D1_DATABASE_ID}" # 使用占位符引用环境变量
+
+[[kv_namespaces]]
+binding = "kv"
+id = "${KV_NAMESPACE_ID}" # 使用占位符引用环境变量
+
+[[r2_buckets]]
+binding = "r2"
+bucket_name = "${R2_BUCKET_NAME}" # 使用占位符引用环境变量
+
+[assets]
+binding = "assets" #静态资源绑定名默认不可修改
+directory = "./dist" #前端vue项目打包的静态资源存放位置,默认dist
+not_found_handling = "single-page-application"
+run_worker_first = true
+
+[triggers]
+crons = ["0 16 * * *"] #定时任务每天晚上12点执行
+
+
+#[vars]
+#orm_log = false
+#domain = [] #邮件域名可可配置多个 示例: ["example1.com","example2.com"]
+#admin = "" #管理员的邮箱 示例: admin@example.com
+#jwt_secret = "" #jwt令牌的密钥,随便填一串字符串
\ No newline at end of file