mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-17 07:17:36 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50f04b2456 | ||
|
|
2ec1a61608 | ||
|
|
eafcf00e5e | ||
|
|
d73fee2c97 | ||
|
|
4bb1016887 |
2
.github/workflows/docs_deploy.yml
vendored
2
.github/workflows/docs_deploy.yml
vendored
@@ -17,6 +17,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|||||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,6 +1,17 @@
|
|||||||
# CHANGE LOG
|
# CHANGE LOG
|
||||||
|
|
||||||
## 2024-04-12 v0.2.1
|
## v0.2.7
|
||||||
|
|
||||||
|
- Added user interface installation documentation
|
||||||
|
- Support email DKIM
|
||||||
|
- Rate limiting configuration for `/api/new_address`
|
||||||
|
|
||||||
|
## v0.2.6
|
||||||
|
|
||||||
|
- Added admin query outbox page
|
||||||
|
- Add admin data cleaning page
|
||||||
|
|
||||||
|
## 2024-04-12 v0.2.5
|
||||||
|
|
||||||
- support send email
|
- support send email
|
||||||
|
|
||||||
|
|||||||
45
README.md
45
README.md
@@ -1,16 +1,13 @@
|
|||||||
# 使用 cloudflare 免费服务,搭建临时邮箱
|
# 使用 cloudflare 免费服务,搭建临时邮箱
|
||||||
|
|
||||||
## [English](README_EN.md)
|
|
||||||
|
|
||||||
## [查看部署文档](https://temp-mail-docs.awsl.uk)
|
## [查看部署文档](https://temp-mail-docs.awsl.uk)
|
||||||
|
|
||||||
|
## [English](https://temp-mail-docs.awsl.uk/en/)
|
||||||
|
|
||||||
## [CHANGELOG](CHANGELOG.md)
|
## [CHANGELOG](CHANGELOG.md)
|
||||||
|
|
||||||
## [在线演示](https://mail.awsl.uk/)
|
## [在线演示](https://mail.awsl.uk/)
|
||||||
|
|
||||||
[https://mail.awsl.uk](https://mail.awsl.uk/)
|
|
||||||
或者 [https://temp-email.dreamhunter2333.xyz](https://temp-email.dreamhunter2333.xyz/)
|
|
||||||
|
|
||||||
[Backend](https://temp-email-api.awsl.uk/)
|
[Backend](https://temp-email-api.awsl.uk/)
|
||||||

|

|
||||||

|

|
||||||
@@ -34,8 +31,8 @@
|
|||||||
</picture>
|
</picture>
|
||||||
|
|
||||||
- [使用 cloudflare 免费服务,搭建临时邮箱](#使用-cloudflare-免费服务搭建临时邮箱)
|
- [使用 cloudflare 免费服务,搭建临时邮箱](#使用-cloudflare-免费服务搭建临时邮箱)
|
||||||
- [English](#english)
|
|
||||||
- [查看部署文档](#查看部署文档)
|
- [查看部署文档](#查看部署文档)
|
||||||
|
- [English](#english)
|
||||||
- [CHANGELOG](#changelog)
|
- [CHANGELOG](#changelog)
|
||||||
- [在线演示](#在线演示)
|
- [在线演示](#在线演示)
|
||||||
- [功能/TODO](#功能todo)
|
- [功能/TODO](#功能todo)
|
||||||
@@ -47,6 +44,7 @@
|
|||||||
- [Cloudflare Email Routing](#cloudflare-email-routing)
|
- [Cloudflare Email Routing](#cloudflare-email-routing)
|
||||||
- [Cloudflare Pages 前端](#cloudflare-pages-前端)
|
- [Cloudflare Pages 前端](#cloudflare-pages-前端)
|
||||||
- [配置发送邮件](#配置发送邮件)
|
- [配置发送邮件](#配置发送邮件)
|
||||||
|
- [配置 DKIM](#配置-dkim)
|
||||||
- [参考资料](#参考资料)
|
- [参考资料](#参考资料)
|
||||||
|
|
||||||
## 功能/TODO
|
## 功能/TODO
|
||||||
@@ -63,6 +61,7 @@
|
|||||||
- [x] 增加查看附件功能
|
- [x] 增加查看附件功能
|
||||||
- [x] 使用 rust wasm 解析邮件
|
- [x] 使用 rust wasm 解析邮件
|
||||||
- [x] 支持发送邮件
|
- [x] 支持发送邮件
|
||||||
|
- [x] 支持 DKIM
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -147,11 +146,22 @@ PREFIX = "tmp" # 要处理的邮箱名称前缀
|
|||||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名
|
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名
|
||||||
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥
|
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥
|
||||||
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
||||||
|
# dkim config
|
||||||
|
# DKIM_SELECTOR = "mailchannels" # 参考 DKIM 部分 mailchannels._domainkey 的 mailchannels
|
||||||
|
# DKIM_PRIVATE_KEY = "" # 参考 DKIM 部分 priv_key.txt 的内容
|
||||||
|
|
||||||
[[d1_databases]]
|
[[d1_databases]]
|
||||||
binding = "DB"
|
binding = "DB"
|
||||||
database_name = "xxx" # D1 数据库名称
|
database_name = "xxx" # D1 数据库名称
|
||||||
database_id = "xxx" # D1 数据库 ID
|
database_id = "xxx" # D1 数据库 ID
|
||||||
|
|
||||||
|
# 新建地址限流配置
|
||||||
|
# [[unsafe.bindings]]
|
||||||
|
# name = "RATE_LIMITER"
|
||||||
|
# type = "ratelimit"
|
||||||
|
# namespace_id = "1001"
|
||||||
|
# # 10 requests per minute
|
||||||
|
# simple = { limit = 10, period = 60 }
|
||||||
```
|
```
|
||||||
|
|
||||||
部署
|
部署
|
||||||
@@ -215,6 +225,29 @@ v=spf1 include:_spf.mx.cloudflare.net include:relay.mailchannels.net ~all
|
|||||||
- 此处 worker 域名为后端 api 的域名,比如我部署在 `https://temp-email-api.awsl.uk/`,则填写 `v=mc1 cfid=awsl.uk`
|
- 此处 worker 域名为后端 api 的域名,比如我部署在 `https://temp-email-api.awsl.uk/`,则填写 `v=mc1 cfid=awsl.uk`
|
||||||
- 如果你的域名是 `https://temp-email-api.xxx.workers.dev`,则填写 `v=mc1 cfid=xxx.workers.dev`
|
- 如果你的域名是 `https://temp-email-api.xxx.workers.dev`,则填写 `v=mc1 cfid=xxx.workers.dev`
|
||||||
|
|
||||||
|
## 配置 DKIM
|
||||||
|
|
||||||
|
参考: [Adding-a-DKIM-Signature](https://support.mailchannels.com/hc/en-us/articles/7122849237389-Adding-a-DKIM-Signature)
|
||||||
|
|
||||||
|
Creating a DKIM private and public key:
|
||||||
|
Private key as PEM file and base64 encoded txt file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl genrsa 2048 | tee priv_key.pem | openssl rsa -outform der | openssl base64 -A > priv_key.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Public key as DNS record:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo -n "v=DKIM1;p=" > pub_key_record.txt && \
|
||||||
|
openssl rsa -in priv_key.pem -pubout -outform der | openssl base64 -A >> pub_key_record.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
在 `Cloudflare` 的 `DNS` 记录中添加 `TXT` 记录
|
||||||
|
|
||||||
|
- `_dmarc`: `v=DMARC1; p=none; adkim=r; aspf=r;`
|
||||||
|
- `mailchannels._domainkey`: `v=DKIM1; p=<content of the file pub_key_record.txt>`
|
||||||
|
|
||||||
## 参考资料
|
## 参考资料
|
||||||
|
|
||||||
- https://developers.cloudflare.com/d1/
|
- https://developers.cloudflare.com/d1/
|
||||||
|
|||||||
115
README_EN.md
115
README_EN.md
@@ -1,115 +0,0 @@
|
|||||||
# cloudflare temp email
|
|
||||||
|
|
||||||
## [中文](README.md)
|
|
||||||
|
|
||||||
[CHANGELOG](CHANGELOG.md)
|
|
||||||
|
|
||||||
## [Live Demo](https://mail.awsl.uk/)
|
|
||||||
|
|
||||||
[https://mail.awsl.uk](https://mail.awsl.uk/)
|
|
||||||
|
|
||||||
This is a temporary email service that uses Cloudflare Workers to create a temporary email address and view the received email in web browser.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- [x] Cloudflare D1 as a database
|
|
||||||
- [x] Deploy the front end with Cloudflare Pages
|
|
||||||
- [x] Deploy the backend with Cloudflare Workers
|
|
||||||
- [x] Email forwarding using Cloudflare Email Routing
|
|
||||||
- [x] Use password to login to the previous mailbox again.
|
|
||||||
- [x] Get Custom Name Email
|
|
||||||
- [x] Support multiple languages
|
|
||||||
- [x] Add access authorization, which can be used as a private site
|
|
||||||
- [x] Add auto reply feature
|
|
||||||
- [x] Add attachment viewing function
|
|
||||||
- [x] use rust wasm to parse email
|
|
||||||
- [x] support send email
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Deploy
|
|
||||||
|
|
||||||
[Install/Update Wrangler](https://developers.cloudflare.com/workers/wrangler/install-and-update/)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install wrangler -g
|
|
||||||
git clone https://github.com/dreamhunter2333/cloudflare_temp_email.git
|
|
||||||
# Switch to the latest tag or the branch you want to deploy. You can also use the main branch directly.
|
|
||||||
# git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
|
|
||||||
```
|
|
||||||
|
|
||||||
## DB - Cloudflare D1
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# create a database, and copy the output to wrangler.toml in the next step
|
|
||||||
wrangler d1 create dev
|
|
||||||
wrangler d1 execute dev --file=db/schema.sql
|
|
||||||
# schema update, if you have initialized the database before this date, you can execute this command to update
|
|
||||||
# wrangler d1 execute dev --file=db/2024-01-13-patch.sql
|
|
||||||
# wrangler d1 execute dev --file=db/2024-04-03-patch.sql
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Backend - Cloudflare workers
|
|
||||||
|
|
||||||
The first deployment will prompt you to create a project. Please fill in `production` for the `production` branch.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd worker
|
|
||||||
pnpm install
|
|
||||||
# copy wrangler.toml.template to wrangler.toml
|
|
||||||
# and add your d1 config and these config
|
|
||||||
# PREFIX = "tmp" - the email create will be like tmp<xxxxx>@DOMAIN
|
|
||||||
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
|
||||||
# PASSWORDS = ["123", "456"]
|
|
||||||
# For admin panel, if not set will no allow to access the admin panel
|
|
||||||
# ADMIN_PASSWORDS = ["123", "456"]
|
|
||||||
# DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] you domain name
|
|
||||||
# JWT_SECRET = "xxx"
|
|
||||||
# BLACK_LIST = ""
|
|
||||||
cp wrangler.toml.template wrangler.toml
|
|
||||||
# deploy
|
|
||||||
pnpm run deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
you can find and test the worker's url in the workers dashboard
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Cloudflare Email Routing
|
|
||||||
|
|
||||||
Before you can bind an email address to your Worker, you need to enable Email Routing and have at least one verified email address.
|
|
||||||
|
|
||||||
enable email route and config email forward catch-all to the worker
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Frontend - Cloudflare pages
|
|
||||||
|
|
||||||
The first deployment will prompt you to create a project. Please fill in `production` for the `production` branch.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd frontend
|
|
||||||
pnpm install
|
|
||||||
# add .env.local and modify VITE_API_BASE to your worker's url
|
|
||||||
# VITE_API_BASE=https://xxx.xxx.workers.dev - don't put / in the end
|
|
||||||
cp .env.example .env.local
|
|
||||||
pnpm build --emptyOutDir
|
|
||||||
pnpm run deploy
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Configure sending emails
|
|
||||||
|
|
||||||
Find the `SPF` record of `TXT` in the domain name `DNS` record, and add `include:relay.mailchannels.net`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
v=spf1 include:_spf.mx.cloudflare.net include:relay.mailchannels.net ~all
|
|
||||||
```
|
|
||||||
|
|
||||||
Create a new `_mailchannels` record, the type is `TXT`, the content is `v=mc1 cfid=your worker domain name`
|
|
||||||
|
|
||||||
- The worker domain name here is the domain name of the back-end api. For example, if I deploy it at `https://temp-email-api.awsl.uk/`, fill in `v=mc1 cfid=awsl.uk`
|
|
||||||
- If your domain name is `https://temp-email-api.xxx.workers.dev`, fill in `v=mc1 cfid=xxx.workers.dev`
|
|
||||||
@@ -100,6 +100,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
|||||||
items: [
|
items: [
|
||||||
{ text: '命令行部署准备', link: 'cli/pre-requisite' },
|
{ text: '命令行部署准备', link: 'cli/pre-requisite' },
|
||||||
{ text: 'D1 数据库', link: 'cli/d1' },
|
{ text: 'D1 数据库', link: 'cli/d1' },
|
||||||
|
{ text: '配置 DKIM', link: 'dkim' },
|
||||||
{ text: 'Cloudflare workers 后端', link: 'cli/worker' },
|
{ text: 'Cloudflare workers 后端', link: 'cli/worker' },
|
||||||
{ text: '配置邮件转发', link: 'email-routing.md' },
|
{ text: '配置邮件转发', link: 'email-routing.md' },
|
||||||
{ text: 'Cloudflare Pages 前端', link: 'cli/pages' },
|
{ text: 'Cloudflare Pages 前端', link: 'cli/pages' },
|
||||||
@@ -111,6 +112,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
|||||||
collapsed: false,
|
collapsed: false,
|
||||||
items: [
|
items: [
|
||||||
{ text: 'D1 数据库', link: 'ui/d1' },
|
{ text: 'D1 数据库', link: 'ui/d1' },
|
||||||
|
{ text: '配置 DKIM', link: 'dkim' },
|
||||||
{ text: 'Cloudflare workers 后端', link: 'ui/worker' },
|
{ text: 'Cloudflare workers 后端', link: 'ui/worker' },
|
||||||
{ text: '配置邮件转发', link: 'email-routing.md' },
|
{ text: '配置邮件转发', link: 'email-routing.md' },
|
||||||
{ text: 'Cloudflare Pages 前端', link: 'ui/pages' },
|
{ text: 'Cloudflare Pages 前端', link: 'ui/pages' },
|
||||||
@@ -121,7 +123,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
|||||||
text: '功能简介',
|
text: '功能简介',
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
items: [
|
items: [
|
||||||
// { text: '先决条件', link: 'pre-requisite' },
|
{ text: 'Admin 控制台', link: 'feature/admin' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ text: '参考', base: "/", link: 'reference' }
|
{ text: '参考', base: "/", link: 'reference' }
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# cloudflare temp email
|
# cloudflare temp email
|
||||||
|
|
||||||
|
This is a temporary email service that uses Cloudflare Workers to create a temporary email address and view the received email in web browser.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [x] Cloudflare D1 as a database
|
- [x] Cloudflare D1 as a database
|
||||||
@@ -14,6 +16,7 @@
|
|||||||
- [x] Add attachment viewing function
|
- [x] Add attachment viewing function
|
||||||
- [x] use rust wasm to parse email
|
- [x] use rust wasm to parse email
|
||||||
- [x] support send email
|
- [x] support send email
|
||||||
|
- [x] support DKIM
|
||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
|
|
||||||
@@ -46,21 +49,46 @@ The first deployment will prompt you to create a project. Please fill in `produc
|
|||||||
```bash
|
```bash
|
||||||
cd worker
|
cd worker
|
||||||
pnpm install
|
pnpm install
|
||||||
# copy wrangler.toml.template to wrangler.toml
|
|
||||||
# and add your d1 config and these config
|
|
||||||
# PREFIX = "tmp" - the email create will be like tmp<xxxxx>@DOMAIN
|
|
||||||
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
|
||||||
# PASSWORDS = ["123", "456"]
|
|
||||||
# For admin panel, if not set will no allow to access the admin panel
|
|
||||||
# ADMIN_PASSWORDS = ["123", "456"]
|
|
||||||
# DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] you domain name
|
|
||||||
# JWT_SECRET = "xxx"
|
|
||||||
# BLACK_LIST = ""
|
|
||||||
cp wrangler.toml.template wrangler.toml
|
cp wrangler.toml.template wrangler.toml
|
||||||
# deploy
|
# deploy
|
||||||
pnpm run deploy
|
pnpm run deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`wrangler.toml`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
name = "cloudflare_temp_email"
|
||||||
|
main = "src/worker.js"
|
||||||
|
compatibility_date = "2023-08-14"
|
||||||
|
node_compat = true
|
||||||
|
|
||||||
|
[vars]
|
||||||
|
PREFIX = "tmp" # The mailbox name prefix to be processed
|
||||||
|
# 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
|
||||||
|
# ADMIN_PASSWORDS = ["123", "456"]
|
||||||
|
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # your domain name
|
||||||
|
JWT_SECRET = "xxx" # Key used to generate jwt
|
||||||
|
BLACK_LIST = "" # Blacklist, used to filter senders, comma separated
|
||||||
|
# dkim config
|
||||||
|
# DKIM_SELECTOR = "mailchannels" # Refer to the DKIM section mailchannels._domainkey for mailchannels
|
||||||
|
# DKIM_PRIVATE_KEY = "" # Refer to the contents of priv_key.txt in the DKIM section
|
||||||
|
|
||||||
|
[[d1_databases]]
|
||||||
|
binding = "DB"
|
||||||
|
database_name = "xxx" # D1 database name
|
||||||
|
database_id = "xxx" # D1 database ID
|
||||||
|
|
||||||
|
# Create a new address current limiting configuration
|
||||||
|
# [[unsafe.bindings]]
|
||||||
|
# name = "RATE_LIMITER"
|
||||||
|
# type = "ratelimit"
|
||||||
|
# namespace_id = "1001"
|
||||||
|
# # 10 requests per minute
|
||||||
|
# simple = { limit = 10, period = 60 }
|
||||||
|
```
|
||||||
|
|
||||||
you can find and test the worker's url in the workers dashboard
|
you can find and test the worker's url in the workers dashboard
|
||||||
|
|
||||||

|

|
||||||
@@ -101,3 +129,26 @@ Create a new `_mailchannels` record, the type is `TXT`, the content is `v=mc1 cf
|
|||||||
|
|
||||||
- The worker domain name here is the domain name of the back-end api. For example, if I deploy it at `https://temp-email-api.awsl.uk/`, fill in `v=mc1 cfid=awsl.uk`
|
- The worker domain name here is the domain name of the back-end api. For example, if I deploy it at `https://temp-email-api.awsl.uk/`, fill in `v=mc1 cfid=awsl.uk`
|
||||||
- If your domain name is `https://temp-email-api.xxx.workers.dev`, fill in `v=mc1 cfid=xxx.workers.dev`
|
- If your domain name is `https://temp-email-api.xxx.workers.dev`, fill in `v=mc1 cfid=xxx.workers.dev`
|
||||||
|
|
||||||
|
## Configure DKIM
|
||||||
|
|
||||||
|
Ref: [Adding-a-DKIM-Signature](https://support.mailchannels.com/hc/en-us/articles/7122849237389-Adding-a-DKIM-Signature)
|
||||||
|
|
||||||
|
Creating a DKIM private and public key:
|
||||||
|
Private key as PEM file and base64 encoded txt file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl genrsa 2048 | tee priv_key.pem | openssl rsa -outform der | openssl base64 -A > priv_key.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Public key as DNS record:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo -n "v=DKIM1;p=" > pub_key_record.txt && \
|
||||||
|
openssl rsa -in priv_key.pem -pubout -outform der | openssl base64 -A >> pub_key_record.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `TXT` record in `Cloudflare` all your mail domain `DNS`
|
||||||
|
|
||||||
|
- `_dmarc`: `v=DMARC1; p=none; adkim=r; aspf=r;`
|
||||||
|
- `mailchannels._domainkey`: `v=DKIM1; p=<content of the file pub_key_record.txt>`
|
||||||
|
|||||||
BIN
vitepress-docs/docs/public/feature/admin.png
Normal file
BIN
vitepress-docs/docs/public/feature/admin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -10,7 +10,7 @@ cp wrangler.toml.template wrangler.toml
|
|||||||
|
|
||||||
## 修改 `wrangler.toml` 配置文件
|
## 修改 `wrangler.toml` 配置文件
|
||||||
|
|
||||||
```bash
|
```toml
|
||||||
name = "cloudflare_temp_email"
|
name = "cloudflare_temp_email"
|
||||||
main = "src/worker.js"
|
main = "src/worker.js"
|
||||||
compatibility_date = "2023-12-01"
|
compatibility_date = "2023-12-01"
|
||||||
@@ -29,12 +29,23 @@ PREFIX = "tmp" # 要处理的邮箱名称前缀,不需要后缀可配置为空
|
|||||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名, 支持多个域名
|
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名, 支持多个域名
|
||||||
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥
|
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥
|
||||||
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
||||||
|
# dkim config
|
||||||
|
# DKIM_SELECTOR = "mailchannels" # 参考 DKIM 部分 mailchannels._domainkey 的 mailchannels
|
||||||
|
# DKIM_PRIVATE_KEY = "" # 参考 DKIM 部分 priv_key.txt 的内容
|
||||||
|
|
||||||
# D1 数据库的名称和 ID 可以在 cloudflare 控制台查看
|
# D1 数据库的名称和 ID 可以在 cloudflare 控制台查看
|
||||||
[[d1_databases]]
|
[[d1_databases]]
|
||||||
binding = "DB"
|
binding = "DB"
|
||||||
database_name = "xxx" # D1 数据库名称
|
database_name = "xxx" # D1 数据库名称
|
||||||
database_id = "xxx" # D1 数据库 ID
|
database_id = "xxx" # D1 数据库 ID
|
||||||
|
|
||||||
|
# 新建地址限流配置 /api/new_address
|
||||||
|
# [[unsafe.bindings]]
|
||||||
|
# name = "RATE_LIMITER"
|
||||||
|
# type = "ratelimit"
|
||||||
|
# namespace_id = "1001"
|
||||||
|
# # 10 requests per minute
|
||||||
|
# simple = { limit = 10, period = 60 }
|
||||||
```
|
```
|
||||||
|
|
||||||
## 部署
|
## 部署
|
||||||
|
|||||||
31
vitepress-docs/docs/zh/guide/dkim.md
Normal file
31
vitepress-docs/docs/zh/guide/dkim.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# 配置 DKIM
|
||||||
|
|
||||||
|
参考: [Adding-a-DKIM-Signature](https://support.mailchannels.com/hc/en-us/articles/7122849237389-Adding-a-DKIM-Signature)
|
||||||
|
|
||||||
|
Creating a DKIM private and public key:
|
||||||
|
Private key as PEM file and base64 encoded txt file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl genrsa 2048 | tee priv_key.pem | openssl rsa -outform der | openssl base64 -A > priv_key.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Public key as DNS record:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo -n "v=DKIM1;p=" > pub_key_record.txt && \
|
||||||
|
openssl rsa -in priv_key.pem -pubout -outform der | openssl base64 -A >> pub_key_record.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
在 `Cloudflare` 的 `DNS` 记录中添加 `TXT` 记录
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
- `_dmarc`: `v=DMARC1; p=none; adkim=r; aspf=r;`
|
||||||
|
- `mailchannels._domainkey`: `v=DKIM1; p=<content of the file pub_key_record.txt>`
|
||||||
|
|
||||||
|
那我在 `wrangler.toml` 中的配置应该是这样的:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
DKIM_SELECTOR = "mailchannels"
|
||||||
|
DKIM_PRIVATE_KEY = "<priv_key.txt 的内容>"
|
||||||
|
```
|
||||||
7
vitepress-docs/docs/zh/guide/feature/admin.md
Normal file
7
vitepress-docs/docs/zh/guide/feature/admin.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Admin 控制台
|
||||||
|
|
||||||
|
部署前端应用之后,访问 `/admin` 路径即可进入管理控制台。
|
||||||
|
|
||||||
|
需要在后端配置 `admin 控制台密码`, 不配置则不允许访问控制台。
|
||||||
|
|
||||||
|

|
||||||
@@ -6,6 +6,3 @@
|
|||||||
打开 [cloudflare控制台](https://dash.cloudflare.com/)
|
打开 [cloudflare控制台](https://dash.cloudflare.com/)
|
||||||
|
|
||||||
请查看通过 [命令行部署](/zh/guide/cli/pre-requisite) 或者 [用户界面部署](/zh/guide/ui/d1)
|
请查看通过 [命令行部署](/zh/guide/cli/pre-requisite) 或者 [用户界面部署](/zh/guide/ui/d1)
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> 用户界面部署正在开发中,文档不完整
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
# Cloudflare workers 后端
|
# Cloudflare workers 后端
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> 用户界面部署正在开发中,文档不完整
|
|
||||||
|
|
||||||
1. 点击 `Workers & Pages` -> `Overview` -> `Create Application`
|
1. 点击 `Workers & Pages` -> `Overview` -> `Create Application`
|
||||||
|
|
||||||

|

|
||||||
@@ -21,9 +18,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
6. 点击 `Settings` -> `Variables`, 如图所示添加变量,参考 README.md 中的 `wrangler.toml` 文件的 `vars` 部分
|
6. 点击 `Settings` -> `Variables`, 如图所示添加变量,参考 [修改 wrangler.toml 配置文件](/zh/guide/cli/worker.html#修改-wrangler-toml-配置文件) 中的 `vars` 部分
|
||||||
|
|
||||||
TODO: 控制台此处变量不支持添加 JSON 变量,正在考虑解决方案
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "temp-mail-docs",
|
"name": "temp-mail-docs",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "0.2.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.12.7",
|
"@types/node": "^20.12.7",
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ api.get('/admin/mails', async (c) => {
|
|||||||
return c.text("Invalid offset", 400)
|
return c.text("Invalid offset", 400)
|
||||||
}
|
}
|
||||||
const { results } = await c.env.DB.prepare(
|
const { results } = await c.env.DB.prepare(
|
||||||
`SELECT id, source, raw, created_at FROM raw_mails where address = ? order by id desc limit ? offset ?`
|
`SELECT * FROM raw_mails where address = ? order by id desc limit ? offset ?`
|
||||||
).bind(address, limit, offset).all();
|
).bind(address, limit, offset).all();
|
||||||
let count = 0;
|
let count = 0;
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
@@ -120,7 +120,7 @@ api.get('/admin/mails_unknow', async (c) => {
|
|||||||
return c.text("Invalid offset", 400)
|
return c.text("Invalid offset", 400)
|
||||||
}
|
}
|
||||||
const { results } = await c.env.DB.prepare(`
|
const { results } = await c.env.DB.prepare(`
|
||||||
SELECT id, source, raw, created_at FROM raw_mails
|
SELECT * FROM raw_mails
|
||||||
where address NOT IN(select concat('${c.env.PREFIX}', name) from address)
|
where address NOT IN(select concat('${c.env.PREFIX}', name) from address)
|
||||||
order by id desc limit ? offset ? `
|
order by id desc limit ? offset ? `
|
||||||
).bind(limit, offset).all();
|
).bind(limit, offset).all();
|
||||||
|
|||||||
@@ -52,13 +52,22 @@ api.post('/api/send_mail', async (c) => {
|
|||||||
if (!content) {
|
if (!content) {
|
||||||
return c.text("Invalid content", 400)
|
return c.text("Invalid content", 400)
|
||||||
}
|
}
|
||||||
const body = JSON.stringify({
|
let dmikBody = {}
|
||||||
|
if (c.env.DKIM_SELECTOR && c.env.DKIM_PRIVATE_KEY && address.includes("@")) {
|
||||||
|
dmikBody = {
|
||||||
|
"dkim_domain": address.split("@")[1],
|
||||||
|
"dkim_selector": c.env.DKIM_SELECTOR,
|
||||||
|
"dkim_private_key": c.env.DKIM_PRIVATE_KEY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const body = {
|
||||||
"personalizations": [
|
"personalizations": [
|
||||||
{
|
{
|
||||||
"to": [{
|
"to": [{
|
||||||
"email": to_mail,
|
"email": to_mail,
|
||||||
"name": to_name,
|
"name": to_name,
|
||||||
}]
|
}],
|
||||||
|
...dmikBody,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"from": {
|
"from": {
|
||||||
@@ -70,13 +79,13 @@ api.post('/api/send_mail', async (c) => {
|
|||||||
"type": is_html ? "text/html" : "text/plain",
|
"type": is_html ? "text/html" : "text/plain",
|
||||||
"value": content,
|
"value": content,
|
||||||
}],
|
}],
|
||||||
});
|
};
|
||||||
let send_request = new Request("https://api.mailchannels.net/tx/v1/send", {
|
let send_request = new Request("https://api.mailchannels.net/tx/v1/send", {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"headers": {
|
"headers": {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
},
|
},
|
||||||
"body": body,
|
"body": JSON.stringify(body),
|
||||||
});
|
});
|
||||||
const resp = await fetch(send_request);
|
const resp = await fetch(send_request);
|
||||||
const respText = await resp.text();
|
const respText = await resp.text();
|
||||||
@@ -98,9 +107,12 @@ api.post('/api/send_mail', async (c) => {
|
|||||||
}
|
}
|
||||||
// save to sendbox
|
// save to sendbox
|
||||||
try {
|
try {
|
||||||
|
if (body?.personalizations?.[0]?.dkim_private_key) {
|
||||||
|
delete body.personalizations[0].dkim_private_key;
|
||||||
|
}
|
||||||
const { success: success2 } = await c.env.DB.prepare(
|
const { success: success2 } = await c.env.DB.prepare(
|
||||||
`INSERT INTO sendbox (address, raw) VALUES (?, ?)`
|
`INSERT INTO sendbox (address, raw) VALUES (?, ?)`
|
||||||
).bind(address, body).run();
|
).bind(address, JSON.stringify(body)).run();
|
||||||
if (!success2) {
|
if (!success2) {
|
||||||
console.warn(`Failed to save to sendbox for ${address}`);
|
console.warn(`Failed to save to sendbox for ${address}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ app.use('/api/*', async (c, next) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c.req.path.startsWith("/api/new_address")) {
|
if (c.req.path.startsWith("/api/new_address")) {
|
||||||
|
const reqIp = c.req.raw.headers.get("cf-connecting-ip")
|
||||||
|
if (reqIp && c.env.RATE_LIMITER) {
|
||||||
|
const { success } = await c.env.RATE_LIMITER.limit({ key: reqIp })
|
||||||
|
if (!success) {
|
||||||
|
return c.text(`IP=${reqIp} Rate limit exceeded for /api/new_address`, 429)
|
||||||
|
}
|
||||||
|
}
|
||||||
await next();
|
await next();
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,8 +16,19 @@ PREFIX = "tmp"
|
|||||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"]
|
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"]
|
||||||
JWT_SECRET = "xxx"
|
JWT_SECRET = "xxx"
|
||||||
BLACK_LIST = ""
|
BLACK_LIST = ""
|
||||||
|
# dkim config
|
||||||
|
# DKIM_SELECTOR = ""
|
||||||
|
# DKIM_PRIVATE_KEY = ""
|
||||||
|
|
||||||
[[d1_databases]]
|
[[d1_databases]]
|
||||||
binding = "DB"
|
binding = "DB"
|
||||||
database_name = "xxx"
|
database_name = "xxx"
|
||||||
database_id = "xxx"
|
database_id = "xxx"
|
||||||
|
|
||||||
|
# ratelimit config for /api/new_address
|
||||||
|
# [[unsafe.bindings]]
|
||||||
|
# name = "RATE_LIMITER"
|
||||||
|
# type = "ratelimit"
|
||||||
|
# namespace_id = "1001"
|
||||||
|
# # 10 requests per minute
|
||||||
|
# simple = { limit = 10, period = 60 }
|
||||||
|
|||||||
Reference in New Issue
Block a user