本地局域网邮件管理系统:从原理到实现的完整指南
本文将带你从零开始构建一个完整的局域网邮件系统,包含用户管理、邮件收发、JWT认证等核心功能。适用于企业内部、学校或家庭局域网环境。
📋 目录
- 系统概述
- 技术架构
- 数据库设计
- 后端实现
- 前端实现
- 部署指南
- 功能演示
- 安全优化
系统概述
功能特性
本邮件系统实现了以下核心功能:
✅ 用户注册与登录
✅ JWT身份认证
✅ 发送邮件
✅ 接收邮件
✅ 收件箱/发件箱管理
✅ 邮件已读/未读状态
✅ 响应式UI界面
技术选型
| 技术 | 版本 | 用途 |
|---|---|---|
| Python | 3.8+ | 后端语言 |
| Flask | 3.0.0 | Web框架 |
| SQLite | 3.x | 数据库 |
| PyJWT | 2.8.0 | JWT认证 |
| HTML5/CSS3/JS | - | 前端界面 |
技术架构
整体架构图
┌─────────────────────────────────────┐
│ 客户端层 (Browser) │
│ HTML5 + CSS3 + JavaScript │
└──────────────┬──────────────────────┘│ HTTP/HTTPS│ RESTful API
┌──────────────▼──────────────────────┐
│ 应用层 (Flask) │
│ - 路由处理 │
│ - JWT认证 │
│ - 业务逻辑 │
└──────────────┬──────────────────────┘│
┌──────────────▼──────────────────────┐
│ 数据层 (SQLite) │
│ - users 表 │
│ - emails 表 │
└─────────────────────────────────────┘
工作流程
1. 用户认证流程
用户登录 → 验证密码 → 生成JWT Token → 返回Token → 客户端存储 → 后续请求携带Token
2. 邮件发送流程
填写邮件 → 发送POST请求 → 验证Token → 插入数据库 → 返回成功响应
数据库设计
ER图
┌─────────────────┐ ┌─────────────────┐
│ users │ │ emails │
├─────────────────┤ ├─────────────────┤
│ id (PK) │◄───────┐│ id (PK) │
│ username │ ││ sender_id (FK) │
│ password │ │└─receiver_id (FK)│
│ email │ │ subject │
│ created_at │ │ content │
└─────────────────┘ │ is_read ││ created_at │└─────────────────┘
SQL建表语句
-- 用户表
CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT UNIQUE NOT NULL,password TEXT NOT NULL,email TEXT UNIQUE NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 邮件表
CREATE TABLE emails (id INTEGER PRIMARY KEY AUTOINCREMENT,sender_id INTEGER NOT NULL,receiver_id INTEGER NOT NULL,subject TEXT NOT NULL,content TEXT NOT NULL,is_read INTEGER DEFAULT 0,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY (sender_id) REFERENCES users(id),FOREIGN KEY (receiver_id) REFERENCES users(id)
);
后端实现
1. 项目结构
mail_system/
├── server.py # Flask后端
├── requirements.txt # 依赖包
├── mail_system.db # 数据库(自动生成)
└── static/└── index.html # 前端页面
2. 依赖配置 (requirements.txt)
Flask==3.0.0
flask-cors==4.0.0
PyJWT==2.8.0
3. 完整后端代码 (server.py)
"""
本地局域网邮件管理系统 - 后端服务器
"""from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import sqlite3
import hashlib
import jwt
import datetime
from functools import wrapsapp = Flask(__name__)
CORS(app)# 配置
app.config['SECRET_KEY'] = 'your-secret-key-change-in-production'
app.config['DATABASE'] = 'mail_system.db'# ============ 数据库操作 ============def init_db():"""初始化数据库"""conn = sqlite3.connect(app.config['DATABASE'])cursor = conn.cursor()# 创建用户表cursor.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT UNIQUE NOT NULL,password TEXT NOT NULL,email TEXT UNIQUE NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')# 创建邮件表cursor.execute('''CREATE TABLE IF NOT EXISTS emails (id INTEGER PRIMARY KEY AUTOINCREMENT,sender_id INTEGER NOT NULL,receiver_id INTEGER NOT NULL,subject TEXT NOT NULL,content TEXT NOT NULL,is_read INTEGER DEFAULT 0,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY (sender_id) REFERENCES users(id),FOREIGN KEY (receiver_id) REFERENCES users(id))''')conn.commit()conn.close()def get_db():"""获取数据库连接"""conn = sqlite3.connect(app.config['DATABASE'])conn.row_factory = sqlite3.Rowreturn conn# ============ 工具函数 ============def hash_password(password):"""密码哈希加密"""return hashlib.sha256(password.encode()).hexdigest()def token_required(f):"""JWT认证装饰器"""@wraps(f)def decorated(current_user_id, *args, **kwargs):token = request.headers.get('Authorization')if not token:return jsonify({'message': '缺少token'}), 401try:token = token.split(' ')[1]data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])current_user_id = data['user_id']except:return jsonify({'message': 'token无效'}), 401return f(current_user_id, *args, **kwargs)return decorated# ============ API路由 ============@app.route('/')
def index():"""首页"""return send_from_directory('static', 'index.html')@app.route('/api/register', methods=['POST'])
def register():"""用户注册"""data = request.get_json()username = data.get('username')password = data.get('password')email = data.get('email')if not all([username, password, email]):return jsonify({'message': '缺少必要参数'}), 400conn = get_db()cursor = conn.cursor()try:hashed_password = hash_password(password)cursor.execute('INSERT INTO users (username, password, email) VALUES (?, ?, ?)',(username, hashed_password, email))conn.commit()return jsonify({'message': '注册成功'}), 201except sqlite3.IntegrityError:return jsonify({'message': '用户名或邮箱已存在'}), 409finally:conn.close()@app.route('/api/login', methods=['POST'])
def login():"""用户登录"""data = request.get_json()username = data.get('username')password = data.get('password')if not all([username, password]):return jsonify({'message': '缺少用户名或密码'}), 400conn = get_db()cursor = conn.cursor()hashed_password = hash_password(password)cursor.execute('SELECT id, username, email FROM users WHERE username = ? AND password = ?',(username, hashed_password))user = cursor.fetchone()conn.close()if user:# 生成JWT tokentoken = jwt.encode({'user_id': user['id'],'username': user['username'],'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=24)}, app.config['SECRET_KEY'], algorithm='HS256')return jsonify({'message': '登录成功','token': token,'user': {'id': user['id'],'username': user['username'],'email': user['email']}}), 200else:return jsonify({'message': '用户名或密码错误'}), 401@app.route('/api/users', methods=['GET'])
@token_required
def get_users(current_user_id):"""获取用户列表"""conn = get_db()cursor = conn.cursor()cursor.execute('SELECT id, username, email FROM users WHERE id != ?', (current_user_id,))users = cursor.fetchall()conn.close()users_list = [dict(user) for user in users]return jsonify({'users': users_list}), 200@app.route('/api/emails/send', methods=['POST'])
@token_required
def send_email(current_user_id):"""发送邮件"""data = request.get_json()receiver_id = data.get('receiver_id')subject = data.get('subject')content = data.get('content')if not all([receiver_id, subject, content]):return jsonify({'message': '缺少必要参数'}), 400conn = get_db()cursor = conn.cursor()try:cursor.execute('INSERT INTO emails (sender_id, receiver_id, subject, content) VALUES (?, ?, ?, ?)',(current_user_id, receiver_id, subject, content))conn.commit()return jsonify({'message': '邮件发送成功'}), 201except Exception as e:return jsonify({'message': f'发送失败: {str(e)}'}), 500finally:conn.close()@app.route('/api/emails/inbox', methods=['GET'])
@token_required
def get_inbox(current_user_id):"""获取收件箱"""conn = get_db()cursor = conn.cursor()cursor.execute('''SELECT e.id, e.subject, e.content, e.is_read, e.created_at,u.username as sender_name, u.email as sender_emailFROM emails eJOIN users u ON e.sender_id = u.idWHERE e.receiver_id = ?ORDER BY e.created_at DESC''', (current_user_id,))emails = cursor.fetchall()conn.close()emails_list = [dict(email) for email in emails]return jsonify({'emails': emails_list}), 200@app.route('/api/emails/sent', methods=['GET'])
@token_required
def get_sent(current_user_id):"""获取发件箱"""conn = get_db()cursor = conn.cursor()cursor.execute('''SELECT e.id, e.subject, e.content, e.is_read, e.created_at,u.username as receiver_name, u.email as receiver_emailFROM emails eJOIN users u ON e.receiver_id = u.idWHERE e.sender_id = ?ORDER BY e.created_at DESC''', (current_user_id,))emails = cursor.fetchall()conn.close()emails_list = [dict(email) for email in emails]return jsonify({'emails': emails_list}), 200@app.route('/api/emails/<int:email_id>/read', methods=['PUT'])
@token_required
def mark_as_read(current_user_id, email_id):"""标记为已读"""conn = get_db()cursor = conn.cursor()cursor.execute('UPDATE emails SET is_read = 1 WHERE id = ? AND receiver_id = ?',(email_id, current_user_id))conn.commit()conn.close()return jsonify({'message': '已标记为已读'}), 200@app.route('/api/emails/<int:email_id>', methods=['DELETE'])
def delete_email(current_user_id, email_id):"""删除邮件"""conn = get_db()cursor = conn.cursor()cursor.execute('DELETE FROM emails WHERE id = ? AND (sender_id = ? OR receiver_id = ?)',(email_id, current_user_id, current_user_id))conn.commit()conn.close()return jsonify({'message': '删除成功'}), 200# ============ 启动服务器 ============if __name__ == '__main__':init_db()print("=" * 50)print("本地局域网邮件系统启动成功!")print("访问地址: http://localhost:5000")print("=" * 50)app.run(host='0.0.0.0', port=5000, debug=True)
前端实现
完整前端代码 (static/index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>局域网邮件系统</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Microsoft YaHei', Arial, sans-serif;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);min-height: 100vh;display: flex;justify-content: center;align-items: center;}.container {width: 90%;max-width: 1200px;background: white;border-radius: 15px;box-shadow: 0 20px 60px rgba(0,0,0,0.3);overflow: hidden;}/* 登录注册页面 */.auth-container {max-width: 400px;padding: 40px;}.auth-container h2 {text-align: center;margin-bottom: 30px;color: #333;}.form-group {margin-bottom: 20px;}.form-group label {display: block;margin-bottom: 5px;color: #555;font-weight: bold;}.form-group input {width: 100%;padding: 12px;border: 2px solid #ddd;border-radius: 5px;font-size: 14px;}.form-group input:focus {outline: none;border-color: #667eea;}.btn {width: 100%;padding: 12px;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);color: white;border: none;border-radius: 5px;font-size: 16px;cursor: pointer;}.btn:hover {transform: translateY(-2px);}.switch-link {text-align: center;margin-top: 20px;color: #666;}.switch-link a {color: #667eea;text-decoration: none;font-weight: bold;}/* 邮件系统主界面 */.mail-app {display: none;height: 600px;}.mail-header {background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);color: white;padding: 20px;display: flex;justify-content: space-between;align-items: center;}.logout-btn {padding: 8px 20px;background: rgba(255,255,255,0.2);border: 2px solid white;color: white;border-radius: 5px;cursor: pointer;}.mail-body {display: flex;height: calc(100% - 80px);}.sidebar {width: 200px;background: #f5f5f5;padding: 20px;border-right: 1px solid #ddd;}.menu-item {padding: 12px;margin-bottom: 10px;background: white;border-radius: 5px;cursor: pointer;transition: all 0.3s;}.menu-item:hover {background: #667eea;color: white;}.menu-item.active {background: #667eea;color: white;}.content {flex: 1;padding: 20px;overflow-y: auto;}.compose-btn {width: 100%;padding: 12px;background: #28a745;color: white;border: none;border-radius: 5px;cursor: pointer;margin-bottom: 20px;}/* 邮件列表 */.email-list {display: none;}.email-list.active {display: block;}.email-item {padding: 15px;border-bottom: 1px solid #eee;cursor: pointer;}.email-item:hover {background: #f9f9f9;}.email-item.unread {background: #e3f2fd;font-weight: bold;}.email-subject {font-size: 16px;margin-bottom: 5px;color: #333;}.email-meta {font-size: 12px;color: #666;}/* 写邮件表单 */.compose-form {display: none;}.compose-form.active {display: block;}.compose-form select,.compose-form input,.compose-form textarea {width: 100%;padding: 10px;margin-bottom: 15px;border: 2px solid #ddd;border-radius: 5px;}.compose-form textarea {min-height: 200px;resize: vertical;}.alert {padding: 12px;margin-bottom: 15px;border-radius: 5px;display: none;}.alert.success {background: #d4edda;color: #155724;}.alert.error {background: #f8d7da;color: #721c24;}</style>
</head>
<body><div class="container"><!-- 登录页面 --><div id="loginPage" class="auth-container"><h2>登录邮件系统</h2><div id="loginAlert" class="alert"></div><form id="loginForm"><div class="form-group"><label>用户名</label><input type="text" id="loginUsername" required></div><div class="form-group"><label>密码</label><input type="password" id="loginPassword" required></div><button type="submit" class="btn">登录</button></form><div class="switch-link">还没有账号? <a href="#" onclick="showRegister()">立即注册</a></div></div><!-- 注册页面 --><div id="registerPage" class="auth-container" style="display: none;"><h2>注册新账号</h2><div id="registerAlert" class="alert"></div><form id="registerForm"><div class="form-group"><label>用户名</label><input type="text" id="registerUsername" required></div><div class="form-group"><label>邮箱</label><input type="email" id="registerEmail" required></div><div class="form-group"><label>密码</label><input type="password" id="registerPassword" required></div><button type="submit" class="btn">注册</button></form><div class="switch-link">已有账号? <a href="#" onclick="showLogin()">立即登录</a></div></div><!-- 邮件系统主界面 --><div id="mailApp" class="mail-app"><div class="mail-header"><h1>📧 局域网邮件系统</h1><div class="user-info"><span id="currentUser"></span><button class="logout-btn" onclick="logout()">退出</button></div></div><div class="mail-body"><div class="sidebar"><button class="compose-btn" onclick="showCompose()">✏️ 写邮件</button><div class="menu-item active" onclick="showInbox()">📥 收件箱</div><div class="menu-item" onclick="showSent()">📤 发件箱</div></div><div class="content"><div id="inboxList" class="email-list active"></div><div id="sentList" class="email-list"></div><div id="composeForm" class="compose-form"><h3>写邮件</h3><div id="composeAlert" class="alert"></div><form id="sendEmailForm"><select id="receiverId" required><option value="">选择收件人</option></select><input type="text" id="emailSubject" placeholder="主题" required><textarea id="emailContent" placeholder="邮件内容" required></textarea><button type="submit" class="btn">发送</button></form></div></div></div></div></div><script>const API_URL = 'http://localhost:5000/api';let currentToken = null;let currentUser = null;function showLogin() {document.getElementById('loginPage').style.display = 'block';document.getElementById('registerPage').style.display = 'none';}function showRegister() {document.getElementById('loginPage').style.display = 'none';document.getElementById('registerPage').style.display = 'block';}function showAlert(elementId, message, type) {const alert = document.getElementById(elementId);alert.textContent = message;alert.className = `alert ${type}`;alert.style.display = 'block';setTimeout(() => alert.style.display = 'none', 3000);}// 注册document.getElementById('registerForm').addEventListener('submit', async (e) => {e.preventDefault();const username = document.getElementById('registerUsername').value;const email = document.getElementById('registerEmail').value;const password = document.getElementById('registerPassword').value;try {const response = await fetch(`${API_URL}/register`, {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ username, email, password })});const data = await response.json();if (response.ok) {showAlert('registerAlert', '注册成功!', 'success');setTimeout(showLogin, 1500);} else {showAlert('registerAlert', data.message, 'error');}} catch (error) {showAlert('registerAlert', '网络错误', 'error');}});// 登录document.getElementById('loginForm').addEventListener('submit', async (e) => {e.preventDefault();const username = document.getElementById('loginUsername').value;const password = document.getElementById('loginPassword').value;try {const response = await fetch(`${API_URL}/login`, {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ username, password })});const data = await response.json();if (response.ok) {currentToken = data.token;currentUser = data.user;showMailApp();} else {showAlert('loginAlert', data.message, 'error');}} catch (error) {showAlert('loginAlert', '网络错误', 'error');}});function showMailApp() {document.getElementById('loginPage').style.display = 'none';document.getElementById('mailApp').style.display = 'block';document.getElementById('currentUser').textContent = currentUser.username;loadUsers();showInbox();}async function loadUsers() {const response = await fetch(`${API_URL}/users`, {headers: { 'Authorization': `Bearer ${currentToken}` }});const data = await response.json();const select = document.getElementById('receiverId');select.innerHTML = '<option value="">选择收件人</option>';data.users.forEach(user => {const option = document.createElement('option');option.value = user.id;option.textContent = `${user.username} (${user.email})`;select.appendChild(option);});}async function showInbox() {hideAll();document.getElementById('inboxList').classList.add('active');const response = await fetch(`${API_URL}/emails/inbox`, {headers: { 'Authorization': `Bearer ${currentToken}` }});const data = await response.json();displayEmails(data.emails, 'inbox');}async function showSent() {hideAll();document.getElementById('sentList').classList.add('active');const response = await fetch(`${API_URL}/emails/sent`, {headers: { 'Authorization': `Bearer ${currentToken}` }});const data = await response.json();displayEmails(data.emails, 'sent');}function displayEmails(emails, type) {const listId = type === 'inbox' ? 'inboxList' : 'sentList';const list = document.getElementById(listId);list.innerHTML = '';if (emails.length === 0) {list.innerHTML = '<p style="text-align:center;color:#999;">暂无邮件</p>';return;}emails.forEach(email => {const div = document.createElement('div');div.className = `email-item ${!email.is_read && type === 'inbox' ? 'unread' : ''}`;const name = type === 'inbox' ? email.sender_name : email.receiver_name;div.innerHTML = `<div class="email-subject">${email.subject}</div><div class="email-meta">${type === 'inbox' ? '来自' : '发送至'}: ${name} | ${new Date(email.created_at).toLocaleString('zh-CN')}</div>`;list.appendChild(div);});}function showCompose() {hideAll();document.getElementById('composeForm').classList.add('active');}document.getElementById('sendEmailForm').addEventListener('submit', async (e) => {e.preventDefault();const receiver_id = document.getElementById('receiverId').value;const subject = document.getElementById('emailSubject').value;const content = document.getElementById('emailContent').value;const response = await fetch(`${API_URL}/emails/send`, {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': `Bearer ${currentToken}`},body: JSON.stringify({ receiver_id, subject, content })});const data = await response.json();if (response.ok) {showAlert('composeAlert', '发送成功!', 'success');setTimeout(showSent, 1500);} else {showAlert('composeAlert', data.message, 'error');}});function hideAll() {document.querySelectorAll('.email-list, .compose-form').forEach(el => {el.classList.remove('active');});}function logout() {currentToken = null;currentUser = null;document.getElementById('mailApp').style.display = 'none';showLogin();}</script>
</body>
</html>
部署指南
环境准备
# 检查Python版本(需要3.8+)
python --version# 检查pip
pip --version
安装步骤
1. 创建项目目录
mkdir mail_system
cd mail_system
mkdir static
2. 创建文件
将上面的代码分别保存为:
server.py(后端代码)static/index.html(前端代码)requirements.txt(依赖配置)
3. 安装依赖
pip install -r requirements.txt# 如果速度慢,使用国内镜像
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
4. 启动服务器
python server.py
看到以下输出表示成功:
==================================================
本地局域网邮件系统启动成功!
访问地址: http://localhost:5000
==================================================
5. 访问系统
本机访问:
http://localhost:5000
局域网其他设备访问:
http://[服务器IP]:5000
查看服务器IP
Windows:
ipconfig
# 查找 IPv4 地址
Linux/Mac:
ifconfig
# 或
ip addr show
功能演示
1. 用户注册

- 打开浏览器访问
http://localhost:5000 - 点击"立即注册"
- 填写用户名、邮箱、密码
- 注册成功后自动跳转登录页
2. 用户登录
- 输入用户名和密码
- 点击"登录"按钮
- 登录成功进入邮件系统
3. 发送邮件
- 点击侧边栏"✏️ 写邮件"
- 从下拉列表选择收件人
- 输入邮件主题
- 输入邮件内容
- 点击"发送"
4. 查看邮件
收件箱:
- 显示接收到的所有邮件
- 未读邮件以蓝色背景高亮
- 点击邮件查看详情
发件箱:
- 显示已发送的所有邮件
- 查看发送历史
安全优化
1. 密码安全
当前实现(SHA-256)
def hash_password(password):return hashlib.sha256(password.encode()).hexdigest()
推荐实现(bcrypt加盐)
import bcryptdef hash_password(password):salt = bcrypt.gensalt()return bcrypt.hashpw(password.encode(), salt)def verify_password(password, hashed):return bcrypt.checkpw(password.encode(), hashed)
2. JWT安全
# 设置合理的过期时间
token = jwt.encode({'user_id': user_id,'exp': datetime.utcnow() + timedelta(hours=24)
}, SECRET_KEY)# 生产环境使用环境变量
import os
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'fallback-key')
3. SQL注入防护
# ✅ 正确: 使用参数化查询
cursor.execute('SELECT * FROM users WHERE id = ?', (user_id,))# ❌ 错误: 字符串拼接
cursor.execute(f'SELECT * FROM users WHERE id = {user_id}')
4. HTTPS配置
生产环境建议使用HTTPS:
# 使用Flask-Talisman
from flask_talisman import TalismanTalisman(app, force_https=True)
5. 防火墙配置
Windows:
控制面板 → Windows Defender防火墙 → 高级设置
→ 入站规则 → 新建规则 → 端口 → TCP 5000
Linux (ufw):
sudo ufw allow 5000/tcp
sudo ufw enable
功能扩展
1. 邮件附件
# 添加附件表
CREATE TABLE attachments (id INTEGER PRIMARY KEY,email_id INTEGER,filename TEXT,file_data BLOB,FOREIGN KEY (email_id) REFERENCES emails(id)
);
2. 邮件搜索
@app.route('/api/emails/search', methods=['GET'])
@token_required
def search_emails(current_user_id):keyword = request.args.get('q')cursor.execute('''SELECT * FROM emails WHERE (sender_id = ? OR receiver_id = ?)AND (subject LIKE ? OR content LIKE ?)''', (current_user_id, current_user_id, f'%{keyword}%', f'%{keyword}%'))
3. 实时通知(WebSocket)
from flask_socketio import SocketIO, emitsocketio = SocketIO(app)@socketio.on('connect')
def handle_connect():emit('notification', {'message': '连接成功'})
4. 富文本编辑器
<!-- 集成Quill编辑器 -->
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<div id="editor"></div>
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<script>const quill = new Quill('#editor', {theme: 'snow'});
</script>
5. 数据库索引优化
-- 提高查询性能
CREATE INDEX idx_sender ON emails(sender_id);
CREATE INDEX idx_receiver ON emails(receiver_id);
CREATE INDEX idx_created ON emails(created_at);
常见问题
Q1: 端口被占用怎么办?
A: 修改server.py中的端口号
app.run(host='0.0.0.0', port=8080, debug=True)
Q2: 无法从其他设备访问?
A: 检查以下几点:
- 防火墙是否开放端口
- 服务器IP地址是否正确
- 使用
0.0.0.0而不是127.0.0.1
Q3: Token过期怎么办?
A: 重新登录获取新Token,或实现Token刷新机制
Q4: 数据库锁定错误?
A: 使用连接池或增加超时时间
conn = sqlite3.connect(DATABASE, timeout=10)
Q5: 中文乱码?
A: 确保文件编码为UTF-8
# 在文件开头添加
# -*- coding: utf-8 -*-
性能优化
1. 分页加载
@app.route('/api/emails/inbox', methods=['GET'])
@token_required
def get_inbox(current_user_id):page = request.args.get('page', 1, type=int)per_page = 20offset = (page - 1) * per_pagecursor.execute('''SELECT * FROM emails WHERE receiver_id = ?ORDER BY created_at DESCLIMIT ? OFFSET ?''', (current_user_id, per_page, offset))
2. 缓存优化
from functools import lru_cache@lru_cache(maxsize=128)
def get_user_info(user_id):# 缓存用户信息pass
3. 数据库连接池
from DBUtils.PooledDB import PooledDBpool = PooledDB(creator=sqlite3,maxconnections=6,database=DATABASE
)
生产部署
使用Gunicorn
# 安装Gunicorn
pip install gunicorn# 启动(4个工作进程)
gunicorn -w 4 -b 0.0.0.0:5000 server:app
Docker容器化
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "server.py"]
# 构建镜像
docker build -t mail-system .# 运行容器
docker run -p 5000:5000 mail-system
Nginx反向代理
server {listen 80;server_name mail.yourdomain.com;location / {proxy_pass http://127.0.0.1:5000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}
}
总结
本文完整实现了一个本地局域网邮件管理系统,包括:
✅ 系统架构 - 前后端分离,RESTful API设计
✅ 数据库设计 - 合理的表结构和关系
✅ 安全机制 - JWT认证、密码加密、SQL注入防护
✅ 完整代码 - 可直接运行的Flask后端和HTML前端
✅ 部署指南 - 详细的安装配置步骤
✅ 扩展方案 - 附件、搜索、性能优化等
适用场景
- 🏢 企业内部邮件系统
- 🏫 学校班级通知系统
- 🏠 家庭局域网消息中心
- 📚 Web开发学习项目
技术要点
- Flask框架 - 轻量级Web开发
- SQLite数据库 - 零配置、易部署
- JWT认证 - 无状态身份验证
- RESTful API - 标准化接口设计
- 响应式设计 - 适配各种设备
参考资料
- Flask官方文档
- JWT介绍
- SQLite文档
- RESTful API设计指南
