ワンクリックで
btpanel-mail
宝塔邮局管理技能,提供邮局服务管理、域名配置、邮箱账户管理、DNS 解析配置等功能
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
宝塔邮局管理技能,提供邮局服务管理、域名配置、邮箱账户管理、DNS 解析配置等功能
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
宝塔面板AI项目建站技能,指导AI完成从项目代码创建到面板接入、Nginx配置、域名管理、SSL证书申请的完整建站流程。 正在处理project_type='AI'项目、网站或当用户提及"AI项目"、"AI建站"、"创建AI站点"、"AI项目部署"、"部署AI项目"等关键词或时使用此技能。
宝塔面板数据库管理技能,覆盖MySQL数据库的创建、配置、管理、删除等操作。 当用户需要创建数据库、删除数据库、管理数据库用户权限、配置数据库访问权限时,使用此技能。 当用户询问宝塔面板数据库管理相关问题、参数规则、错误排查时也使用此技能。
宝塔面板防火墙管理技能,覆盖系统防火墙启停、Ping协议开关、端口规则管理(添加/删除/查看)、防火墙状态查询等操作。 当用户需要管理防火墙、开放/关闭端口、配置端口规则、禁Ping/允许Ping、查看防火墙状态时,使用此技能。
宝塔面板运行环境管理技能,用于查询和安装 PHP、Java/JDK、Node.js、Go、Python、.NET 等项目运行环境的具体版本。当用户要安装语言运行环境版本、为项目准备运行环境,或需要确保 Node.js/.NET 管理器插件存在时使用此技能。
宝塔面板网站管理技能,覆盖PHP站点、HTML静态站点、反向代理站点的创建与删除操作。 当用户提及创建网站、添加站点、删除网站、PHP站点、HTML站点、静态站点、反向代理、代理转发等网站管理相关操作时,使用此技能。
宝塔面板软件商店安装技能,覆盖普通软件/插件查询、版本选择、安装任务创建、安装状态和日志查看。 当用户需要在宝塔软件商店安装非运行环境类应用,或安装运行环境管理器插件时使用此技能。
| name | btpanel_mail |
| description | 宝塔邮局管理技能,提供邮局服务管理、域名配置、邮箱账户管理、DNS 解析配置等功能 |
| author | Baota Team |
| category | |
| tags | ["mail","postfix","dovecot","email","邮局"] |
宝塔邮局(BT Mail)是基于宝塔面板的企业级邮件系统管理工具,提供完整的邮件服务器搭建、域名配置、邮箱账户管理、DNS 解析配置等功能。
![]()
本技能提供以下核心功能:
| 功能模块 | 描述 |
|---|---|
| 邮局初始化 | 一键安装和配置 Postfix、Dovecot、Rspamd 等邮件服务 |
| 域名管理 | 添加、删除、查询邮件域名 |
| 邮箱账户 | 创建、删除、批量管理邮箱账户 |
| DNS 解析 | 自动配置 MX、SPF、DKIM、DMARC 等 DNS 记录 |
| 服务监控 | 检查邮件服务运行状态 |
| 证书管理 | SSL 证书配置和自动续签 |
宝塔邮局依赖以下核心服务:
| 服务 | 端口 | 用途 |
|---|---|---|
| Postfix | 25 (SMTP) | 邮件发送和接收 |
| Dovecot | 143 (IMAP), 993 (IMAPS) | 邮件收取 |
| Rspamd | 11333 | 垃圾邮件过滤 |
| OpenDKIM | - | 邮件签名验证 |
使用本技能时,AI 必须遵循以下原则:
os.system、public.ExecShell 等直接执行系统命令)/etc/postfix/、/etc/dovecot/ 等配置文件setup_mail_sys| 接口类型 | 可用功能 | 说明 |
|---|---|---|
| 完整功能 | 所有接口 | 包括安装、初始化、自动 DNS 配置等 |
| 基础功能 | 核心接口 | 包括初始化、域名管理、邮箱管理等 |
AI: 我将为您执行以下操作:
1. 检查邮局安装状态
2. [如未安装] 安装邮局服务
3. 检查邮局初始化状态
4. [如未初始化] 初始化邮局系统
5. 检查邮局服务状态(Postfix、Dovecot、Rspamd)
6. 添加域名 example.com
7. 配置 DNS 解析记录
正在获取数据,请稍候...
[调用接口]
[展示结果]
注意:内部会自动判断可用接口,不向用户展示判断过程。
import sys
import os
import time
import json
sys.path.insert(0, '/www/server/panel')
sys.path.insert(0, '/www/server/panel/class')
os.chdir('/www/server/panel')
from mod.base import public_aap as public
# 内部函数:检查授权状态(不展示给用户)
def _check_auth():
auth_file = '/www/server/panel/data/auth_list.json'
if os.path.exists(auth_file):
try:
auth_data = json.loads(public.readFile(auth_file))
ltd = auth_data.get('ltd', 0)
current_time = int(time.time())
return ltd > current_time
except:
return False
return False
# 内部函数:根据授权选择接口(不展示给用户)
def _get_mail_interface():
if _check_auth():
from mailModel.mainModel import main as MailMain
from mailModel.manageModel import main as MailManage
return MailMain(), MailManage(), True
else:
MAIL_SYS_PLUGIN = '/www/server/panel/plugin/mail_sys/mail_sys_main.py'
if not os.path.exists(MAIL_SYS_PLUGIN):
return None, None, False
sys.path.insert(0, '/www/server/panel/plugin/mail_sys')
from mail_sys_main import mail_sys_main as MailMain
return MailMain(), None, False
# 获取接口(内部操作)
mail, manage, has_full_access = _get_mail_interface()
if not mail:
print("邮局服务不可用")
sys.exit(1)
class Args:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# 对外展示的步骤(用户可见)
print("="*60)
print("宝塔邮局部署")
print("="*60)
# 步骤 1: 检查安装状态
print("\n[步骤 1] 检查邮局安装状态...")
if has_full_access:
install_check = manage.install_status(None)
if not install_check.get('status', False):
print("正在安装邮局服务...")
manage.install_service(None)
print("安装任务已提交,请等待完成后重试")
sys.exit(0)
else:
if not os.path.exists('/www/server/panel/plugin/mail_sys/mail_sys_main.py'):
print("邮局插件未安装")
sys.exit(1)
print("✓ 邮局已安装")
# 步骤 2: 检查初始化状态
print("\n[步骤 2] 检查邮局初始化状态...")
init_check = mail.check_mail_sys(None)
if not init_check.get('status', False):
print("正在初始化邮局系统...")
args = Args(
domain='example.com',
a_record='mail.example.com',
ips='1.2.3.4'
)
result = mail.setup_mail_sys(args)
print(f"初始化完成:{result.get('msg', '')}")
else:
print("✓ 邮局已初始化")
# 步骤 3: 检查服务状态
print("\n[步骤 3] 检查服务状态...")
status = mail.get_service_status(None)
print(f"Postfix: {'✓' if status['data']['postfix'] else '✗'}")
print(f"Dovecot: {'✓' if status['data']['dovecot'] else '✗'}")
print(f"Rspamd: {'✓' if status['data']['rspamd'] else '✗'}")
result = mail.check_mail_sys(None)
# 已初始化返回
{
"status": True,
"msg": "邮局系统已经存在,重装之前请先卸载!"
}
# 未初始化返回
{
"status": False,
"msg": "之前没有安装过邮局系统,请放心安装!"
}
# 判断逻辑
if result['status']:
print("邮局已初始化")
else:
print("需要初始化邮局系统")
# 注意:mailModel 和插件版本各有自己的 setup_mail_sys 实现
# 使用时通过已选择的 mail 对象调用
class Args:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
args = Args(
domain='example.com', # 主域名
a_record='mail.example.com', # A 记录
ips='1.2.3.4' # 服务器 IP
)
result = mail.setup_mail_sys(args)
result = mail.get_service_status(None)
# 返回示例
{
"status": True,
"data": {
"postfix": True, # Postfix 状态
"dovecot": True, # Dovecot 状态
"rspamd": True, # Rspamd 状态
"opendkim": False, # OpenDKIM 状态
"change_rspamd": False
}
}
# 方法一:标准添加(需要 DNS 验证)
args = Args(
domain='example.com',
a_record='mail.example.com',
ips='1.2.3.4'
)
result = mail.add_domain(args)
# 方法二:跳过 DNS 验证(推荐)
args = Args(
domain='example.com',
a_record='mail.example.com',
ips='1.2.3.4',
mailboxes=1000, # 邮箱数量限制
mailbox_quota='1 GB', # 单个邮箱配额
quota='10 GB', # 域名总配额
rate_limit=12 # 发送频率限制
)
result = mail.add_domain_new(args)
# 单个创建
args = Args(
username='user@example.com',
full_name='User Name',
password='Password123', # 必须包含大小写字母和数字,长度≥8
quota='1 GB',
is_admin=0,
active=1
)
result = mail.add_mailbox(args)
# 批量创建
args = Args(
content=json.dumps([
"user1|user1@example.com|Password123|1|GB",
"user2|user2@example.com|Password123|1|GB"
])
)
result = mail.add_mailbox_multiple(args)
# 注意:此接口仅在完整功能下可用
args = Args(
domain='example.com',
a_record='mail.example.com'
)
result = mail.auto_create_dns_record(args)
# 自动创建以下 DNS 记录:
# - MX 记录:指向 mail.example.com
# - A 记录:mail.example.com 解析到服务器 IP
# - SPF 记录:v=spf1 a mx ~all
# - DKIM 记录:default._domainkey 签名
# - DMARC 记录:v=DMARC1;p=quarantine
result = mail.get_domain_name(None)
# 返回示例
{
"status": True,
"data": ["example.com", "test.com"]
}
args = Args(p=1, size=50)
result = mail.get_mailboxs(args)
# 返回示例
{
"status": True,
"data": [
{
"username": "user@example.com",
"full_name": "User Name",
"quota": 1073741824,
"active": 1,
"domain": "example.com"
}
],
"page": "分页 HTML"
}
# mailModel 和插件版本都支持此接口
args = Args(domain='example.com')
result = mail.delete_domain(args)
# 返回示例
{
"status": True,
"msg": "删除域成功! (example.com)"
}
# mailModel 和插件版本都支持此接口
args = Args(username='user@example.com')
result = mail.delete_mailbox(args)
# 返回示例
{
"status": True,
"msg": "删除邮箱用户成功! (user@example.com)"
}
# mailModel 和插件版本都支持此接口
args = Args(
username='user@example.com',
mail_from='user@example.com',
mail_to=['user1@example.com'],
subject='测试邮件',
content='这是一封测试邮件。',
subtype='html',
smtp_server='localhost'
)
result = mail.send_mail(args)
# 返回示例
{
"status": True,
"msg": "发送邮件成功"
}
| 接口名称 | 完整功能 | 基础功能 | 说明 |
|---|---|---|---|
install_service | ✅ | ❌ | 安装邮局服务 |
install_status | ✅ | ❌ | 检查安装状态 |
check_mail_sys | ✅ | ✅ | 检查初始化状态 |
setup_mail_sys | ✅ | ✅ | 初始化邮局系统 |
get_service_status | ✅ | ✅ | 检查服务状态 |
add_domain | ✅ | ✅ | 添加域名 |
add_domain_new | ✅ | ✅ | 添加域名(跳过 DNS 验证) |
add_mailbox | ✅ | ✅ | 创建邮箱 |
add_mailbox_multiple | ✅ | ✅ | 批量创建邮箱 |
get_domain_name | ✅ | ✅ | 查询域名列表 |
get_mailboxs | ✅ | ✅ | 查询邮箱列表 |
auto_create_dns_record | ✅ | ❌ | 自动配置 DNS |
delete_domain | ✅ | ✅ | 删除域名 |
delete_mailbox | ✅ | ✅ | 删除邮箱 |
send_mail | ✅ | ✅ | 发送邮件 |
重要提示:
#!/usr/bin/env python3
import sys
import os
import json
import time
sys.path.insert(0, '/www/server/panel')
sys.path.insert(0, '/www/server/panel/class')
os.chdir('/www/server/panel')
from mod.base import public_aap as public
# 内部函数:检查授权状态
def _check_auth():
auth_file = '/www/server/panel/data/auth_list.json'
if os.path.exists(auth_file):
try:
auth_data = json.loads(public.readFile(auth_file))
ltd = auth_data.get('ltd', 0)
current_time = int(time.time())
return ltd > current_time
except:
return False
return False
# 内部函数:根据授权选择接口
def _get_mail_interface():
if _check_auth():
from mailModel.mainModel import main as MailMain
from mailModel.manageModel import main as MailManage
return MailMain(), MailManage(), True
else:
MAIL_SYS_PLUGIN = '/www/server/panel/plugin/mail_sys/mail_sys_main.py'
if not os.path.exists(MAIL_SYS_PLUGIN):
return None, None, False
sys.path.insert(0, '/www/server/panel/plugin/mail_sys')
from mail_sys_main import mail_sys_main as MailMain
return MailMain(), None, False
print("="*60)
print("宝塔邮局部署")
print("="*60)
# 获取接口(内部操作,不展示给用户)
mail, manage, has_full_access = _get_mail_interface()
if not mail:
print("\n✗ 邮局服务不可用")
sys.exit(1)
class Args:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# 步骤 1: 检查安装状态
print("\n[步骤 1] 检查邮局安装状态...")
if has_full_access:
install_check = manage.install_status(None)
if not install_check.get('status', False):
print("正在安装邮局服务...")
install_result = manage.install_service(None)
print(f"安装结果:{install_result.get('msg', '')}")
print("请等待安装完成后重新运行")
sys.exit(0)
else:
if not os.path.exists('/www/server/panel/plugin/mail_sys/mail_sys_main.py'):
print("✗ 邮局插件未安装")
sys.exit(1)
print("✓ 邮局已安装")
# 步骤 2: 检查初始化状态
print("\n[步骤 2] 检查邮局初始化状态...")
init_check = mail.check_mail_sys(None)
if not init_check.get('status', False):
print("正在初始化邮局系统...")
args = Args(
domain='example.com',
a_record='mail.example.com',
ips='1.2.3.4'
)
result = mail.setup_mail_sys(args)
print(f"初始化完成:{result.get('msg', '')}")
else:
print("✓ 邮局已初始化")
# 步骤 3: 检查服务状态
print("\n[步骤 3] 检查服务状态...")
status = mail.get_service_status(None)
print(f"Postfix: {'✓ 运行中' if status['data']['postfix'] else '✗ 未运行'}")
print(f"Dovecot: {'✓ 运行中' if status['data']['dovecot'] else '✗ 未运行'}")
print(f"Rspamd: {'✓ 运行中' if status['data']['rspamd'] else '✗ 未运行'}")
# 步骤 4: 添加域名
print("\n[步骤 4] 添加域名...")
args = Args(
domain='example.com',
a_record='mail.example.com',
ips='1.2.3.4',
mailboxes=1000,
mailbox_quota='1 GB',
quota='10 GB',
rate_limit=12
)
result = mail.add_domain_new(args)
print(f"域名添加:{result.get('msg', '')}")
# 步骤 5: 自动配置 DNS(完整功能)
if has_full_access:
print("\n[步骤 5] 自动配置 DNS...")
args = Args(domain='example.com', a_record='mail.example.com')
result = mail.auto_create_dns_record(args)
print(f"DNS 配置:{result.get('msg', '')}")
else:
print("\n[步骤 5] 跳过 DNS 自动配置")
print(" 请手动配置 DNS 记录")
# 步骤 6: 创建管理员邮箱
print("\n[步骤 6] 创建管理员邮箱...")
args = Args(
username='admin@example.com',
full_name='Admin',
password='AdminPass123',
quota='2 GB',
is_admin=1,
active=1
)
result = mail.add_mailbox(args)
print(f"邮箱创建:{result.get('msg', '')}")
print("\n" + "="*60)
print("邮局配置完成!")
print("="*60)
#!/usr/bin/env python3
import sys
import os
import json
import time
sys.path.insert(0, '/www/server/panel')
sys.path.insert(0, '/www/server/panel/class')
os.chdir('/www/server/panel')
from mod.base import public_aap as public
# 内部函数:检查授权状态
def _check_auth():
auth_file = '/www/server/panel/data/auth_list.json'
if os.path.exists(auth_file):
try:
auth_data = json.loads(public.readFile(auth_file))
ltd = auth_data.get('ltd', 0)
current_time = int(time.time())
return ltd > current_time
except:
return False
return False
# 内部函数:根据授权选择接口
def _get_mail_interface():
if _check_auth():
from mailModel.mainModel import main as MailMain
from mailModel.manageModel import main as MailManage
return MailMain(), MailManage(), True
else:
MAIL_SYS_PLUGIN = '/www/server/panel/plugin/mail_sys/mail_sys_main.py'
if not os.path.exists(MAIL_SYS_PLUGIN):
return None, None, False
sys.path.insert(0, '/www/server/panel/plugin/mail_sys')
from mail_sys_main import mail_sys_main as MailMain
return MailMain(), None, False
mail, manage, has_full_access = _get_mail_interface()
if not mail:
print("邮局服务不可用")
sys.exit(1)
class Args:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# 检查安装状态
if has_full_access:
install_check = manage.install_status(None)
if not install_check.get('status', False):
print("邮局未安装")
sys.exit(1)
# 检查初始化状态
check_result = mail.check_mail_sys(None)
if not check_result.get('status', False):
print("邮局未初始化")
sys.exit(1)
domain = 'example.com'
count = 50
password = 'TestPass123'
print(f"开始创建 {count} 个测试邮箱...")
success = 0
fail = 0
for i in range(1, count + 1):
args = Args(
username=f'test{i}@{domain}',
full_name=f'Test User {i}',
password=password,
quota='1 GB',
is_admin=0,
active=1
)
result = mail.add_mailbox(args)
if result.get('status', False):
success += 1
else:
fail += 1
print(f"创建完成:成功 {success} 个,失败 {fail} 个")
宝塔邮局使用 SQLite 数据库存储配置,数据库文件位于:
/www/vmail/postfixadmin.db/www/vmail/postfixmaillog.db| 字段 | 类型 | 说明 |
|---|---|---|
| domain | TEXT | 域名 |
| a_record | TEXT | A 记录 |
| mailboxes | INTEGER | 邮箱数量限制 |
| mailbox_quota | INTEGER | 单个邮箱配额(字节) |
| quota | INTEGER | 域名总配额(字节) |
| rate_limit | INTEGER | 发送频率限制 |
| created | DATETIME | 创建时间 |
| 字段 | 类型 | 说明 |
|---|---|---|
| username | TEXT | 邮箱地址 |
| full_name | TEXT | 显示名称 |
| password | TEXT | 加密密码 |
| password_encode | TEXT | 可解密密码 |
| quota | INTEGER | 配额(字节) |
| domain | TEXT | 所属域名 |
| active | INTEGER | 是否启用 |
| is_admin | INTEGER | 是否管理员 |
| created | DATETIME | 创建时间 |
| modified | DATETIME | 修改时间 |
| 文件 | 路径 | 说明 |
|---|---|---|
| Postfix 主配置 | /etc/postfix/main.cf | Postfix 配置 |
| Dovecot 主配置 | /etc/dovecot/dovecot.conf | Dovecot 配置 |
| Rspamd 配置 | /etc/rspamd/ | Rspamd 配置目录 |
| 虚拟邮箱目录 | /www/vmail/ | 邮箱数据存储 |
| 邮局插件目录 | /www/server/panel/plugin/mail_sys/ | 插件文件 |
| 邮局模型目录 | /www/server/panel/class/mailModel/ | 核心代码 |
| 授权文件 | /www/server/panel/data/auth_list.json | 授权信息 |
| 安装检测文件 | /etc/postfix/sqlite_virtual_domains_maps.cf | 邮局安装标志 |
setup_mail_sys 接口在两个版本中各有实现:
| 版本 | 文件位置 | 类名 |
|---|---|---|
| 完整功能 | /www/server/panel/class/mailModel/mainModel.py | main (mailModel.mainModel) |
| 基础功能 | /www/server/panel/plugin/mail_sys/mail_sys_main.py | mail_sys_main |
使用方式:
# 通过已选择的 mail 对象调用,不要混用
result = mail.setup_mail_sys(args)
def _get_mail_interface():
"""
根据授权状态选择可用接口
此函数为内部实现,不向用户展示
"""
# 检查授权状态
auth_file = '/www/server/panel/data/auth_list.json'
has_full_access = False
if os.path.exists(auth_file):
try:
auth_data = json.loads(public.readFile(auth_file))
ltd = auth_data.get('ltd', 0)
current_time = int(time.time())
has_full_access = ltd > current_time
except:
pass
# 根据授权选择接口
if has_full_access:
from mailModel.mainModel import main as MailMain
from mailModel.manageModel import main as MailManage
return MailMain(), MailManage(), True
else:
MAIL_SYS_PLUGIN = '/www/server/panel/plugin/mail_sys/mail_sys_main.py'
if not os.path.exists(MAIL_SYS_PLUGIN):
return None, None, False
sys.path.insert(0, '/www/server/panel/plugin/mail_sys')
from mail_sys_main import mail_sys_main as MailMain
return MailMain(), None, False
# 完整功能
from mailModel.manageModel import main as MailManage
manage = MailManage()
result = manage.install_status(None)
print(f"安装状态:{result.get('status', False)}")
# 基础功能
if not os.path.exists('/www/server/panel/plugin/mail_sys/mail_sys_main.py'):
print("邮局插件未安装")
# 两个版本都使用此接口检查
result = mail.check_mail_sys(None)
if not result.get('status', False):
print("邮局未初始化,需要执行 setup_mail_sys")
# 调用初始化接口
args = Args(domain='example.com', ...)
mail.setup_mail_sys(args)
# 检查服务状态
systemctl status postfix
systemctl status dovecot
systemctl status rspamd
# 查看日志
journalctl -u postfix -f
journalctl -u dovecot -f
# 完整功能
try:
from mailModel.mainModel import main as MailMain
from mailModel.manageModel import main as MailManage
print("✓ 接口导入成功")
except Exception as e:
print(f"✗ 导入失败:{e}")
# 基础功能
MAIL_SYS_PLUGIN = '/www/server/panel/plugin/mail_sys/mail_sys_main.py'
if os.path.exists(MAIL_SYS_PLUGIN):
try:
sys.path.insert(0, '/www/server/panel/plugin/mail_sys')
from mail_sys_main import mail_sys_main as MailMain
print("✓ 接口导入成功")
except Exception as e:
print(f"✗ 导入失败:{e}")
检查 DNS 记录是否正确配置:
# 检查 MX 记录
dig MX example.com
# 检查 A 记录
dig mail.example.com
# 检查 SPF 记录
dig TXT example.com
os.system、public.ExecShell 等直接执行系统命令/etc/postfix/、/etc/dovecot/ 等配置文件check_mail_sys 检查setup_mail_sys 进行初始化