教程:发现一款免费搭建电子邮箱服务的项目

很久以前就想搭建一个专属于自己的邮箱服务。曾经尝试使用了宝塔面板,但是由于服务器硬盘容量 系统版本 费用的问题也就暂时搁置了。今天无意中发现了这一款免费搭建自己的邮箱服务的项目,那个劲头立马就窜起来。

项目地址:https://github.com/eoao/cloud-mail

图文搭建教程: https://doc.skymail.ink/guide/via-ui

本项目使用Cloudflare worker部署,Resend推送邮件,无需服务器费用,就可以实现类似各大邮箱平台,如QQ邮箱,谷歌邮箱等自己的邮箱服务

前提是需要有个域名,并且dns设置为cloudflare的dns

好了,废话不多说了。开始了

一. 登录到cloudflare官网控制台,https://dash.cloudflare.com/

二. 点击左侧栏的 Workers 和 Pages,点击右上角的创建应用程序,点击导入存储库,导入该fork后的github项目。别跟我说不懂,哈哈

三. 点击高级设置-根目录-路径,修改路径为 /mail-worker,再点击创建和部署,等待完成

四. 构建和部署完成后。进入该项目,点击设置,点击域和路由,点击添加,选择自定义域,之后选择你之前绑定到cloudflare的域名

说一下,这里可以是子域名。比如你转发到cloudflare的域名是123456.com 那么你可以添加子域名mail.123456.com,这个稍后我会再讲到

五. 点击变量和机密,添加三个变量名

1
2
3
4
5
6
7

domain ["mail.123456.com"]

admin 管理员的邮箱,如admin@mail.123456.com

jwt_secret 123456

注意:domain是json类型的,其它两个都是文本。管理员账号之后需要你初始化数据后,在注册页面重新注册,否则是登录不了的

六. 创建kv数据库,点击控制面板左侧菜单栏,点击存储和数据库,创建kv数据库,命名空间名称随意,比如mail

七. 创建d1数据库,数据库名字随意,比如db。位置选择北美洲西部,不知道为什么,其它位置好像无法识别

八. 返回到worker项目,点击绑定-添加绑定-d1数据库-变量名称db-选择第7步创建的d1数据库,比如db

九. 点击绑定-添加绑定-kv命名空间-变量名称kv-选择第6步创建的kv数据库,比如mail

十. 浏览器输入https://你的自定义域名/api/init/你绑定的的jwt_secret 会自动初始化数据库(如果之前部署过只会更新不会覆盖原有数据)

十一. 浏览器输入你绑定的自定义域名网站,成功后,点击创建账号,使用admin账号注册,密码记住了。之后登录就直接有管理员的权限了

十二. 启用邮件接收,设置完成后才能接收邮件。回到cloudflare控制台,点击菜单账户主页,再点你的域名-点击电子邮件-开始使用-跳过入门指南-启用电子邮件路由-路由规则-状态改为活动-点击编辑-操作发送到worker,目标mail-点击保存

十三. 点击设置-点击添加子域(这里就是我之前第四步讲到的添加子域)-修改需要的子域,比如mail.123456.com

十四. 测试时候接受到邮件即可

十五. 设置附件收发,设置完这一步后才能接收附件和发送附件。由于这个可能会出现付费操作,所以我就不多说了。上面一般都够用了

十六. 如果看不懂,或者需要添加附件和人机验证功能,TG和其他邮箱转发,建议看看原文教程

结束语录:

总的来说,这个还是相当实用的,能在如今这年头搭建一个属于自己的邮箱系统,真的有一种“科技掌握在自己手里”的成就感。更关键的是——全程免费、无需服务器、可完全自定义域名,这一点简直太香了。

折腾的过程虽然略显繁琐,但当你看到那个熟悉的“收件箱”页面出现在自己域名下的那一刻,一切都值了。无论是作为个人项目、团队邮箱,还是单纯想体验自建服务的乐趣,这个项目都值得一试。

下载地址:https://wwwm.lanzn.com/b00hr8p0fe

密码:ezi2

补充:

后续发现在ios14系统以下,均无法正常加载主页面,一直转圈圈。安卓和pc端均正常访问。特提供解决方案

1.要完全兼容iOS14以下系统,需使用 @vitejs/plugin-legacy插件,并加 regenerator-runtime/runtime

2.在main.js文件中,把顶层 await init() 改为 async bootstrap 包裹,兼容所有浏览器

3.build.target 不要高于 es2017,否则 legacy 插件可能无法生成完整 ES5 代码

4.需要修改的文件有package.json vite.config.js main.js

5.数据对应不一致,需要删除\mail-vue里面的lock文件,然后重新生成

以2.2版本为例,具体步骤如下:

a.修改vite.config.js文件,增加vitejs/plugin-legacy插件

vite.config.js修改的完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

import {defineConfig, loadEnv} from 'vite'
import vue from '@vitejs/plugin-vue'
import legacy from '@vitejs/plugin-legacy'
import path from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
import {VitePWA} from 'vite-plugin-pwa';

export default defineConfig(({mode}) => {
const env = loadEnv(mode, process.cwd(), 'VITE')
return {
server: {
host: true,
port: 3001,
hmr: true,
},
base: env.VITE_STATIC_URL || '/',
plugins: [vue(),
VitePWA({
injectRegister: 'script-defer',
manifest: {
name: env.VITE_PWA_NAME,
short_name: env.VITE_PWA_NAME,
background_color: '#FFFFFF',
theme_color: '#FFFFFF',
icons: [
{
src: 'mail-pwa.png',
sizes: '192x192',
type: 'image/png',
}
],
},
workbox: {
disableDevLogs: true,
globPatterns: [],
runtimeCaching: [],
navigateFallback: null,
cleanupOutdatedCaches: true,
}
}),
legacy({
targets: ['defaults', 'not IE 11', 'iOS >= 10'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
modernPolyfills: true
}),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
},
build: {
target: 'es2017',
outDir: env.VITE_OUT_DIR || 'dist',
emptyOutDir: true,
assetsInclude: ['**/*.json']
}
}
})

b. 在main.js文件,把顶层 await init() 改为 async bootstrap 包裹,兼容所有浏览器:

main.js完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import 'regenerator-runtime/runtime'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './style.css'
import { init } from '@/init/init.js'
import { createPinia } from 'pinia'
import piniaPersistedState from 'pinia-plugin-persistedstate'
import perm from '@/perm/perm.js'
import i18n from '@/i18n/index.js'

const pinia = createPinia().use(piniaPersistedState)
const app = createApp(App).use(pinia)

async function bootstrap() {
await init()
app.use(router).use(i18n).directive('perm', perm)
app.mount('#app')
}

bootstrap()

c.修改package.json,vitejs/plugin-vue的版本号,使其和vite版本号对应

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

{
"name": "mail-vue",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --mode dev",
"remote": "vite --mode remote",
"build": "vite build --mode release",
"eo": "vite build --mode eo",
"preview": "vite preview"
},
"dependencies": {
"@iconify/vue": "^4.3.0",
"@vueuse/core": "^12.0.0",
"axios": "^1.7.8",
"compressorjs": "^1.2.1",
"date-time-format-timezone": "^1.0.22",
"dayjs": "^1.11.13",
"dexie": "^4.0.11",
"echarts": "^5.6.0",
"element-plus": "^2.9.11",
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"pinia": "^3.0.2",
"pinia-plugin-persistedstate": "^4.2.0",
"regenerator-runtime": "^0.14.1",
"vue": "^3.5.13",
"vue-i18n": "^11.1.10",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-vue": "^6.0.1",
"less": "^4.2.2",
"sass": "^1.82.0",
"terser": "^5.39.0",
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.7.0",
"vite": "^7.1.5",
"vite-plugin-pwa": "^1.0.3"
}
}

d.定位到mail-vue目录下安装插件。若数据对应不一致,需要删除mail-vue目录里面的两个lock文件,然后重新生成

e.依次按照下面代码输入

1
2
3
4
5
6
7

pnpm install vite@7.1.5 --save-dev
npm install vite@7.1.5 --save-dev
npm install regenerator-runtime --save
npm install -D @vitejs/plugin-vue@6.0.1
npm install -D @vitejs/plugin-legacy@7.2.1 --legacy-peer-deps

f.对项目进行重新构建

1
2
3

npm run build

g.最后推送到仓库,在cloudflare重新部署就行了