+
33
-

回答

需要使用linux+Postfix/Dovecot+mysql+python实现:

项目蓝图 (Architecture)

操作系统: Ubuntu 22.04 LTS

MTA: Postfix

IMAP/Auth: Dovecot

数据库: MariaDB (MySQL 的一个流行分支)

管理后台: Python 3 + Django

Web 服务器: Nginx + Gunicorn

数据流:用户通过浏览器访问 Django 管理后台 -> Django 将域名/用户信息写入 MariaDB 数据库 -> Postfix 和 Dovecot 读取 MariaDB 中的信息来收发邮件和验证用户。

第一阶段:服务器基础和数据库设置

在你的服务器上,以 root 或 sudo 权限执行以下命令。

1. 安装软件包
sudo apt update
sudo apt install -y postfix postfix-mysql mariadb-server python3-pip python3-dev libmysqlclient-dev nginx curl
# 在安装 Postfix 的过程中,会有一个图形化配置界面:
# 1. 选择 'Internet Site'.
# 2. 'System mail name' 处填写你的主域名,例如 'mydomain.com'.
2. 配置 MariaDB (MySQL) 数据库
sudo mysql_secure_installation # 运行安全脚本,设置 root 密码等

# 登录数据库
sudo mysql -u root -p

# 创建数据库和用户 (在 MySQL shell 中执行)
CREATE DATABASE mailserver CHARACTER SET 'utf8mb4';
CREATE USER 'mail_admin'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD_HERE';
GRANT SELECT ON mailserver.* TO 'mail_admin'@'localhost';
FLUSH PRIVILEGES;
3. 在数据库中创建邮件系统所需的表

继续在 MySQL shell 中执行。这是我们邮件系统的核心数据结构。

USE mailserver;

-- 存放所有可用的虚拟域名
CREATE TABLE `virtual_domains` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 存放所有虚拟邮箱账户
CREATE TABLE `virtual_users` (
  `id` int(11) NOT NULL auto_increment,
  `domain_id` int(11) NOT NULL,
  `email` varchar(120) NOT NULL,
  `password` varchar(150) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
  FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 存放邮件别名,例如 postmaster@... -> admin@...
CREATE TABLE `virtual_aliases` (
  `id` int(11) NOT NULL auto_increment,
  `domain_id` int(11) NOT NULL,
  `source` varchar(100) NOT NULL,
  `destination` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 退出数据库
EXIT;

第二阶段:Python Django 管理后台开发

这是你要求的核心代码部分。我们将创建一个 Django 项目来管理上述数据库表。

1. 创建 Python 环境和 Django 项目
# 创建项目目录
mkdir /opt/mailadmin
cd /opt/mailadmin

# 创建并激活 Python 虚拟环境
python3 -m venv venv
source venv/bin/activate

# 安装必要的库
pip install django gunicorn pymysql crypt # crypt 用于生成 dovecot 密码

# 创建 Django 项目和 App
django-admin startproject mailadmin .
python manage.py startapp core
2. 配置 Django (mailadmin/settings.py)

打开 mailadmin/settings.py 文件,进行如下修改:

# mailadmin/settings.py

# ... (保留原有内容)

# 在 INSTALLED_APPS 列表中加入我们的 app
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'core', # 添加我们的 app
]

# ...

# 配置数据库连接
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mailserver',
        'USER': 'mail_admin',
        'PASSWORD': 'STRONG_PASSWORD_HERE', # 填写你设置的密码
        'HOST': 'localhost',
        'PORT': '3306',
        'OPTIONS': {
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

# ...

注意: Django 默认使用 mysqlclient,但 PyMySQL 更容易安装。在 mailadmin/__init__.py 文件中加入以下代码,让 Django 使用 PyMySQL:

# mailadmin/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
3. 创建数据模型 (core/models.py)

打开 core/models.py,写入以下代码。这些模型将与我们之前创建的数据库表一一对应。

# core/models.py
from django.db import models
from django.core.exceptions import ValidationError
import crypt

# Dovecot/Postfix 需要特定的密码格式, 例如 SHA512-CRYPT
def create_dovecot_password(plain_password):
    """Generates a password hash compatible with Dovecot's SHA512-CRYPT."""
    if not plain_password:
        return ""
    # 使用 SHA512-CRYPT 算法
    salt = crypt.mksalt(crypt.METHOD_SHA512)
    hashed_password = crypt.crypt(plain_password, salt)
    return hashed_password

class VirtualDomain(models.Model):
    name = models.CharField(max_length=50, unique=True)

    class Meta:
        db_table = 'virtual_domains' # 关键:指定表名

    def __str__(self):
        return self.name

class VirtualUser(models.Model):
    domain = models.ForeignKey(VirtualDomain, on_delete=models.CASCADE, db_column='domain_id')
    email = models.EmailField(max_length=120, unique=True)
    password = models.CharField(max_length=150)

    class Meta:
        db_table = 'virtual_users'

    def save(self, *args, **kwargs):
        # 自动生成 email 字段
        # 这是为了确保 email 的 @domain 部分和关联的 domain 匹配
        # 你可以在 admin.py 中让 username 部分可编辑
        # 这里只是一个示例,假设 email 字段是完整的

        # 关键: 在保存前,将明文密码哈希化
        # Django 的 Admin 会传递明文密码,我们需要在这里拦截并处理
        # 我们通过检查密码是否以 {CRYPT} 开头来判断它是否已经被哈希
        if not self.password.startswith('{CRYPT}'):
             self.password = '{CRYPT}' + create_dovecot_password(self.password)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.email

class VirtualAlias(models.Model):
    domain = models.ForeignKey(VirtualDomain, on_delete=models.CASCADE, db_column='domain_id')
    source = models.CharField(max_length=100) # 例如 'info'
    destination = models.EmailField(max_length=100) # 例如 'user@mydomain.com'

    class Meta:
        db_table = 'virtual_aliases'
        unique_together = ('source', 'destination')

    def __str__(self):
        return f"{self.source}@{self.domain.name} -> {self.destination}"
4. 创建 Django Admin 界面 (core/admin.py)

打开 core/admin.py,配置管理界面,让我们能方便地增删改查。

# core/admin.py
from django.contrib import admin
from .models import VirtualDomain, VirtualUser, VirtualAlias

@admin.register(VirtualDomain)
class VirtualDomainAdmin(admin.ModelAdmin):
    list_display = ('name',)

@admin.register(VirtualUser)
class VirtualUserAdmin(admin.ModelAdmin):
    list_display = ('email', 'domain')
    list_filter = ('domain',)
    # 为了安全,不显示哈希后的密码
    fields = ('domain', 'email', 'password')
    # 在新建用户时,密码字段是明文输入的
    # 在保存时,我们 models.py 中的 save() 方法会处理它

@admin.register(VirtualAlias)
class VirtualAliasAdmin(admin.ModelAdmin):
    list_display = ('source', 'destination', 'domain')
    list_filter = ('domain',)
5. 初始化 Django 应用
# 在 /opt/mailadmin 目录下
# 注意:因为我们是映射到已存在的表,所以不使用 migrate
# 如果是全新的项目,你需要运行 python manage.py makemigrations 和 migrate
python manage.py makemigrations # 这会创建迁移文件,但我们不应用它
python manage.py createsuperuser # 创建一个登录后台的管理员账户

# 测试运行
python manage.py runserver 0.0.0.0:8000

现在,你应该可以通过 http://你的服务器IP:8000/admin 访问 Django 后台,并用刚刚创建的超级用户登录。你可以尝试创建一个域名和用户了!

第三阶段:配置 Postfix 和 Dovecot

这部分是告诉 Postfix 和 Dovecot 如何去数据库里查找我们用 Django 创建的数据。

1. 为 Postfix 创建 MySQL 查询配置文件

创建以下文件,并在其中写入 SQL 查询语句:

/etc/postfix/mysql-virtual-mailbox-domains.cf:

user = mail_admin
password = STRONG_PASSWORD_HERE
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'

/etc/postfix/mysql-virtual-mailbox-maps.cf:

user = mail_admin
password = STRONG_PASSWORD_HERE
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'

/etc/postfix/mysql-virtual-alias-maps.cf:

user = mail_admin
password = STRONG_PASSWORD_HERE
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'

/etc/postfix/mysql-email2email.cf:

user = mail_admin
password = STRONG_PASSWORD_HERE
hosts = 127.0.0.1
dbname = mailserver
query = SELECT email FROM virtual_users WHERE email='%s'

设置权限:

sudo chmod o= /etc/postfix/mysql-*.cf
sudo chgrp postfix /etc/postfix/mysql-*.cf
2. 修改 Postfix 主配置 (/etc/postfix/main.cf)

使用 postconf -e "key=value" 命令修改,或者直接编辑文件。确保有以下配置:

# 使用 postconf 命令添加/修改
sudo postconf -e "virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf"
sudo postconf -e "virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf"
sudo postconf -e "virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual-alias-maps.cf, proxy:mysql:/etc/postfix/mysql-email2email.cf"
sudo postconf -e "virtual_mailbox_base = /var/vmail"
sudo postconf -e "virtual_uid_maps = static:5000"
sudo postconf -e "virtual_gid_maps = static:5000"
sudo postconf -e "smtpd_sasl_type = dovecot"
sudo postconf -e "smtpd_sasl_path = private/auth"
sudo postconf -e "smtpd_sasl_auth_enable = yes"
# ... 其他 smtpd_recipient_restrictions 等安全配置

创建一个用于存放邮件的用户和目录:

sudo groupadd -g 5000 vmail
sudo useradd -u 5000 -g vmail -s /sbin/nologin -d /var/vmail vmail
sudo mkdir /var/vmail
sudo chown vmail:vmail /var/vmail
3. 安装和配置 Dovecot
sudo apt install -y dovecot-core dovecot-imapd dovecot-lmtp dovecot-mysql

编辑 Dovecot 配置文件(主要是 /etc/dovecot/conf.d/ 目录下的文件):

/etc/dovecot/conf.d/10-auth.conf:

disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-sql.conf.ext

/etc/dovecot/conf.d/10-mail.conf:

mail_location = maildir:/var/vmail/%d/%n
# %d = domain, %n = user part of email

/etc/dovecot/conf.d/10-master.conf:

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
}

/etc/dovecot/conf.d/auth-sql.conf.ext:

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

/etc/dovecot/dovecot-sql.conf.ext:

driver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mail_admin password=STRONG_PASSWORD_HERE

# 密码查询,使用 CRYPT 方式比对
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

# 用户查询
user_query = SELECT '/var/vmail/%d/%n' as home, 5000 as uid, 5000 as gid FROM virtual_users WHERE email='%u';
4. 重启服务
sudo systemctl restart postfix
sudo systemctl restart dovecot

第四阶段:生产环境部署 Django (Nginx + Gunicorn)

1. 配置 Gunicorn
# 在 /opt/mailadmin 目录下,保持虚拟环境激活
pip install gunicorn
2. 配置 Nginx

创建 Nginx 配置文件 /etc/nginx/sites-available/mailadmin:

server {
    listen 80;
    server_name mailadmin.mydomain.com; # 你的管理域名

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /opt/mailadmin;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

启用该配置: sudo ln -s /etc/nginx/sites-available/mailadmin /etc/nginx/sites-enabled

3. 使用 Systemd 运行 Gunicorn

创建 /etc/systemd/system/gunicorn.service:

[Unit]
Description=gunicorn daemon for mailadmin
After=network.target

[Service]
User=root # 或者一个非特权用户
Group=www-data
WorkingDirectory=/opt/mailadmin
ExecStart=/opt/mailadmin/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock mailadmin.wsgi:application

[Install]
WantedBy=multi-user.target

启动并设为开机自启:bashsudo systemctl start gunicornsudo systemctl enable gunicornsudo systemctl restart nginx

如何使用

访问 http://mailadmin.mydomain.com/admin。

登录 Django 后台。

在 "Virtual domains" 中,添加你的域名,例如 mydomain.com。

在 "Virtual users" 中,添加用户,例如 contact@mydomain.com,并设置密码。

现在,这个邮箱账户就生效了!你可以使用任何邮件客户端(Thunderbird, Outlook)配置这个账户来收发邮件了。

IMAP 服务器: mail.mydomain.com (需要你正确设置 A 记录)

SMTP 服务器: mail.mydomain.com

用户名: contact@mydomain.com

密码: 你在后台设置的密码

安全: 务必配置 SSL/TLS,端口号会相应改变 (e.g., IMAPS: 993, SMTP Submission: 587)。

这是一个完整的骨架,你已经拥有了一个由 Python Django 驱动的自定义域名邮箱系统。接下来的工作是不断进行安全加固和功能完善。

网友回复

我知道答案,我要回答