mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-12 02:20:12 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ae3b0d85e | ||
|
|
01e6cb1075 | ||
|
|
814f6fada2 | ||
|
|
31901aacc5 | ||
|
|
fb9b9f6ae4 | ||
|
|
095951ab45 | ||
|
|
37614ce6fa | ||
|
|
3f81fbee6d | ||
|
|
cf13236e7b | ||
|
|
36e9c611e6 | ||
|
|
047200c1c2 | ||
|
|
a22add0e14 | ||
|
|
7b1c4cc72a | ||
|
|
3870727a08 | ||
|
|
2bb033964c | ||
|
|
9db5a00b35 |
12
.github/config/mail-parser-wasm-worker.patch
vendored
12
.github/config/mail-parser-wasm-worker.patch
vendored
@@ -1,8 +1,8 @@
|
||||
diff --git a/worker/src/common.ts b/worker/src/common.ts
|
||||
index 8b63e8f..6a7c844 100644
|
||||
index bd9bcc9..e7e2748 100644
|
||||
--- a/worker/src/common.ts
|
||||
+++ b/worker/src/common.ts
|
||||
@@ -273,22 +273,22 @@ export const commonParseMail = async (parsedEmailContext: ParsedEmailContext): P
|
||||
@@ -273,23 +273,23 @@ export const commonParseMail = async (parsedEmailContext: ParsedEmailContext): P
|
||||
}
|
||||
const raw_mail = parsedEmailContext.rawEmail;
|
||||
// TODO: WASM parse email
|
||||
@@ -10,9 +10,9 @@ index 8b63e8f..6a7c844 100644
|
||||
- // const { parse_message_wrapper } = await import('mail-parser-wasm-worker');
|
||||
+ try {
|
||||
+ const { parse_message_wrapper } = await import('mail-parser-wasm-worker');
|
||||
|
||||
|
||||
- // const parsedEmail = parse_message_wrapper(raw_mail);
|
||||
- // return {
|
||||
- // parsedEmailContext.parsedEmail = {
|
||||
- // sender: parsedEmail.sender || "",
|
||||
- // subject: parsedEmail.subject || "",
|
||||
- // text: parsedEmail.text || "",
|
||||
@@ -21,11 +21,12 @@ index 8b63e8f..6a7c844 100644
|
||||
- // ) || [],
|
||||
- // html: parsedEmail.body_html || "",
|
||||
- // };
|
||||
- // return parsedEmailContext.parsedEmail;
|
||||
- // } catch (e) {
|
||||
- // console.error("Failed use mail-parser-wasm-worker to parse email", e);
|
||||
- // }
|
||||
+ const parsedEmail = parse_message_wrapper(raw_mail);
|
||||
+ return {
|
||||
+ parsedEmailContext.parsedEmail = {
|
||||
+ sender: parsedEmail.sender || "",
|
||||
+ subject: parsedEmail.subject || "",
|
||||
+ text: parsedEmail.text || "",
|
||||
@@ -34,6 +35,7 @@ index 8b63e8f..6a7c844 100644
|
||||
+ ) || [],
|
||||
+ html: parsedEmail.body_html || "",
|
||||
+ };
|
||||
+ return parsedEmailContext.parsedEmail;
|
||||
+ } catch (e) {
|
||||
+ console.error("Failed use mail-parser-wasm-worker to parse email", e);
|
||||
+ }
|
||||
|
||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,14 +1,27 @@
|
||||
<!-- markdownlint-disable-file MD004 MD024 MD034 MD036 -->
|
||||
# CHANGE LOG
|
||||
|
||||
## main(v0.8.4)
|
||||
## main(v0.8.6)
|
||||
|
||||
- feat: |UI| 公告支持 html 格式
|
||||
- feat: |UI| `COPYRIGHT` 支持 html 格式
|
||||
- feat: |Doc| 优化部署文档,补充了 `Github Actions 部署文档`,增加了 `Worker 变量说明`
|
||||
|
||||
## v0.8.5
|
||||
|
||||
- feat: |mail-parser-wasm-worker| 修复 `initSync` 函数调用时的 `deprecated` 参数警告
|
||||
- feat: rpc headers covert & typo (#559)
|
||||
- fix: telegram mail page use iframe show email (#561)
|
||||
- feat: |Worker| 增加 `REMOVE_ALL_ATTACHMENT` 和 `REMOVE_EXCEED_SIZE_ATTACHMENT` 用于移除邮件附件,由于是解析邮件的一些信息会丢失,比如图片等.
|
||||
|
||||
## v0.8.4
|
||||
|
||||
- fix: |UI| 修复 admin portal 无收件人邮箱删除调用api 错误
|
||||
- feat: |Telegram Bot| 增加 telegram bot 清理无效地址凭证命令
|
||||
- feat: 增加 worker 配置 `DISABLE_ANONYMOUS_USER_CREATE_EMAIL` 禁用匿名用户创建邮箱地址,只允许登录用户创建邮箱地址
|
||||
- feat: 增加 worker 配置 `ENABLE_ANOTHER_WORKER` 及 `ANOTHER_WORKER_LIST` ,用于调用其他 worker 的 rpc 接口 (#547)
|
||||
- feat: |UI| 自动刷新配置保存到浏览器,可配置刷新间隔
|
||||
- feat: 垃圾邮件检测增加存在是才检查的列表 `JUNK_MAIL_CHECK_LIST` 配置
|
||||
- feat: 垃圾邮件检测增加存在时才检查的列表 `JUNK_MAIL_CHECK_LIST` 配置
|
||||
- feat: | Worker | 增加 `ParsedEmailContext` 类用于缓存解析后的邮件内容,减少解析次数
|
||||
- feat: |Github Action| Worker 部署增加 `DEBUG_MODE` 输出日志, `BACKEND_USE_MAIL_WASM_PARSER` 配置是否使用 wasm 解析邮件
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
## [查看部署文档](https://temp-mail-docs.awsl.uk)
|
||||
|
||||
[](https://deploy.workers.cloudflare.com/?url=https://github.com/dreamhunter2333/cloudflare_temp_email)
|
||||
[](https://temp-mail-docs.awsl.uk/zh/guide/actions/github-action.html)
|
||||
|
||||
[Github Action 部署文档](https://temp-mail-docs.awsl.uk/zh/guide/github-action.html)
|
||||
[Github Action 部署文档](https://temp-mail-docs.awsl.uk/zh/guide/actions/github-action.html)
|
||||
|
||||
[English Docs](https://temp-mail-docs.awsl.uk/en/)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cloudflare_temp_email",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.6",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -19,16 +19,16 @@
|
||||
"deploy:actions": "npm run build && wrangler pages deploy ./dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@simplewebauthn/browser": "^10.0.0",
|
||||
"@unhead/vue": "^1.11.14",
|
||||
"@vueuse/core": "^12.2.0",
|
||||
"@simplewebauthn/browser": "10.0.0",
|
||||
"@unhead/vue": "^1.11.18",
|
||||
"@vueuse/core": "^12.5.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.7.9",
|
||||
"jszip": "^3.10.1",
|
||||
"mail-parser-wasm": "^0.2.0",
|
||||
"naive-ui": "^2.40.4",
|
||||
"postal-mime": "^2.3.2",
|
||||
"mail-parser-wasm": "^0.2.1",
|
||||
"naive-ui": "^2.41.0",
|
||||
"postal-mime": "^2.4.1",
|
||||
"vooks": "^0.2.12",
|
||||
"vue": "^3.5.13",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
@@ -39,14 +39,14 @@
|
||||
"@vicons/fa": "^0.13.0",
|
||||
"@vicons/material": "^0.13.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"unplugin-auto-import": "^0.19.0",
|
||||
"unplugin-vue-components": "^0.28.0",
|
||||
"vite": "^6.0.6",
|
||||
"unplugin-auto-import": "^19.0.0",
|
||||
"unplugin-vue-components": "^28.0.0",
|
||||
"vite": "^6.0.11",
|
||||
"vite-plugin-pwa": "^0.21.1",
|
||||
"vite-plugin-top-level-await": "^1.4.4",
|
||||
"vite-plugin-wasm": "^3.4.1",
|
||||
"workbox-build": "^7.3.0",
|
||||
"workbox-window": "^7.3.0",
|
||||
"wrangler": "^3.99.0"
|
||||
"wrangler": "^3.104.0"
|
||||
}
|
||||
}
|
||||
|
||||
1208
frontend/pnpm-lock.yaml
generated
1208
frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -61,24 +61,26 @@ onMounted(async () => {
|
||||
<n-config-provider :locale="localeConfig" :theme="theme">
|
||||
<n-global-style />
|
||||
<n-spin description="loading..." :show="loading">
|
||||
<n-message-provider container-style="margin-top: 20px;">
|
||||
<n-grid x-gap="12" :cols="12">
|
||||
<n-gi v-if="showSideMargin" span="1"></n-gi>
|
||||
<n-gi :span="!showSideMargin ? 12 : 10">
|
||||
<div class="main">
|
||||
<n-space vertical>
|
||||
<n-layout style="min-height: 80vh;">
|
||||
<Header />
|
||||
<router-view></router-view>
|
||||
</n-layout>
|
||||
<Footer />
|
||||
</n-space>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi v-if="showSideMargin" span="1"></n-gi>
|
||||
</n-grid>
|
||||
<n-back-top />
|
||||
</n-message-provider>
|
||||
<n-notification-provider container-style="margin-top: 60px;">
|
||||
<n-message-provider container-style="margin-top: 20px;">
|
||||
<n-grid x-gap="12" :cols="12">
|
||||
<n-gi v-if="showSideMargin" span="1"></n-gi>
|
||||
<n-gi :span="!showSideMargin ? 12 : 10">
|
||||
<div class="main">
|
||||
<n-space vertical>
|
||||
<n-layout style="min-height: 80vh;">
|
||||
<Header />
|
||||
<router-view></router-view>
|
||||
</n-layout>
|
||||
<Footer />
|
||||
</n-space>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi v-if="showSideMargin" span="1"></n-gi>
|
||||
</n-grid>
|
||||
<n-back-top />
|
||||
</n-message-provider>
|
||||
</n-notification-provider>
|
||||
</n-spin>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useGlobalState } from '../store'
|
||||
import { h } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
||||
@@ -52,7 +53,7 @@ const apiFetch = async (path, options = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getOpenSettings = async (message) => {
|
||||
const getOpenSettings = async (message, notification) => {
|
||||
try {
|
||||
const res = await api.fetch("/open_api/settings");
|
||||
const domainLabels = res["domainLabels"] || [];
|
||||
@@ -89,10 +90,12 @@ const getOpenSettings = async (message) => {
|
||||
}
|
||||
if (openSettings.value.announcement && openSettings.value.announcement != announcement.value) {
|
||||
announcement.value = openSettings.value.announcement;
|
||||
message.info(announcement.value, {
|
||||
showIcon: false,
|
||||
duration: 0,
|
||||
closable: true
|
||||
notification.info({
|
||||
content: () => {
|
||||
return h("div", {
|
||||
innerHTML: announcement.value
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -21,9 +21,14 @@ const { t } = useI18n({
|
||||
<div>
|
||||
<n-divider class="footer-divider" />
|
||||
<div style="text-align: center; padding: 20px">
|
||||
<n-text depth="3">
|
||||
{{ t('copyright') }} © 2023-{{ new Date().getFullYear() }} {{ openSettings.copyright }}
|
||||
</n-text>
|
||||
<n-space justify="center">
|
||||
<n-text depth="3">
|
||||
{{ t('copyright') }} © 2023-{{ new Date().getFullYear() }}
|
||||
</n-text>
|
||||
<n-text depth="3">
|
||||
<div v-html="openSettings.copyright"></div>
|
||||
</n-text>
|
||||
</n-space>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -15,6 +15,7 @@ import { api } from '../api'
|
||||
import { getRouterPathWithLang } from '../utils'
|
||||
|
||||
const message = useMessage()
|
||||
const notification = useNotification()
|
||||
|
||||
const {
|
||||
toggleDark, isDark, isTelegram, showAdminPage,
|
||||
@@ -223,7 +224,7 @@ const logoClick = async () => {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await api.getOpenSettings(message);
|
||||
await api.getOpenSettings(message, notification);
|
||||
// make sure user_id is fetched
|
||||
if (!userSettings.value.user_id) await api.getUserSettings(message);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<div class="center">
|
||||
<n-card :bordered="false" embedded style="max-width: 600px;">
|
||||
<n-card :bordered="false" embedded style="max-width: 600px; overflow: auto;">
|
||||
<pre>{{ JSON.stringify(settings, null, 2) }}</pre>
|
||||
</n-card>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script setup>
|
||||
import { GithubAlt, Discord, Telegram } from '@vicons/fa'
|
||||
import { useGlobalState } from '../../store'
|
||||
const { announcement } = useGlobalState()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="center">
|
||||
<n-card :bordered="false" embedded>
|
||||
<div v-html="announcement"></div>
|
||||
<n-button tag="a" target="_blank" href="https://github.com/dreamhunter2333/cloudflare_temp_email">
|
||||
<template #icon>
|
||||
<n-icon :component="GithubAlt" />
|
||||
|
||||
@@ -34,6 +34,7 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const message = useMessage()
|
||||
const notification = useNotification()
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
@@ -195,7 +196,7 @@ const showNewAddressTab = computed(() => {
|
||||
|
||||
onMounted(async () => {
|
||||
if (!openSettings.value.domains || openSettings.value.domains.length === 0) {
|
||||
await api.getOpenSettings();
|
||||
await api.getOpenSettings(message, notification);
|
||||
}
|
||||
emailDomain.value = domainsOptions.value ? domainsOptions.value[0]?.value : "";
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<div class="center">
|
||||
<n-card :bordered="false" embedded v-if="curMail.message" style="max-width: 800px; overflow: auto;">
|
||||
<n-card :bordered="false" embedded v-if="curMail.message" style="max-width: 800px; height: 100%;">
|
||||
<n-tag type="info">
|
||||
ID: {{ curMail.id }}
|
||||
</n-tag>
|
||||
@@ -59,7 +59,8 @@ onMounted(async () => {
|
||||
<n-tag v-if="showEMailTo" type="info">
|
||||
TO: {{ curMail.address }}
|
||||
</n-tag>
|
||||
<div v-html="curMail.message" style="margin-top: 10px;"></div>
|
||||
<iframe :srcdoc="curMail.message" style="margin-top: 10px;width: 100%; height: 100%;">
|
||||
</iframe>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -71,5 +72,6 @@ onMounted(async () => {
|
||||
text-align: left;
|
||||
place-items: center;
|
||||
justify-content: center;
|
||||
height: 80vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -24,6 +24,7 @@ export default defineConfig({
|
||||
{
|
||||
'naive-ui': [
|
||||
'useMessage',
|
||||
'useNotification',
|
||||
'NButton',
|
||||
'NPopconfirm',
|
||||
'NIcon',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mail-parser-wasm"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
description = "A simple mail parser for wasm"
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import initAsync, { initSync, parse_message } from './mail_parser_wasm';
|
||||
import MODULE from './mail_parser_wasm_bg.wasm';
|
||||
|
||||
initSync(MODULE);
|
||||
initSync({ module: MODULE });
|
||||
|
||||
|
||||
export { initAsync, MODULE };
|
||||
export * from './mail_parser_wasm';
|
||||
export const parse_message_wrapper = (raw_message) => {
|
||||
initSync(MODULE);
|
||||
initSync({ module: MODULE });
|
||||
return parse_message(raw_message);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"url": "https://github.com/dreamhunter2333/cloudflare_temp_email",
|
||||
"directory": "mail-parser-wasm"
|
||||
},
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"mail_parser_wasm_bg.wasm",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "temp-email-pages",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.6",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -11,6 +11,6 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"wrangler": "^3.99.0"
|
||||
"wrangler": "^3.104.0"
|
||||
}
|
||||
}
|
||||
|
||||
15
scripts/update-dependencies.sh
Executable file
15
scripts/update-dependencies.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
cd frontend/
|
||||
pnpm up
|
||||
cd ..
|
||||
|
||||
cd worker/
|
||||
pnpm up
|
||||
cd ..
|
||||
|
||||
cd pages/
|
||||
pnpm up
|
||||
cd ..
|
||||
|
||||
cd vitepress-docs/
|
||||
pnpm up
|
||||
cd ..
|
||||
@@ -119,9 +119,21 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
||||
},
|
||||
{
|
||||
text: '通过 Github Actions 部署',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'D1 数据库', link: 'actions/d1' },
|
||||
{ text: 'Github Actions 配置', link: 'actions/github-action' },
|
||||
{ text: '配置邮件转发', link: 'email-routing.md' },
|
||||
{ text: '配置发送邮件', link: 'config-send-mail' },
|
||||
{ text: '自动更新配置', link: 'actions/auto-update' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '通用',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '通过 Github Actions 部署', link: 'github-action' },
|
||||
{ text: 'worker变量说明', link: 'worker-vars' },
|
||||
{ text: '常见问题', link: 'common-issues' },
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -77,13 +77,13 @@ compatibility_flags = [ "nodejs_compat" ]
|
||||
# TITLE = "Custom Title" # The title of the site
|
||||
PREFIX = "tmp" # The mailbox name prefix to be processed
|
||||
# (min, max) length of the adderss, if not set, the default is (1, 30)
|
||||
# MIN_ADDRESS_LEN = 1
|
||||
# MAX_ADDRESS_LEN = 30
|
||||
# ANNOUNCEMENT = "Custom Announcement"
|
||||
# address check REGEX, if not set, will not check
|
||||
# ADDRESS_CHECK_REGEX = "^(?!.*admin).*"
|
||||
# address name replace REGEX, if not set, the default is [^a-z0-9]
|
||||
# ADDRESS_REGEX = "[^a-z0-9]"
|
||||
# MIN_ADDRESS_LEN = 1
|
||||
# MAX_ADDRESS_LEN = 30
|
||||
# If you want your site to be private, uncomment below and change your password
|
||||
# PASSWORDS = ["123", "456"]
|
||||
# admin console password, if not configured, access to the console is not allowed
|
||||
@@ -138,6 +138,10 @@ ENABLE_AUTO_REPLY = false
|
||||
# JUNK_MAIL_CHECK_LIST = = ["spf", "dkim", "dmarc"]
|
||||
# junk mail force check pass list, if no status or status is not pass, will be marked as junk mail
|
||||
# JUNK_MAIL_FORCE_PASS_LIST = ["spf", "dkim", "dmarc"]
|
||||
# remove attachment if size exceed 2MB, mail maybe mising some information due to parsing
|
||||
# REMOVE_EXCEED_SIZE_ATTACHMENT = true
|
||||
# remove all attachment, mail maybe mising some information due to parsing
|
||||
# REMOVE_ALL_ATTACHMENT = true
|
||||
|
||||
[[d1_databases]]
|
||||
binding = "DB"
|
||||
|
||||
@@ -15,14 +15,17 @@ hero:
|
||||
- theme: alt
|
||||
text: 通过用户界面部署
|
||||
link: /zh/guide/quick-start
|
||||
- theme: alt
|
||||
text: 通过 Github Actions 部署
|
||||
link: /zh/guide/quick-start
|
||||
|
||||
features:
|
||||
- title: 免费托管在 CloudFlare,无需服务器
|
||||
details: Cloudflare D1 数据库,Cloudflare Pages 前端,Cloudflare Workers 后端, Cloudflare Email Routing
|
||||
- title: 仅需域名即可私有部署
|
||||
details: 支持 password 登录邮箱,使用访问密码可作为私人站点,支持附件功能
|
||||
- title: 仅需域名即可私有部署, 免费托管在 CloudFlare,无需服务器
|
||||
details: 支持 password 登录邮箱, 用户注册,使用访问密码可作为私人站点,支持附件功能。
|
||||
- title: 使用 rust wasm 解析邮件
|
||||
details: 使用 rust wasm 解析邮件,支持邮件各种RFC标准,支持附件, 速度极快
|
||||
- title: 支持 Telegram Bot 和 Webhook
|
||||
details: 邮件可转发到 Telegram 或者 webhook, Telegram Bot 支持绑定邮箱,查看邮件, Telegram 小程序
|
||||
- title: 支持发送邮件(UI/API/SMTP)
|
||||
details: 支持通过域名邮箱发送 txt 或者 html 邮件,支持 DKIM 签名, UI/API/SMTP 发送邮件
|
||||
---
|
||||
|
||||
10
vitepress-docs/docs/zh/guide/actions/auto-update.md
Normal file
10
vitepress-docs/docs/zh/guide/actions/auto-update.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Github Actions 部署如何配置自动更新
|
||||
|
||||
::: warning 注意
|
||||
有问题请通过 `Github Issues` 反馈,感谢。
|
||||
自动更新不会执行 D1 数据库的 sql 文件,当数据库 schema 变动时,需要手动执行。
|
||||
:::
|
||||
|
||||
1. 打开仓库的 `Actions` 页面,找到 `Upstream Sync`,点击 `enable workflow` 启用 `workflow`
|
||||
2. 如果 `Upstream Sync` 运行失败,到仓库主页点击 `Sync` 手动同步即可
|
||||
3. 修改 `Upstream Sync` 的 `schedule` 配置可自定义更新间隔,参考 [cron 表达式](https://crontab.guru/)
|
||||
3
vitepress-docs/docs/zh/guide/actions/d1.md
Normal file
3
vitepress-docs/docs/zh/guide/actions/d1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 初始化/更新 D1 数据库
|
||||
|
||||
参考 [命令行更新 d1](/zh/guide/cli/d1) 或者 [用户界面更新 d1](/zh/guide/ui/d1)
|
||||
@@ -1,16 +1,13 @@
|
||||
# 通过 Github Actions 部署
|
||||
|
||||
::: warning 注意
|
||||
目前只支持 worker 和 pages 的部署,D1 数据库以及 Email 部分请参考 [UI/CLI 部署](/)。
|
||||
目前只支持 worker 和 pages 的部署。
|
||||
有问题请通过 `Github Issues` 反馈,感谢。
|
||||
自动更新不会执行 sql 文件,需要手动执行。
|
||||
:::
|
||||
|
||||
[](https://deploy.workers.cloudflare.com/?url=https://github.com/dreamhunter2333/cloudflare_temp_email)
|
||||
|
||||
## 部署步骤
|
||||
|
||||
1. 点击按钮 fork 本仓库 或者直接 fork 本仓库
|
||||
1. 在 GitHub fork 本仓库
|
||||
|
||||
2. 打开仓库的 `Actions` 页面,找到 `Deploy Backend Production` 和 `Deploy Frontend`,点击 `enable workflow` 启用 `workflow`
|
||||
|
||||
@@ -22,6 +22,9 @@ wrangler kv:namespace create DEV
|
||||
|
||||
## 修改 `wrangler.toml` 配置文件
|
||||
|
||||
> [!NOTE] 注意
|
||||
> 更多变量的配置请查看 [worker变量说明](/zh/guide/worker-vars)
|
||||
|
||||
```toml
|
||||
name = "cloudflare_temp_email"
|
||||
main = "src/worker.ts"
|
||||
@@ -43,90 +46,20 @@ compatibility_flags = [ "nodejs_compat" ]
|
||||
# ]
|
||||
|
||||
[vars]
|
||||
# TITLE = "Custom Title" # 自定义网站标题
|
||||
PREFIX = "tmp" # 要处理的邮箱名称前缀,不需要后缀可配置为空字符串
|
||||
# (min, max) adderss的长度,如果不设置,默认为(1, 30)
|
||||
# ANNOUNCEMENT = "Custom Announcement" # 自定义公告
|
||||
# address name 的正则表达式, 只用于检查,符合条件将通过检查
|
||||
# ADDRESS_CHECK_REGEX = "^(?!.*admin).*"
|
||||
# address name 替换非法符号的正则表达式, 不在其中的符号将被替换,如果不设置,默认为 [^a-z0-9], 需谨慎使用, 有些符号可能导致无法收件
|
||||
# ADDRESS_REGEX = "[^a-z0-9]"
|
||||
# MIN_ADDRESS_LEN = 1
|
||||
# MAX_ADDRESS_LEN = 30
|
||||
# 如果你想要你的网站私有,取消下面的注释,并修改密码
|
||||
# PASSWORDS = ["123", "456"]
|
||||
# 邮箱名称前缀,不需要后缀可配置为空字符串或者不配置
|
||||
PREFIX = "tmp"
|
||||
# 用于临时邮箱的所有域名, 支持多个域名
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"]
|
||||
# 用于生成 jwt 的密钥, jwt 用于给用户登录以及鉴权
|
||||
JWT_SECRET = "xxx"
|
||||
|
||||
# admin 控制台密码, 不配置则不允许访问控制台
|
||||
# ADMIN_PASSWORDS = ["123", "456"]
|
||||
# 警告: 管理员控制台没有密码或用户检查
|
||||
# DISABLE_ADMIN_PASSWORD_CHECK = false
|
||||
# admin 联系方式,不配置则不显示,可配置任意字符串
|
||||
# ADMIN_CONTACT = "xx@xx.xxx"
|
||||
# DEFAULT_DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 默认用户可用的域名(未登录或未分配角色的用户)
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名, 支持多个域名
|
||||
# 对于中文域名,可以使用 DOMAIN_LABELS 显示域名的中文展示名称
|
||||
# DOMAIN_LABELS = ["中文.xxx", "xxx.xxx2"]
|
||||
# 新用户默认角色, 仅在启用邮件验证时有效
|
||||
# USER_DEFAULT_ROLE = "vip"
|
||||
# admin 角色配置, 如果用户角色等于 ADMIN_USER_ROLE 则可以访问 admin 控制台
|
||||
# ADMIN_USER_ROLE = "admin" # the role which can access admin panel
|
||||
# 用户角色配置, 如果 domains 为空将使用 default_domains
|
||||
# 如果 prefix 为 null 将使用默认前缀, 如果 prefix 为空字符串将不使用前缀
|
||||
# USER_ROLES = [
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "vip", prefix = "vip" },
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "admin", prefix = "" },
|
||||
# ]
|
||||
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥, jwt 用于给用户登录以及鉴权
|
||||
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
||||
|
||||
# 是否允许用户创建邮件, 不配置则不允许
|
||||
ENABLE_USER_CREATE_EMAIL = true
|
||||
# 禁用匿名用户创建邮箱,如果设置为 true,则用户只能在登录后创建邮箱地址
|
||||
# DISABLE_ANONYMOUS_USER_CREATE_EMAIL = true
|
||||
# 允许用户删除邮件, 不配置则不允许
|
||||
ENABLE_USER_DELETE_EMAIL = true
|
||||
# 允许自动回复邮件
|
||||
ENABLE_AUTO_REPLY = false
|
||||
# 是否启用 webhook
|
||||
# ENABLE_WEBHOOK = true
|
||||
# 前端界面页脚文本
|
||||
# COPYRIGHT = "Dream Hunter"
|
||||
# DISABLE_SHOW_GITHUB = true # 是否显示 GitHub 链接
|
||||
# 默认发送邮件余额,如果不设置,将为 0
|
||||
# DEFAULT_SEND_BALANCE = 1
|
||||
# NO_LIMIT_SEND_ROLE = "vip" # 可以无限发送邮件的角色
|
||||
# Turnstile 人机验证配置
|
||||
# CF_TURNSTILE_SITE_KEY = ""
|
||||
# CF_TURNSTILE_SECRET_KEY = ""
|
||||
# telegram bot 最多绑定邮箱数量
|
||||
# TG_MAX_ADDRESS = 5
|
||||
# telegram BOT_INFO,预定义的 BOT_INFO 可以降低 webhook 的延迟
|
||||
# TG_BOT_INFO = "{}"
|
||||
# 全局转发地址列表,如果不配置则不启用,启用后所有邮件都会转发到列表中的地址
|
||||
# FORWARD_ADDRESS_LIST = ["xxx@xxx.com"]
|
||||
# 前端地址,用于发送 webhook 的邮件 url
|
||||
# FRONTEND_URL = "https://xxxx.xxx"
|
||||
# 是否启用垃圾邮件检查,默认任何一项存在配置且不通过则被判定为垃圾邮件
|
||||
# ENABLE_CHECK_JUNK_MAIL = false
|
||||
# 垃圾邮件检查配置, 任何一项 存在 且 不通过 则被判定为垃圾邮件
|
||||
# JUNK_MAIL_CHECK_LIST = = ["spf", "dkim", "dmarc"]
|
||||
# 垃圾邮件检查配置, 任何一项 不存在 或者 不通过 则被判定为垃圾邮件
|
||||
# JUNK_MAIL_FORCE_PASS_LIST = ["spf", "dkim", "dmarc"]
|
||||
# 是否开启其他 worker 处理邮件
|
||||
# ENABLE_ANOTHER_WORKER = false
|
||||
# 其他 worker 处理邮件的配置,可以配置多个其他 worker。
|
||||
# 通过关键词筛选,调用对应绑定的 worker 的方法(默认方法名为 rpcEmail)
|
||||
# keywords必填,否则 worker 将不会被触发
|
||||
#ANOTHER_WORKER_LIST ="""
|
||||
#[
|
||||
# {
|
||||
# "binding":"AUTH_INBOX",
|
||||
# "method":"rpcEmail",
|
||||
# "keywords":[
|
||||
# "验证码","激活码","激活链接","确认链接","验证邮箱","确认邮件","账号激活","邮件验证","账户确认","安全码","认证码","安全验证","登陆码","确认码","启用账户","激活账户","账号验证","注册确认",
|
||||
# "account","activation","verify","verification","activate","confirmation","email","code","validate","registration","login","code","expire","confirm"
|
||||
# ]
|
||||
# }
|
||||
#]
|
||||
#"""
|
||||
|
||||
# D1 数据库的名称和 ID 可以在 cloudflare 控制台查看
|
||||
[[d1_databases]]
|
||||
|
||||
41
vitepress-docs/docs/zh/guide/common-issues.md
Normal file
41
vitepress-docs/docs/zh/guide/common-issues.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# 常见问题
|
||||
|
||||
> [!NOTE] 注意
|
||||
> 如果你的问题没有在这里找到解决方案,请到 `Github Issues` 中搜索或者提问, 或者到 Telegram 群组中提问。
|
||||
|
||||
## 通用
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
| ---------------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| 使用 Cloudflare Workers 给已认证的邮箱发送邮件 | 使用 cf 的 API 进行发送,只支持绑定到 CF 上的收件地址,即 CF EMAIL 转发目的地址 |
|
||||
| 绑定多个域名 | 每个域名都需要设置 email 转发到 worker |
|
||||
|
||||
## worker 相关
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
| ------------------------------------------------------------------ | --------------------------------------------------------------------------- |
|
||||
| `Uncaught Error: No such module "path". imported from "worker.js"` | [参考](/zh/guide/ui/worker) |
|
||||
| `No such module "node:stream". imported from "worker.js"` | [参考](/zh/guide/ui/worker) |
|
||||
| `二级域名无法发送邮件` | [参考](https://github.com/dreamhunter2333/cloudflare_temp_email/issues/515) |
|
||||
| `Failed to send verify code: No balance` | admin 后台设置无限制邮件或者发件权限页面增加额度 |
|
||||
| `Github OAuth无法获取到邮箱 400 Failed to get user email` | 需要 github 用户设置公开邮箱 |
|
||||
| `Cannot read properties of undefined (reading 'map')` | worker 变量没有设置成功 |
|
||||
|
||||
## pages 相关
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
| --------------- | ---------------------------------------- |
|
||||
| `network error` | 使用无痕模式或者清空浏览器缓存,DNS 缓存 |
|
||||
|
||||
## telegram bot
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
| -------------------------------------------------------------- | -------------------------------------------------- |
|
||||
| `Telgram Bot获取邮件失败:400:Bad Request:BUTTON_URL_INVALID` | tg mini app 的 URL 填写错误,需要填写 pages 的 URL |
|
||||
| `Telegram bot bind error: bind adress count reach the limit` | 需要设置 worker 变量 `TG_MAX_ADDRESS` |
|
||||
|
||||
## Github Actions
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
| ------------------------------------------ | --------------------------------------------------------------------------------- |
|
||||
| Github Action部署后,cf里始终是preview分支 | 到 cf pages 页面的设置中确认 前端的分支 和 Github Action 的 前端部署分支 是否相同 |
|
||||
@@ -1,5 +1,7 @@
|
||||
# 配置 Telegram Bot
|
||||
|
||||
试用地址:[@cf_temp_mail_bot](https://t.me/cf_temp_mail_bot)
|
||||
|
||||
::: warning 注意
|
||||
worker 默认的 `worker.dev` 域名的证书是不被 telegram 支持的,配置 Telegram Bot 请使用自定义域名
|
||||
:::
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
# 快速开始
|
||||
|
||||
- 良好的网络环境
|
||||
- cloudflare 账号
|
||||
## 开始之前
|
||||
|
||||
打开 [cloudflare控制台](https://dash.cloudflare.com/)
|
||||
需要 `良好的网络环境` 和 `cloudflare 账号`, 打开 [cloudflare控制台](https://dash.cloudflare.com/)
|
||||
|
||||
请查看通过 [命令行部署](/zh/guide/cli/pre-requisite) 或者 [用户界面部署](/zh/guide/ui/d1)
|
||||
请选择下面三种方式之一进行部署
|
||||
|
||||
## 网友提供的详细的小白教程
|
||||
- [通过命令行部署](/zh/guide/cli/pre-requisite)
|
||||
- [通过用户界面部署](/zh/guide/ui/d1)
|
||||
- [通过Github Actions 部署](/zh/guide/actions/github-action)
|
||||
|
||||
### 也可以参考网友提供的详细的小白教程
|
||||
|
||||
- [【教程】小白也能看懂的自建Cloudflare临时邮箱教程(域名邮箱)](https://linux.do/t/topic/316819/1)
|
||||
|
||||
@@ -22,14 +25,18 @@
|
||||
|
||||
然后参考下面的文档使用 `CLI` 或者 `UI` 覆盖部署之前的 `worker` 和 `pages` 即可
|
||||
|
||||
CLI 部署
|
||||
### CLI 部署
|
||||
|
||||
- [命令行更新 d1](/zh/guide/cli/d1)
|
||||
- [命令行部署 worker](/zh/guide/cli/worker)
|
||||
- [命令行部署 pages](/zh/guide/cli/worker)
|
||||
|
||||
UI 部署
|
||||
### UI 部署
|
||||
|
||||
- [用户界面更新 d1](/zh/guide/ui/d1)
|
||||
- [用户界面部署 worker](/zh/guide/ui/worker)
|
||||
- [用户界面部署 pages](/zh/guide/ui/pages)
|
||||
|
||||
### Github Actions 部署
|
||||
|
||||
- [Github Actions 部署如何配置自动更新](/zh/guide/actions/auto-update)
|
||||
|
||||
@@ -26,34 +26,36 @@
|
||||

|
||||

|
||||
|
||||
6. 点击 `Settings` -> `Variables`, 如图所示添加变量,参考 [修改 wrangler.toml 配置文件](/zh/guide/cli/worker.html#修改-wrangler-toml-配置文件) 中的 `[vars]` 部分
|
||||
|
||||
> [!NOTE]
|
||||
> 注意字符串格式的变量的最外层的引号是不需要的
|
||||
>
|
||||
> - 对于 `USER_ROLES` 请配置为此格式 `[{"domains":["awsl.uk","dreamhunter2333.xyz"],"role":"vip","prefix":"vip"},{"domains":["awsl.uk","dreamhunter2333.xyz"],"role":"admin","prefix":""}]`
|
||||
6. 点击 `Settings` -> `Variables`, 如图所示添加变量
|
||||
|
||||

|
||||
|
||||
7. 以下是 `Settings` -> `Variables` 中必须配置的变量列表
|
||||
> [!NOTE] 注意
|
||||
> 更多变量的配置请查看 [worker变量说明](/zh/guide/worker-vars)
|
||||
>
|
||||
> 注意字符串格式的变量的最外层的引号是不需要的
|
||||
>
|
||||
> 对于 `USER_ROLES` 请配置为此格式 `[{"domains":["awsl.uk","dreamhunter2333.xyz"],"role":"vip","prefix":"vip"},{"domains":["awsl.uk","dreamhunter2333.xyz"],"role":"admin","prefix":""}]`
|
||||
|
||||
| 变量名 | 说明 | 示例 |
|
||||
| -------------------------- | ------------------------------------------------ | ------------------------------------ |
|
||||
| `PREFIX` | 要处理的邮箱名称前缀,不需要后缀可配置为空字符串 | `tmp` |
|
||||
| `DOMAINS` | 你的域名, 支持多个域名 | `["awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
| `ADMIN_PASSWORDS` | admin 控制台密码, 不配置则不允许访问控制台 | `["123", "456"]` |
|
||||
| `JWT_SECRET` | 用于生成 jwt 的密钥, jwt 用于登录以及鉴权 | `xxx` |
|
||||
| `ENABLE_USER_CREATE_EMAIL` | 是否允许用户创建邮箱, 不配置则不允许 | `true` |
|
||||
| `ENABLE_USER_DELETE_EMAIL` | 是否允许用户删除邮箱, 不配置则不允许 | `true` |
|
||||
建议配置的变量列表
|
||||
|
||||
8. 点击 `Settings` -> `Variables`, 下拉找到 `D1 Database`, 点击 `Add Binding`, 名称如图,选择刚刚创建的 D1 数据库,点击 `Deploy`
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| -------------------------- | ----------- | ------------------------------------------ | ------------------------------------ |
|
||||
| `PREFIX` | 文本 | 新建邮箱名称默认前缀,不需要前缀可不配置 | `tmp` |
|
||||
| `DOMAINS` | JSON | 用于临时邮箱的所有域名, 支持多个域名 | `["awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
| `JWT_SECRET` | 文本/Secret | 用于生成 jwt 的密钥, jwt 用于登录以及鉴权 | `xxx` |
|
||||
| `ADMIN_PASSWORDS` | JSON | admin 控制台密码, 不配置则不允许访问控制台 | `["123", "456"]` |
|
||||
| `ENABLE_USER_CREATE_EMAIL` | 文本/JSON | 是否允许用户创建邮箱, 不配置则不允许 | `true` |
|
||||
| `ENABLE_USER_DELETE_EMAIL` | 文本/JSON | 是否允许用户删除邮件, 不配置则不允许 | `true` |
|
||||
|
||||
7. 点击 `Settings` -> `Variables`, 下拉找到 `D1 Database`, 点击 `Add Binding`, 名称如图,选择刚刚创建的 D1 数据库,点击 `Deploy`
|
||||
|
||||
> [!NOTE] 重要
|
||||
> 注意此处 `D1 Database` 的绑定名称必须为 `DB`
|
||||
|
||||

|
||||
|
||||
9. 点击 `Settings` -> `Trggers`, 这里可以添加自己的域名,你也可以使用自动生成的 `*.workers.dev` 的域名。记录下这个域名,后面部署前端会用到。
|
||||
8. 点击 `Settings` -> `Trggers`, 这里可以添加自己的域名,你也可以使用自动生成的 `*.workers.dev` 的域名。记录下这个域名,后面部署前端会用到。
|
||||
|
||||
> [!NOTE]
|
||||
> 打开 `worker` 的 `url`,如果显示 `OK` 说明部署成功
|
||||
@@ -62,7 +64,7 @@
|
||||
|
||||

|
||||
|
||||
10. 如果你要启用注册用户功能,并需要发送邮件验证,则需要创建 `KV` 缓存, 不需要可跳过此步骤,点击 `Workers & Pages` -> `KV` -> `Create Namespace`, 如图,点击 `Create Namespace`,然后在 `Settings` -> `Variables`, 下拉找到 `KV`, 点击 `Add Binding`, 名称如图,选择刚刚创建的 `KV` 缓存,点击 `Deploy`
|
||||
9. 如果你要启用注册用户功能,并需要发送邮件验证,则需要创建 `KV` 缓存, 不需要可跳过此步骤,点击 `Workers & Pages` -> `KV` -> `Create Namespace`, 如图,点击 `Create Namespace`,然后在 `Settings` -> `Variables`, 下拉找到 `KV`, 点击 `Add Binding`, 名称如图,选择刚刚创建的 `KV` 缓存,点击 `Deploy`
|
||||
|
||||
> [!NOTE] 重要
|
||||
> 如果你要启用注册用户功能,并需要发送邮件验证,则需要创建 `KV` 缓存, 不需要可跳过此步骤
|
||||
@@ -72,9 +74,14 @@
|
||||

|
||||

|
||||
|
||||
11. Telegram Bot 配置
|
||||
10. Telegram Bot 配置
|
||||
|
||||
> [!NOTE]
|
||||
> 如果不需要 Telegram Bot, 可跳过此步骤
|
||||
|
||||
请先创建一个 Telegram Bot,然后获取 `token`,然后执行下面的命令,将 `token` 添加到 `Variables` 中, Name: `TELEGRAM_BOT_TOKEN`
|
||||
|
||||
11. 如果你想要使用 admin 页面中的定时任务清理邮件,需要到 `Settings` -> `Triggers` -> `Cron Triggers` 中添加定时任务.
|
||||
|
||||
> [!NOTE]
|
||||
> 选择 `cron` 表达式,输入 `0 0 * * *`(此表达式表示每天午夜运行),点击 `Add` 增加。请根据您的需求调整此表达式。
|
||||
|
||||
138
vitepress-docs/docs/zh/guide/worker-vars.md
Normal file
138
vitepress-docs/docs/zh/guide/worker-vars.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Worker 变量说明
|
||||
|
||||
> [!NOTE] 注意
|
||||
> 通过 CLI 部署时的写法请参考 `worker/wrangler.toml.template`
|
||||
|
||||
## 必填变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| -------------------------- | ----------- | ------------------------------------------ | ------------------------------------ |
|
||||
| `DOMAINS` | JSON | 用于临时邮箱的所有域名, 支持多个域名 | `["awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
| `JWT_SECRET` | 文本/Secret | 用于生成 jwt 的密钥, jwt 用于登录以及鉴权 | `xxx` |
|
||||
| `ADMIN_PASSWORDS` | JSON | admin 控制台密码, 不配置则不允许访问控制台 | `["123", "456"]` |
|
||||
| `ENABLE_USER_CREATE_EMAIL` | 文本/JSON | 是否允许用户创建邮箱, 不配置则不允许 | `true` |
|
||||
| `ENABLE_USER_DELETE_EMAIL` | 文本/JSON | 是否允许用户删除邮件, 不配置则不允许 | `true` |
|
||||
|
||||
## 后台相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ------------------------------ | --------- | ------------------------------------ | ---------------- |
|
||||
| `PASSWORDS` | JSON | 网站私有密码, 配置后需要密码才能访问 | `["123", "456"]` |
|
||||
| `DISABLE_ADMIN_PASSWORD_CHECK` | 文本/JSON | 警告: 管理员控制台没有密码或用户检查 | `false` |
|
||||
|
||||
## 邮箱相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ---------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
|
||||
| `PREFIX` | 文本 | 新建 `邮箱名称` 的默认前缀,不需要前缀可不配置 | `tmp` |
|
||||
| `MIN_ADDRESS_LEN` | 数字 | `邮箱名称` 的最小长度 | `1` |
|
||||
| `MAX_ADDRESS_LEN` | 数字 | `邮箱名称` 的最大长度 | `30` |
|
||||
| `ADDRESS_CHECK_REGEX` | 文本 | `邮箱名称` 的正则表达式, 只用于检查 | `^(?!.*admin).*` |
|
||||
| `ADDRESS_REGEX` | 文本 | `邮箱名称` 替换非法符号的正则表达式, 不在其中的符号将被替换,如果不设置,默认为 `[^a-z0-9]`, 需谨慎使用, 有些符号可能导致无法收件 | `[^a-z0-9]` |
|
||||
| `DEFAULT_DOMAINS` | JSON | 默认用户可用的域名(未登录或未分配角色的用户) | `["awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
| `DOMAIN_LABELS` | JSON | 对于中文域名,可以使用 DOMAIN_LABELS 显示域名的中文展示名称 | `["中文.awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
| `ENABLE_AUTO_REPLY` | 文本/JSON | 允许自动回复邮件 | `true` |
|
||||
| `DEFAULT_SEND_BALANCE` | 文本/JSON | 默认发送邮件余额,如果不设置,将为 0 | `1` |
|
||||
|
||||
## 接受邮件相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ------------------------------- | --------- | -------------------------------------------------------------------------- | -------------------------- |
|
||||
| `BLACK_LIST` | 文本 | 黑名单,用于过滤发件人,逗号分隔 | `gov.cn,edu.cn` |
|
||||
| `ENABLE_CHECK_JUNK_MAIL` | 文本/JSON | 是否启用垃圾邮件检查,配合下列两个列表使用 | `false` |
|
||||
| `JUNK_MAIL_CHECK_LIST` | JSON | 垃圾邮件检查配置, 任何一项 `存在` 且 `不通过` 则被判定为垃圾邮件 | `["spf", "dkim", "dmarc"]` |
|
||||
| `JUNK_MAIL_FORCE_PASS_LIST` | JSON | 垃圾邮件检查配置, 任何一项 `不存在` 或者 `不通过` 则被判定为垃圾邮件 | `["spf", "dkim", "dmarc"]` |
|
||||
| `FORWARD_ADDRESS_LIST` | JSON | 全局转发地址列表,如果不配置则不启用,启用后所有邮件都会转发到列表中的地址 | `["xxx@xxx.com"]` |
|
||||
| `REMOVE_EXCEED_SIZE_ATTACHMENT` | 文本/JSON | 如果附件大小超过 2MB,则删除附件,邮件可能由于解析而丢失一些信息 | `true` |
|
||||
| `REMOVE_ALL_ATTACHMENT` | 文本/JSON | 移除所有附件,邮件可能由于解析而丢失一些信息 | `true` |
|
||||
|
||||
> [!NOTE]
|
||||
> `垃圾邮件检查` 和 `移除附件功能` 需要解析邮件,免费版 CPU 有限,可能会导致大邮件解析超时
|
||||
>
|
||||
> 如果你想解析邮件能力更强
|
||||
>
|
||||
> 参考 [配置 worker 使用 wasm 解析邮件](/zh/guide/feature/mail_parser_wasm_worker)
|
||||
|
||||
## webhook 相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ---------------- | --------- | ------------------------------------- | ------------------ |
|
||||
| `ENABLE_WEBHOOK` | 文本/JSON | 是否启用 webhook | `true` |
|
||||
| `FRONTEND_URL` | 文本 | 前端地址,用于发送 webhook 的邮件 url | `https://xxxx.xxx` |
|
||||
|
||||
> [!NOTE]
|
||||
> webhook 功能需要解析邮件,免费版 CPU 有限,可能会导致大邮件解析超时
|
||||
>
|
||||
> 如果你想解析邮件能力更强
|
||||
>
|
||||
> 参考 [配置 worker 使用 wasm 解析邮件](/zh/guide/feature/mail_parser_wasm_worker)
|
||||
|
||||
## 用户相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ------------------------------------- | --------- | ------------------------------------------------------------------------ | ------- |
|
||||
| `USER_DEFAULT_ROLE` | 文本 | 新用户默认角色, 仅在启用邮件验证时有效 | `vip` |
|
||||
| `ADMIN_USER_ROLE` | 文本 | admin 角色配置, 如果用户角色等于 ADMIN_USER_ROLE 则可以访问 admin 控制台 | `admin` |
|
||||
| `USER_ROLES` | JSON | - | 见下方 |
|
||||
| `DISABLE_ANONYMOUS_USER_CREATE_EMAIL` | 文本/JSON | 禁用匿名用户创建邮箱,如果设置为 true,则用户只能在登录后创建邮箱地址 | `true` |
|
||||
| `NO_LIMIT_SEND_ROLE` | 文本 | 可以无限发送邮件的角色 | `vip` |
|
||||
|
||||
> [!NOTE] USER_ROLES 用户角色配置说明
|
||||
>
|
||||
> - 如果 `domains` 为空将使用 `DEFAULT_DOMAINS`
|
||||
> - 如果 prefix 为 null 将使用默认前缀, 如果 prefix 为空字符串将不使用前缀
|
||||
>
|
||||
> 通过用户界面部署时 `USER_ROLES` 请配置为此格式 `[{"domains":["awsl.uk","dreamhunter2333.xyz"],"role":"vip","prefix":"vip"},{"domains":["awsl.uk","dreamhunter2333.xyz"],"role":"admin","prefix":""}]`
|
||||
>
|
||||
> CLI 部署时 `USER_ROLES` 请参考 `worker/wrangler.toml.template` 配置为此格式 `[{ domains = ["awsl.uk", "dreamhunter2333.xyz"], role = "vip", prefix = "vip" }, { domains = ["awsl.uk", "dreamhunter2333.xyz"], role = "admin", prefix = "" }]`
|
||||
|
||||
## 网页相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ------------------------- | ----------- | ------------------------------------------------ | --------------------- |
|
||||
| `TITLE` | 文本 | 自定义前端页面网站标题,支持 html | `Custom Title` |
|
||||
| `ANNOUNCEMENT` | 文本 | 自定义前端页面公告,支持 html | `Custom Announcement` |
|
||||
| `COPYRIGHT` | 文本 | 自定义前端界面页脚文本,支持 html | `Dream Hunter` |
|
||||
| `ADMIN_CONTACT` | 文本 | admin 联系方式,可配置任意字符串, 不配置则不显示 | `xxx@gmail.com` |
|
||||
| `DISABLE_SHOW_GITHUB` | 文本/JSON | 是否显示 GitHub 链接 | `true` |
|
||||
| `CF_TURNSTILE_SITE_KEY` | 文本/Secret | Turnstile 人机验证配置 | `xxx` |
|
||||
| `CF_TURNSTILE_SECRET_KEY` | 文本/Secret | Turnstile 人机验证配置 | `xxx` |
|
||||
|
||||
## Telegram Bot 相关变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ---------------- | ---- | ---------------------------------------------------------------------- | ---- |
|
||||
| `TG_MAX_ADDRESS` | 数字 | telegram bot 最多绑定邮箱数量 | `5` |
|
||||
| `TG_BOT_INFO` | 文本 | 可不配置,telegram BOT_INFO,预定义的 BOT_INFO 可以降低 webhook 的延迟 | `{}` |
|
||||
|
||||
> [!NOTE]
|
||||
> Telegram 功能需要解析邮件,免费版 CPU 有限,可能会导致大邮件解析超时
|
||||
>
|
||||
> 如果你想解析邮件能力更强
|
||||
>
|
||||
> 参考 [配置 worker 使用 wasm 解析邮件](/zh/guide/feature/mail_parser_wasm_worker)
|
||||
|
||||
## 其他变量
|
||||
|
||||
| 变量名 | 类型 | 说明 | 示例 |
|
||||
| ----------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||
| `ENABLE_ANOTHER_WORKER` | 文本/JSON | 是否开启其他 worker 处理邮件 | `false` |
|
||||
| `ANOTHER_WORKER_LIST` | JSON | - 其他 worker 处理邮件的配置,可以配置多个其他 worker <br/> - 通过关键词筛选,调用对应绑定的 worker 的方法(默认方法名为 rpcEmail)<br/> - keywords必填,否则 worker 将不会被触发 | 见下方 |
|
||||
|
||||
> [!NOTE]
|
||||
> `ANOTHER_WORKER_LIST` 的配置示例
|
||||
>
|
||||
> ```toml
|
||||
> #ANOTHER_WORKER_LIST ="""
|
||||
> #[
|
||||
> # {
|
||||
> # "binding":"AUTH_INBOX",
|
||||
> # "method":"rpcEmail",
|
||||
> # "keywords":[
|
||||
> # "验证码","激活码","激活链接","确认链接","验证邮箱","确认邮件","账号激活","邮件验证","账户确认","安全码","认证码","安全验证","登陆码","确认码","启用账户","激活账户","账号验证","注册确认",
|
||||
> # "account","activation","verify","verification","activate","confirmation","email","code","validate","registration","login","code","expire","confirm"
|
||||
> # ]
|
||||
> # }
|
||||
> #]
|
||||
> #
|
||||
> ```
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "temp-mail-docs",
|
||||
"private": true,
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.6",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
"vitepress": "^1.5.0",
|
||||
"wrangler": "^3.99.0"
|
||||
"@types/node": "^22.10.7",
|
||||
"vitepress": "^1.6.2",
|
||||
"wrangler": "^3.104.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vitepress dev docs",
|
||||
|
||||
926
vitepress-docs/pnpm-lock.yaml
generated
926
vitepress-docs/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cloudflare_temp_email",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.6",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -11,22 +11,22 @@
|
||||
"build": "wrangler deploy --dry-run --outdir dist --minify"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20241224.0",
|
||||
"@eslint/js": "9.17.0",
|
||||
"@simplewebauthn/types": "^10.0.0",
|
||||
"eslint": "9.17.0",
|
||||
"@cloudflare/workers-types": "^4.20250121.0",
|
||||
"@eslint/js": "9.18.0",
|
||||
"@simplewebauthn/types": "10.0.0",
|
||||
"eslint": "9.18.0",
|
||||
"globals": "^15.14.0",
|
||||
"typescript-eslint": "^8.18.2",
|
||||
"wrangler": "^3.99.0"
|
||||
"typescript-eslint": "^8.21.0",
|
||||
"wrangler": "^3.104.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.717.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.717.0",
|
||||
"@simplewebauthn/server": "^10.0.1",
|
||||
"hono": "^4.6.14",
|
||||
"mimetext": "^3.0.24",
|
||||
"postal-mime": "^2.3.2",
|
||||
"resend": "^4.0.1",
|
||||
"@aws-sdk/client-s3": "^3.732.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.732.0",
|
||||
"@simplewebauthn/server": "10.0.1",
|
||||
"hono": "^4.6.17",
|
||||
"mimetext": "^3.0.27",
|
||||
"postal-mime": "^2.4.1",
|
||||
"resend": "^4.1.1",
|
||||
"telegraf": "4.16.3"
|
||||
},
|
||||
"pnpm": {
|
||||
|
||||
2032
worker/pnpm-lock.yaml
generated
2032
worker/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ export default {
|
||||
"HAS_ADMIN_PASSWORDS": getAdminPasswords(c).length,
|
||||
"ANNOUNCEMENT": getStringValue(c.env.ANNOUNCEMENT),
|
||||
|
||||
"PREFIX": c.env.PREFIX,
|
||||
"PREFIX": getStringValue(c.env.PREFIX),
|
||||
"ADDRESS_CHECK_REGEX": getStringValue(c.env.ADDRESS_CHECK_REGEX),
|
||||
"ADDRESS_REGEX": getStringValue(c.env.ADDRESS_REGEX),
|
||||
"MIN_ADDRESS_LEN": getIntValue(c.env.MIN_ADDRESS_LEN, 1),
|
||||
@@ -46,6 +46,9 @@ export default {
|
||||
"JUNK_MAIL_CHECK_LIST": getStringArray(c.env.JUNK_MAIL_CHECK_LIST),
|
||||
"JUNK_MAIL_FORCE_PASS_LIST": getStringArray(c.env.JUNK_MAIL_FORCE_PASS_LIST),
|
||||
|
||||
"REMOVE_EXCEED_SIZE_ATTACHMENT": getBooleanValue(c.env.REMOVE_EXCEED_SIZE_ATTACHMENT),
|
||||
"REMOVE_ALL_ATTACHMENT": getBooleanValue(c.env.REMOVE_ALL_ATTACHMENT),
|
||||
|
||||
"ENABLE_ANOTHER_WORKER": getBooleanValue(c.env.ENABLE_ANOTHER_WORKER),
|
||||
"ANOTHER_WORKER_LIST": getAnotherWorkerList(c),
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@ api.get('/open_api/settings', async (c) => {
|
||||
return c.json({
|
||||
"title": c.env.TITLE,
|
||||
"announcement": getStringValue(c.env.ANNOUNCEMENT),
|
||||
"prefix": c.env.PREFIX,
|
||||
"prefix": getStringValue(c.env.PREFIX),
|
||||
"addressRegex": getStringValue(c.env.ADDRESS_REGEX),
|
||||
"minAddressLen": getIntValue(c.env.MIN_ADDRESS_LEN, 1),
|
||||
"maxAddressLen": getIntValue(c.env.MAX_ADDRESS_LEN, 30),
|
||||
|
||||
@@ -277,7 +277,7 @@ export const commonParseMail = async (parsedEmailContext: ParsedEmailContext): P
|
||||
// const { parse_message_wrapper } = await import('mail-parser-wasm-worker');
|
||||
|
||||
// const parsedEmail = parse_message_wrapper(raw_mail);
|
||||
// return {
|
||||
// parsedEmailContext.parsedEmail = {
|
||||
// sender: parsedEmail.sender || "",
|
||||
// subject: parsedEmail.subject || "",
|
||||
// text: parsedEmail.text || "",
|
||||
@@ -286,19 +286,21 @@ export const commonParseMail = async (parsedEmailContext: ParsedEmailContext): P
|
||||
// ) || [],
|
||||
// html: parsedEmail.body_html || "",
|
||||
// };
|
||||
// return parsedEmailContext.parsedEmail;
|
||||
// } catch (e) {
|
||||
// console.error("Failed use mail-parser-wasm-worker to parse email", e);
|
||||
// }
|
||||
try {
|
||||
const { default: PostalMime } = await import('postal-mime');
|
||||
const parsedEmail = await PostalMime.parse(raw_mail);
|
||||
return {
|
||||
parsedEmailContext.parsedEmail = {
|
||||
sender: parsedEmail.from ? `${parsedEmail.from.name} <${parsedEmail.from.address}>` : "",
|
||||
subject: parsedEmail.subject || "",
|
||||
text: parsedEmail.text || "",
|
||||
html: parsedEmail.html || "",
|
||||
headers: parsedEmail.headers || [],
|
||||
};
|
||||
return parsedEmailContext.parsedEmail;
|
||||
}
|
||||
catch (e) {
|
||||
console.error("Failed use PostalMime to parse email", e);
|
||||
@@ -319,13 +321,13 @@ export const commonGetUserRole = async (
|
||||
export const getAddressPrefix = async (c: Context<HonoCustomType>): Promise<string | undefined> => {
|
||||
const user = c.get("userPayload");
|
||||
if (!user) {
|
||||
return c.env.PREFIX;
|
||||
return getStringValue(c.env.PREFIX);
|
||||
}
|
||||
const user_role = await commonGetUserRole(c, user.user_id);
|
||||
if (typeof user_role?.prefix === "string") {
|
||||
return user_role.prefix;
|
||||
}
|
||||
return c.env.PREFIX;
|
||||
return getStringValue(c.env.PREFIX);
|
||||
}
|
||||
|
||||
export const getAllowDomains = async (c: Context<HonoCustomType>): Promise<string[]> => {
|
||||
@@ -451,9 +453,17 @@ export async function triggerAnotherWorker(
|
||||
console.log(`worker.binding = ${bindingName} not match keywords, parsedText = ${parsedText}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const requestBody = JSON.stringify(rpcEmailMessage);
|
||||
const bodyObj = { ...rpcEmailMessage } as any;
|
||||
if (bodyObj.headers && typeof bodyObj.headers.forEach === "function") {
|
||||
const headerObj: any = {}
|
||||
bodyObj.headers.forEach((value: string, key: string) => {
|
||||
headerObj[key] = value;
|
||||
});
|
||||
bodyObj.headers = headerObj
|
||||
}
|
||||
const requestBody = JSON.stringify(bodyObj);
|
||||
console.log(`exec worker , binding = ${bindingName} , requestBody = ${requestBody}`);
|
||||
await method(requestBody);
|
||||
} catch (e1) {
|
||||
console.error(`execute method = ${methodName} error`, e1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const CONSTANTS = {
|
||||
VERSION: 'v0.8.4',
|
||||
VERSION: 'v0.8.6',
|
||||
|
||||
// DB settings
|
||||
ADDRESS_BLOCK_LIST_KEY: 'address_block_list',
|
||||
|
||||
52
worker/src/email/check_attachment.ts
Normal file
52
worker/src/email/check_attachment.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Bindings, ParsedEmailContext } from "../types";
|
||||
import { getBooleanValue } from "../utils";
|
||||
import { commonParseMail } from "../common";
|
||||
import { createMimeMessage } from "mimetext";
|
||||
|
||||
export const remove_attachment_if_need = async (
|
||||
env: Bindings,
|
||||
parsedEmailContext: ParsedEmailContext,
|
||||
from_address: string,
|
||||
to_address: string,
|
||||
size: number
|
||||
): Promise<void> => {
|
||||
// if configured, remove all attachment
|
||||
const removeAllAttachment = getBooleanValue(env.REMOVE_ALL_ATTACHMENT);
|
||||
// if attachment size > 2MB, remove attachment
|
||||
const removeExceedSizeAttachment = getBooleanValue(env.REMOVE_EXCEED_SIZE_ATTACHMENT) && size >= 2 * 1024 * 1024;
|
||||
const shouldRemoveAttachment = removeAllAttachment || removeExceedSizeAttachment;
|
||||
if (!shouldRemoveAttachment) return;
|
||||
|
||||
const parsedEmail = await commonParseMail(parsedEmailContext);
|
||||
if (!parsedEmail) return;
|
||||
|
||||
const msg = createMimeMessage();
|
||||
if (parsedEmail?.headers) {
|
||||
for (const header of parsedEmail.headers) {
|
||||
try {
|
||||
msg.setHeader(header["key"], header["value"]);
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
msg.setSender({
|
||||
name: parsedEmail?.sender || from_address,
|
||||
addr: from_address
|
||||
});
|
||||
msg.setRecipient(to_address);
|
||||
msg.setSubject(parsedEmail?.subject || "Failed to parse email subject");
|
||||
if (parsedEmail?.html) {
|
||||
msg.addMessage({
|
||||
contentType: 'text/html',
|
||||
data: parsedEmail.html
|
||||
});
|
||||
}
|
||||
if (parsedEmail?.text) {
|
||||
msg.addMessage({
|
||||
contentType: 'text/plain',
|
||||
data: parsedEmail.text
|
||||
});
|
||||
}
|
||||
parsedEmailContext.rawEmail = msg.asRaw();
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { auto_reply } from "./auto_reply";
|
||||
import { isBlocked } from "./black_list";
|
||||
import { triggerWebhook, triggerAnotherWorker, commonParseMail } from "../common";
|
||||
import { check_if_junk_mail } from "./check_junk";
|
||||
import { remove_attachment_if_need } from "./check_attachment";
|
||||
|
||||
|
||||
async function email(message: ForwardableEmailMessage, env: Bindings, ctx: ExecutionContext) {
|
||||
@@ -29,7 +30,14 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("check junk mail error", error);
|
||||
console.error("check junk mail error", error);
|
||||
}
|
||||
|
||||
// remove attachment if configured or size > 2MB
|
||||
try {
|
||||
await remove_attachment_if_need(env, parsedEmailContext, message.from, message.to, message.rawSize);
|
||||
} catch (error) {
|
||||
console.error("remove attachment error", error);
|
||||
}
|
||||
|
||||
const message_id = message.headers.get("Message-ID");
|
||||
@@ -38,15 +46,15 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu
|
||||
const { success } = await env.DB.prepare(
|
||||
`INSERT INTO raw_mails (source, address, raw, message_id) VALUES (?, ?, ?, ?)`
|
||||
).bind(
|
||||
message.from, message.to, rawEmail, message_id
|
||||
message.from, message.to, parsedEmailContext.rawEmail, message_id
|
||||
).run();
|
||||
if (!success) {
|
||||
message.setReject(`Failed save message to ${message.to}`);
|
||||
console.log(`Failed save message from ${message.from} to ${message.to}`);
|
||||
console.error(`Failed save message from ${message.from} to ${message.to}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log("save email error", error);
|
||||
console.error("save email error", error);
|
||||
}
|
||||
|
||||
// forward email
|
||||
@@ -56,7 +64,7 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu
|
||||
await message.forward(forwardAddress);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("forward email error", error);
|
||||
console.error("forward email error", error);
|
||||
}
|
||||
|
||||
// send email to telegram
|
||||
@@ -65,7 +73,7 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu
|
||||
{ env: env } as Context<HonoCustomType>,
|
||||
message.to, parsedEmailContext, message_id);
|
||||
} catch (error) {
|
||||
console.log("send mail to telegram error", error);
|
||||
console.error("send mail to telegram error", error);
|
||||
}
|
||||
|
||||
// send webhook
|
||||
@@ -75,21 +83,18 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu
|
||||
message.to, parsedEmailContext, message_id
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("send webhook error", error);
|
||||
console.error("send webhook error", error);
|
||||
}
|
||||
|
||||
// trigger another worker
|
||||
try {
|
||||
const headersMap = new Map<string, string>();
|
||||
if (message.headers) {
|
||||
message.headers.forEach((value, key) => { headersMap.set(key, value); });
|
||||
}
|
||||
const parsedText = (await commonParseMail(parsedEmailContext))?.text ?? ""
|
||||
const parsedEmail = (await commonParseMail(parsedEmailContext));
|
||||
const parsedText = parsedEmail?.text ?? ""
|
||||
const rpcEmail: RPCEmailMessage = {
|
||||
from: message.from,
|
||||
to: message.to,
|
||||
rawEmail: rawEmail,
|
||||
headers: headersMap
|
||||
headers: message.headers
|
||||
}
|
||||
await triggerAnotherWorker({ env: env } as Context<HonoCustomType>, rpcEmail, parsedText);
|
||||
} catch (error) {
|
||||
|
||||
@@ -338,8 +338,8 @@ export async function sendMailToTelegram(
|
||||
return;
|
||||
}
|
||||
const settings = await c.env.KV.get<TelegramSettings>(CONSTANTS.TG_KV_SETTINGS_KEY, "json");
|
||||
const golbalPush = settings?.enableGlobalMailPush && settings?.globalMailPushList;
|
||||
if (!userId && !golbalPush) {
|
||||
const globalPush = settings?.enableGlobalMailPush && settings?.globalMailPushList;
|
||||
if (!userId && !globalPush) {
|
||||
return;
|
||||
}
|
||||
const mailId = await c.env.DB.prepare(
|
||||
@@ -353,7 +353,7 @@ export async function sendMailToTelegram(
|
||||
url.searchParams.set("mail_id", mailId);
|
||||
miniAppButtons.push(Markup.button.webApp("查看邮件", url.toString()));
|
||||
}
|
||||
if (golbalPush) {
|
||||
if (globalPush) {
|
||||
for (const pushId of settings.globalMailPushList) {
|
||||
await bot.telegram.sendMessage(pushId, mail, {
|
||||
...Markup.inlineKeyboard([
|
||||
|
||||
4
worker/src/types.d.ts
vendored
4
worker/src/types.d.ts
vendored
@@ -50,6 +50,8 @@ export type Bindings = {
|
||||
ENABLE_ANOTHER_WORKER: string | boolean | undefined
|
||||
ANOTHER_WORKER_LIST: string | AnotherWorker[] | undefined
|
||||
|
||||
REMOVE_ALL_ATTACHMENT: string | boolean | undefined
|
||||
REMOVE_EXCEED_SIZE_ATTACHMENT: string | boolean | undefined
|
||||
|
||||
// s3 config
|
||||
S3_ENDPOINT: string | undefined
|
||||
@@ -108,7 +110,7 @@ type RPCEmailMessage = {
|
||||
from: string | undefined | null,
|
||||
to: string | undefined | null,
|
||||
rawEmail: string | undefined | null,
|
||||
headers: Map<string, string>,
|
||||
headers: object | undefined | null,
|
||||
}
|
||||
|
||||
type ParsedEmailContext = {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { api as telegramApi } from './telegram_api'
|
||||
|
||||
import { email } from './email';
|
||||
import { scheduled } from './scheduled';
|
||||
import { getAdminPasswords, getPasswords, getBooleanValue } from './utils';
|
||||
import { getAdminPasswords, getPasswords, getBooleanValue, getStringArray } from './utils';
|
||||
import { HonoCustomType, UserPayload } from './types';
|
||||
|
||||
const app = new Hono<HonoCustomType>()
|
||||
@@ -210,14 +210,21 @@ app.route('/', adminApi)
|
||||
app.route('/', apiSendMail)
|
||||
app.route('/', telegramApi)
|
||||
|
||||
app.get('/', async c => {
|
||||
if (!c.env.DB) { return c.text("DB is not available", 400); }
|
||||
const health_check = async (c: Context<HonoCustomType>) => {
|
||||
if (!c.env.DB) {
|
||||
return c.text("DB is not available", 400);
|
||||
}
|
||||
if (!c.env.JWT_SECRET) {
|
||||
return c.text("JWT_SECRET is not set", 400);
|
||||
}
|
||||
if (getStringArray(c.env.DOMAINS).length === 0) {
|
||||
return c.text("DOMAINS is not set", 400);
|
||||
}
|
||||
return c.text("OK");
|
||||
})
|
||||
app.get('/health_check', async c => {
|
||||
if (!c.env.DB) { return c.text("DB is not available", 400); }
|
||||
return c.text("OK");
|
||||
})
|
||||
}
|
||||
|
||||
app.get('/', health_check)
|
||||
app.get('/health_check', health_check)
|
||||
app.all('/*', async c => c.text("Not Found", 404))
|
||||
|
||||
|
||||
|
||||
@@ -80,10 +80,14 @@ ENABLE_AUTO_REPLY = false
|
||||
# JUNK_MAIL_CHECK_LIST = = ["spf", "dkim", "dmarc"]
|
||||
# junk mail force check pass list, if no status or status is not pass, will be marked as junk mail
|
||||
# JUNK_MAIL_FORCE_PASS_LIST = ["spf", "dkim", "dmarc"]
|
||||
# remove attachment if size exceed 2MB, mail maybe mising some information due to parsing
|
||||
# REMOVE_EXCEED_SIZE_ATTACHMENT = true
|
||||
# remove all attachment, mail maybe mising some information due to parsing
|
||||
# REMOVE_ALL_ATTACHMENT = true
|
||||
# Calling other woker to process email
|
||||
#ENABLE_ANOTHER_WORKER = false
|
||||
#ANOTHER_WORKER_LIST ="""
|
||||
#[
|
||||
# ENABLE_ANOTHER_WORKER = false
|
||||
# ANOTHER_WORKER_LIST = """
|
||||
# [
|
||||
# {
|
||||
# "binding":"AUTH_INBOX",
|
||||
# "method":"rpcEmail",
|
||||
@@ -92,8 +96,8 @@ ENABLE_AUTO_REPLY = false
|
||||
# "account","activation","verify","verification","activate","confirmation","email","code","validate","registration","login","code","expire","confirm"
|
||||
# ]
|
||||
# }
|
||||
#]
|
||||
#"""
|
||||
# ]
|
||||
# """
|
||||
|
||||
[[d1_databases]]
|
||||
binding = "DB"
|
||||
|
||||
Reference in New Issue
Block a user