first commit
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
# kiri-mail-server 部署使用指南
|
||||
|
||||
## 一、安装
|
||||
|
||||
```bash
|
||||
composer require game-worker/kiri-mail-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、创建配置文件
|
||||
|
||||
将默认配置复制到你的项目:
|
||||
|
||||
```bash
|
||||
cp vendor/game-worker/kiri-mail-server/config/mail.php config/mail.php
|
||||
```
|
||||
|
||||
编辑 `config/mail.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
return [
|
||||
'smtp' => [
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 25,
|
||||
'hostname' => 'mail.yourdomain.com', // ← 改成你的域名
|
||||
],
|
||||
'imap' => [
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 143,
|
||||
],
|
||||
'redis' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
],
|
||||
'storage' => [
|
||||
'path' => '/data/mail', // ← 邮件存储目录,确保可写
|
||||
],
|
||||
'domains' => [
|
||||
'local' => ['yourdomain.com'], // ← 你的域名
|
||||
],
|
||||
'database' => [
|
||||
'driver' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 3306,
|
||||
'database' => 'mail',
|
||||
'username' => 'root',
|
||||
'password' => 'your_mysql_password', // ← 改成你的密码
|
||||
],
|
||||
'auth' => [
|
||||
'type' => 'simple', // 快速测试用 simple,生产用 database(见第五节)
|
||||
'users' => [ // 仅 simple 模式有效
|
||||
'admin@yourdomain.com' => 'password123',
|
||||
],
|
||||
'require_auth_for_send' => true,
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、选择认证模式
|
||||
|
||||
### 模式 A:简单配置认证(测试用)
|
||||
|
||||
```php
|
||||
'auth' => [
|
||||
'type' => 'simple',
|
||||
'users' => [
|
||||
'user1@yourdomain.com' => 'mypassword',
|
||||
'user2@yourdomain.com' => 'anotherpassword',
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
### 模式 B:数据库认证(生产用)
|
||||
|
||||
在 `config/databases.php` 中添加 mail 连接:
|
||||
|
||||
```php
|
||||
// config/databases.php
|
||||
return [
|
||||
'connections' => [
|
||||
// 原有连接...
|
||||
'db' => [ /* ... */ ],
|
||||
|
||||
// 新增邮件数据库连接
|
||||
'mail' => [
|
||||
'id' => 'mail',
|
||||
'cds' => 'mysql:host=127.0.0.1;port=3306;dbname=mail',
|
||||
'username' => 'root',
|
||||
'password' => 'yourpassword',
|
||||
'database' => 'mail',
|
||||
'tablePrefix' => '',
|
||||
'driver' => 'mysql',
|
||||
'charset' => 'utf8mb4',
|
||||
'pool' => ['min' => 1, 'max' => 10],
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
执行 SQL 迁移:
|
||||
|
||||
```bash
|
||||
mysql -u root -p mail < vendor/game-worker/kiri-mail-server/migrations/001_init.sql
|
||||
```
|
||||
|
||||
`config/mail.php` 中设置:
|
||||
|
||||
```php
|
||||
'auth' => [
|
||||
'type' => 'database',
|
||||
],
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、注册进程
|
||||
|
||||
编辑 `config/servers.php`:
|
||||
|
||||
```php
|
||||
return [
|
||||
'process' => [
|
||||
\Kiri\MailServer\SmtpServerProcess::class, // SMTP 收信 :25
|
||||
\Kiri\MailServer\ImapServerProcess::class, // IMAP 读信 :143
|
||||
\Kiri\MailServer\OutboundDeliveryProcess::class, // 外发投递
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
启动服务:
|
||||
|
||||
```bash
|
||||
php kiri.php sw:server start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、注册 Webmail 路由
|
||||
|
||||
创建 `app/Controller/MailWebController.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace App\Controller;
|
||||
|
||||
use Kiri\Router\Annotate\Get;
|
||||
use Kiri\Router\Annotate\Post;
|
||||
use Kiri\Router\Base\Controller;
|
||||
use Kiri\MailServer\WebmailViews;
|
||||
use Kiri\MailServer\Controller\MailApiController;
|
||||
use Kiri\MailServer\Auth\DatabaseAuth;
|
||||
use Kiri\MailServer\Storage\MaildirStorage;
|
||||
use Kiri\MailServer\MailQueue;
|
||||
|
||||
class MailWebController extends Controller
|
||||
{
|
||||
private MailApiController $api;
|
||||
|
||||
public function init(): void
|
||||
{
|
||||
$redis = new \Redis();
|
||||
$redis->connect('127.0.0.1', 6379);
|
||||
|
||||
$storage = new MaildirStorage('/data/mail');
|
||||
$mailQueue = new MailQueue($redis);
|
||||
$auth = new DatabaseAuth();
|
||||
|
||||
$this->api = new MailApiController($auth, $storage, $mailQueue);
|
||||
}
|
||||
|
||||
#[Get('/webmail')]
|
||||
public function index(): string
|
||||
{
|
||||
return WebmailViews::loginPage();
|
||||
}
|
||||
|
||||
#[Post('/webmail/login')]
|
||||
public function login(): string
|
||||
{
|
||||
$email = $this->request->post('email');
|
||||
$password = $this->request->post('password');
|
||||
|
||||
if ($this->api->verifyCredentials($email, $password)) {
|
||||
// 生产环境应使用 Session 或 JWT
|
||||
$url = '/webmail/inbox?email=' . urlencode($email);
|
||||
return $this->response->withHeader('Location', $url)->withStatus(302);
|
||||
}
|
||||
|
||||
return WebmailViews::loginPage();
|
||||
}
|
||||
|
||||
#[Get('/webmail/inbox')]
|
||||
public function inbox(): string
|
||||
{
|
||||
$email = $_GET['email'] ?? '';
|
||||
$data = $this->api->list($email);
|
||||
return WebmailViews::inboxPage($email, $data['messages'] ?? []);
|
||||
}
|
||||
|
||||
#[Get('/webmail/read')]
|
||||
public function read(): string
|
||||
{
|
||||
$email = $_GET['email'] ?? '';
|
||||
$id = $_GET['id'] ?? '';
|
||||
$data = $this->api->read($email, $id);
|
||||
return WebmailViews::readPage($email, $data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、创建管理面板路由
|
||||
|
||||
创建 `app/Controller/MailAdminController.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace App\Controller;
|
||||
|
||||
use Kiri\Router\Annotate\Get;
|
||||
use Kiri\Router\Annotate\Post;
|
||||
use Kiri\Router\Base\Controller;
|
||||
use Kiri\MailServer\WebmailViews;
|
||||
use Kiri\MailServer\Controller\AdminApiController;
|
||||
use Kiri\MailServer\MailQueue;
|
||||
use Kiri\MailServer\Model\Database;
|
||||
|
||||
class MailAdminController extends Controller
|
||||
{
|
||||
private AdminApiController $api;
|
||||
|
||||
public function init(): void
|
||||
{
|
||||
Database::init(config('mail.database'));
|
||||
|
||||
$redis = new \Redis();
|
||||
$redis->connect('127.0.0.1', 6379);
|
||||
$mailQueue = new MailQueue($redis);
|
||||
|
||||
$this->api = new AdminApiController($mailQueue);
|
||||
}
|
||||
|
||||
#[Get('/admin')]
|
||||
public function dashboard(): string
|
||||
{
|
||||
$domains = $this->api->listDomains()['domains'] ?? [];
|
||||
$queueStats = $this->api->queueStats();
|
||||
return WebmailViews::adminDashboard($domains, $queueStats);
|
||||
}
|
||||
|
||||
#[Get('/admin/users')]
|
||||
public function users(): string
|
||||
{
|
||||
$domainId = (int)($_GET['domain_id'] ?? 0);
|
||||
$users = $this->api->listUsers($domainId)['users'] ?? [];
|
||||
return WebmailViews::adminUsers($users, "Domain #{$domainId}");
|
||||
}
|
||||
|
||||
#[Post('/api/admin/domains/create')]
|
||||
public function createDomain(): string
|
||||
{
|
||||
$result = $this->api->createDomain(
|
||||
$this->request->post('domain'),
|
||||
$this->request->post('description', ''),
|
||||
(int)$this->request->post('max_users', 100),
|
||||
(int)$this->request->post('max_quota', 0),
|
||||
);
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
#[Post('/api/admin/users/create')]
|
||||
public function createUser(): string
|
||||
{
|
||||
$result = $this->api->createUser(
|
||||
$this->request->post('email'),
|
||||
(int)$this->request->post('domain_id'),
|
||||
$this->request->post('password'),
|
||||
);
|
||||
return json_encode($result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、测试验证
|
||||
|
||||
### 测试 SMTP 收信
|
||||
|
||||
```bash
|
||||
# 连接 SMTP 服务器
|
||||
telnet localhost 25
|
||||
|
||||
# 发送测试邮件
|
||||
EHLO test
|
||||
MAIL FROM:<sender@external.com>
|
||||
RCPT TO:<admin@yourdomain.com>
|
||||
DATA
|
||||
From: sender@external.com
|
||||
To: admin@yourdomain.com
|
||||
Subject: Test Email
|
||||
|
||||
Hello, this is a test email.
|
||||
.
|
||||
QUIT
|
||||
```
|
||||
|
||||
### 发送外部邮件
|
||||
|
||||
```bash
|
||||
# 使用认证 (AUTH PLAIN)
|
||||
telnet localhost 25
|
||||
EHLO test
|
||||
AUTH PLAIN AG1haWwAMTIzNA== # base64(\0user\0pass)
|
||||
MAIL FROM:<admin@yourdomain.com>
|
||||
RCPT TO:<friend@gmail.com>
|
||||
DATA
|
||||
From: admin@yourdomain.com
|
||||
To: friend@gmail.com
|
||||
Subject: Outbound Test
|
||||
|
||||
Hello from my mail server!
|
||||
.
|
||||
QUIT
|
||||
```
|
||||
|
||||
检查队列状态:
|
||||
|
||||
```bash
|
||||
redis-cli
|
||||
> ZCARD mail:queue:outbound # 待发送数
|
||||
> ZCARD mail:queue:outbound:dead # 死信数
|
||||
```
|
||||
|
||||
### 测试 IMAP 读信
|
||||
|
||||
```bash
|
||||
telnet localhost 143
|
||||
|
||||
A001 LOGIN admin@yourdomain.com password123
|
||||
A002 SELECT INBOX
|
||||
A003 FETCH 1:* (FLAGS BODY[])
|
||||
A004 LOGOUT
|
||||
```
|
||||
|
||||
### 测试 Webmail
|
||||
|
||||
```bash
|
||||
# 浏览器访问
|
||||
open http://localhost:9501/webmail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、DNS 记录配置(生产环境必须)
|
||||
|
||||
在你的 DNS 管理后台添加:
|
||||
|
||||
| 类型 | 名称 | 值 | 说明 |
|
||||
|------|------|-----|------|
|
||||
| **A** | `mail` | `你的服务器IP` | 邮件服务器主机 |
|
||||
| **MX** | `@` | `mail.yourdomain.com` | 邮件路由,优先级 10 |
|
||||
| **TXT** | `@` | `v=spf1 mx -all` | SPF 记录 |
|
||||
| **TXT** | `mail._domainkey` | `v=DKIM1; k=rsa; p=你的公钥` | DKIM 签名(需先生成密钥) |
|
||||
|
||||
生成 DKIM 密钥:
|
||||
|
||||
```bash
|
||||
openssl genrsa -out dkim_private.pem 2048
|
||||
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem
|
||||
# 将公钥内容放入 DNS TXT 记录: mail._domainkey.yourdomain.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、检查清单
|
||||
|
||||
- [ ] `config/mail.php` 中 `hostname` 改为真实域名
|
||||
- [ ] `domains.local` 添加了真实域名
|
||||
- [ ] `storage.path` 目录存在且可写
|
||||
- [ ] Redis 服务已启动 (`redis-cli ping`)
|
||||
- [ ] MySQL 数据库已创建并迁移
|
||||
- [ ] DNS MX 记录已配置(指向 `mail.yourdomain.com`)
|
||||
- [ ] DNS SPF 记录已配置
|
||||
- [ ] 防火墙开放端口 25、143、587
|
||||
- [ ] `config/servers.php` 注册了三个进程
|
||||
Reference in New Issue
Block a user