需要使用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 core2. 配置 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-*.cf2. 修改 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/vmail3. 安装和配置 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 gunicorn2. 配置 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 驱动的自定义域名邮箱系统。接下来的工作是不断进行安全加固和功能完善。
网友回复
如何让ai帮我自动在小红书或抖音上自动根据需求截流与潜在客户聊天拉客?
如果用go编写一个在virtualbox中启动的简单操作系统?
go如何搭建一个零信任网络?
如何用python实现一个公网代理访问软件?
如何用go实现一个公网代理访问软件?
如何用python实现一个内网穿透打洞程序,实现内网的80端口暴露到公网上可以访问?
如何用go实现一个内网穿透打洞程序,实现内网的80端口暴露到公网上可以访问?
何为Shadowsocks 代理?
python如何实现类似php的opendir目录相互隔离的fastcgi多租户虚拟空间?
nodejs如何实现类似php的opendir目录相互隔离的fastcgi多租户虚拟空间?


