需要使用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 驱动的自定义域名邮箱系统。接下来的工作是不断进行安全加固和功能完善。
网友回复
有没有开源的solo agent一句话描述就能开发直接运行的前后端应用源代码?
订单支付过程中部分商品库存不足如何处理?
python如何开发一个自定义域名后缀的邮箱系统及登录发送邮件管理web页面?
有没有开源的项目将图片视频声音文字转场特效编排自动生成剪映草稿json文件?
有没有摄像头捕获眼球转动操作鼠标的开源代码?
localstorage如何生成自增的键值对进行增删改查?
python有没有将python脚本与python运行环境一键打包成exe的代码?
nodejs如何执行浏览器中运行的js代码?
iframe中如何阻止其他域名网页的打开或跳转?
webrtc如何实现多人音频电话会议?