本文目录导读:

- 使用
fetchmail+procmail备份(Linux/Unix) - 使用 Python +
imaplib(跨平台方案) - 使用
curl+getmail(简单方案) - 设置定时任务(Cron)
- 使用 systemd 定时器
- 使用建议
使用 fetchmail + procmail 备份(Linux/Unix)
安装依赖
sudo apt-get install fetchmail procmail mailutils
备份脚本 backup_email.sh
#!/bin/bash
# 邮件备份脚本
# 支持 IMAP 和 POP3 协议
# 配置
BACKUP_DIR="/path/to/email_backups"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$BACKUP_DIR/backup_$DATE.log"
# 邮箱配置
EMAIL_USER="your_email@example.com"
EMAIL_PASS="your_password"
EMAIL_SERVER="imap.example.com"
EMAIL_PORT="993"
PROTOCOL="IMAP" # 或 POP3
SSL="--ssl"
# 创建备份目录
mkdir -p "$BACKUP_DIR"
cd "$BACKUP_DIR"
# 创建 fetchmail 配置
cat > .fetchmailrc << EOF
set daemon 0
set logfile "$LOG_FILE"
poll $EMAIL_SERVER
protocol $PROTOCOL
port $EMAIL_PORT
username "$EMAIL_USER"
password "$EMAIL_PASS"
$SSL
mda "/usr/bin/procmail -d %T"
EOF
chmod 600 .fetchmailrc
# 开始备份
echo "=== 开始备份邮件: $(date) ===" >> "$LOG_FILE"
fetchmail -f .fetchmailrc -v >> "$LOG_FILE" 2>&1
# 邮件格式转换(如果有新的 .eml 文件)
if ls *.eml 1> /dev/null 2>&1; then
mkdir -p "$BACKUP_DIR/mbox_$DATE"
for eml in *.eml; do
mv "$eml" "$BACKUP_DIR/mbox_$DATE/"
done
# 压缩备份
tar -czf "$BACKUP_DIR/email_backup_$DATE.tar.gz" "mbox_$DATE"
rm -rf "mbox_$DATE"
fi
# 清理旧配置
rm -f .fetchmailrc
echo "=== 备份完成: $(date) ===" >> "$LOG_FILE"
使用 Python + imaplib(跨平台方案)
安装依赖
pip install python-dotenv
备份脚本 email_backup.py
#!/usr/bin/env python3
"""
邮件备份脚本 - 支持导出为 .eml 和 .mbox 格式
"""
import imaplib
import email
import os
import json
import gzip
import logging
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.utils import parsedate_to_datetime
from dotenv import load_dotenv
import getpass
# 加载环境变量
load_dotenv()
class EmailBackup:
def __init__(self, config=None):
self.config = config or self._load_config()
self.setup_logging()
def _load_config(self):
"""从环境变量或配置文件加载邮箱设置"""
if os.path.exists('config.json'):
with open('config.json', 'r') as f:
return json.load(f)
return {
'IMAP_SERVER': os.getenv('IMAP_SERVER', 'imap.example.com'),
'IMAP_PORT': int(os.getenv('IMAP_PORT', 993)),
'EMAIL': os.getenv('EMAIL'),
'PASSWORD': os.getenv('PASSWORD'),
'BACKUP_DIR': os.getenv('BACKUP_DIR', './email_backups'),
'FOLDERS': ['INBOX', 'Sent', 'Archive'],
'BACKUP_FORMAT': 'eml' # 或 'mbox'
}
def setup_logging(self):
"""配置日志"""
backup_dir = self.config['BACKUP_DIR']
os.makedirs(backup_dir, exist_ok=True)
log_file = os.path.join(backup_dir, f'backup_{datetime.now().strftime("%Y%m%d")}.log')
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def connect(self):
"""连接到 IMAP 服务器"""
try:
self.logger.info(f"连接到 {self.config['IMAP_SERVER']}:{self.config['IMAP_PORT']}")
if self.config.get('SSL', True):
mail = imaplib.IMAP4_SSL(
self.config['IMAP_SERVER'],
self.config['IMAP_PORT']
)
else:
mail = imaplib.IMAP4(
self.config['IMAP_SERVER'],
self.config['IMAP_PORT']
)
email_addr = self.config['EMAIL'] or input("邮箱地址: ")
password = self.config['PASSWORD'] or getpass.getpass("密码: ")
mail.login(email_addr, password)
self.mail = mail
self.logger.info("连接成功")
except Exception as e:
self.logger.error(f"连接失败: {e}")
raise
def backup_folder(self, folder='INBOX'):
"""备份指定文件夹的邮件"""
try:
self.logger.info(f"备份文件夹: {folder}")
# 选择文件夹
status, messages = self.mail.select(folder)
if status != 'OK':
self.logger.warning(f"无法访问文件夹: {folder}")
return
# 获取所有邮件ID
status, message_ids = self.mail.search(None, 'ALL')
if status != 'OK':
self.logger.warning(f"没有找到邮件: {folder}")
return
message_ids = message_ids[0].split()
total = len(message_ids)
self.logger.info(f"找到 {total} 封邮件")
# 创建备份子目录
folder_dir = os.path.join(
self.config['BACKUP_DIR'],
folder.replace('/', '_'),
datetime.now().strftime("%Y%m%d")
)
os.makedirs(folder_dir, exist_ok=True)
# 备份每封邮件
for idx, msg_id in enumerate(message_ids, 1):
try:
self._backup_single_email(msg_id, folder_dir, idx)
if idx % 10 == 0:
self.logger.info(f"进度: {idx}/{total} ({idx*100/total:.1f}%)")
except Exception as e:
self.logger.error(f"备份邮件 {msg_id} 失败: {e}")
continue
self.logger.info(f"文件夹 {folder} 备份完成: {total} 封邮件")
except Exception as e:
self.logger.error(f"备份文件夹 {folder} 失败: {e}")
def _backup_single_email(self, msg_id, folder_dir, idx):
"""备份单封邮件"""
status, msg_data = self.mail.fetch(msg_id, '(RFC822)')
if status != 'OK':
raise Exception(f"获取邮件 {msg_id} 失败")
raw_email = msg_data[0][1]
email_message = email.message_from_bytes(raw_email)
# 获取邮件日期
date_str = email_message.get('Date', '')
try:
date = parsedate_to_datetime(date_str)
date_prefix = date.strftime("%Y%m")
except:
date_prefix = "nodate"
# 生成文件名
subject = email_message.get('Subject', 'no_subject')
# 清理文件名中的特殊字符
subject = "".join(c if c.isalnum() or c in (' ', '-', '_') else '_' for c in subject)[:50]
if self.config['BACKUP_FORMAT'] == 'eml':
# 保存为 .eml 文件
filename = f"{idx:05d}_{date_prefix}_{subject}.eml"
filepath = os.path.join(folder_dir, filename)
with open(filepath, 'wb') as f:
f.write(raw_email)
elif self.config['BACKUP_FORMAT'] == 'mbox':
# 添加到 mbox 文件
mbox_file = os.path.join(folder_dir, f"{date_prefix}_backup.mbox")
with open(mbox_file, 'ab') as f:
f.write(f"From {email_message.get('From', 'unknown')} {date_str}\n".encode())
f.write(raw_email)
f.write(b"\n\n")
self.logger.debug(f"备份邮件: {subject[:30]}")
def backup_all(self):
"""备份所有配置的文件夹"""
try:
self.connect()
for folder in self.config.get('FOLDERS', ['INBOX']):
self.backup_folder(folder)
# 压缩备份文件
self._compress_backup()
except Exception as e:
self.logger.error(f"备份过程出错: {e}")
finally:
try:
self.mail.logout()
except:
pass
def _compress_backup(self):
"""压缩备份文件夹"""
import shutil
import tarfile
backup_dir = self.config['BACKUP_DIR']
today = datetime.now().strftime("%Y%m%d")
archive_name = f"email_backup_{today}"
archive_path = os.path.join(backup_dir, archive_name)
# 创建 tar.gz 归档
with tarfile.open(f"{archive_path}.tar.gz", "w:gz") as tar:
tar.add(backup_dir, arcname=archive_name)
self.logger.info(f"备份已压缩: {archive_path}.tar.gz")
if __name__ == "__main__":
# 使用示例
backup = EmailBackup()
backup.backup_all()
# 也可以使用命令行参数
import sys
if len(sys.argv) > 1 and sys.argv[1] == '--incremental':
# 增量备份模式
backup.config['FOLDERS'] = ['INBOX']
backup.backup_all()
配置文件 config.json
{
"IMAP_SERVER": "imap.gmail.com",
"IMAP_PORT": 993,
"EMAIL": "your_email@gmail.com",
"PASSWORD": "your_app_password",
"BACKUP_DIR": "/path/to/email_backups",
"FOLDERS": ["INBOX", "[Gmail]/Sent Mail", "[Gmail]/All Mail"],
"BACKUP_FORMAT": "eml",
"SSL": true
}
环境变量文件 .env
IMAP_SERVER=imap.gmail.com IMAP_PORT=993 EMAIL=your_email@gmail.com PASSWORD=your_app_password BACKUP_DIR=./email_backups
使用 curl + getmail(简单方案)
安装
sudo apt-get install getmail4
配置文件 ~/.getmail/getmailrc
[retriever] type = SimpleIMAPSSLRetriever server = imap.gmail.com username = your_email@gmail.com password = your_password [destination] type = Maildir path = /path/to/backup/Maildir/ [options] verbose = 1 delete = false message_log = ~/.getmail/log
定时备份脚本 cron_backup.sh
#!/bin/bash # 备份路径 BACKUP_DIR="/path/to/email_backups" DATE=$(date +%Y%m%d) LOG_FILE="$BACKUP_DIR/backup_$DATE.log" mkdir -p "$BACKUP_DIR" echo "=== 邮件备份开始: $(date) ===" | tee -a "$LOG_FILE" # 执行 getmail 备份 getmail --rcfile=getmailrc -g "$BACKUP_DIR" | tee -a "$LOG_FILE" # 压缩备份 cd "$BACKUP_DIR" tar -czf "email_backup_$DATE.tar.gz" "$BACKUP_DIR"/* rm -rf "$BACKUP_DIR"/*/ echo "=== 备份完成: $(date) ===" | tee -a "$LOG_FILE" # 保留最近30天的备份 find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete
设置定时任务(Cron)
添加到 crontab
# 编辑 crontab crontab -e # 添加以下内容(每天凌晨2点执行) 0 2 * * * /path/to/backup_email.sh # 或者使用 Python 版本 0 2 * * * /usr/bin/python3 /path/to/email_backup.py # 每周日凌晨3点执行完整备份 0 3 * * 0 /usr/bin/python3 /path/to/email_backup.py --full # 每天执行增量备份 0 2 * * * /usr/bin/python3 /path/to/email_backup.py --incremental
使用 systemd 定时器
Systemd 服务文件 /etc/systemd/system/email-backup.service
[Unit] Description=Email Backup Service After=network.target [Service] Type=oneshot ExecStart=/usr/bin/python3 /path/to/email_backup.py User=backup_user Group=backup_group [Install] WantedBy=multi-user.target
Systemd 定时器文件 /etc/systemd/system/email-backup.timer
[Unit] Description=Email Backup Timer Requires=email-backup.service [Timer] OnCalendar=daily OnCalendar=*-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target
启用定时器
sudo systemctl enable email-backup.timer sudo systemctl start email-backup.timer
使用建议
-
安全性:
- 使用应用专用密码而非主密码
- 配置文件设置权限 600
- 考虑加密备份文件
-
存储管理:
# 定期清理旧备份 find /path/to/backups -name "*.tar.gz" -mtime +90 -delete
-
备份验证:
# 验证备份完整性 tar -tzf backup.tar.gz > /dev/null && echo "备份有效"
-
日志监控:
# 检查备份状态 tail -f /var/log/email_backup.log
选择适合您需求的方案,根据邮箱服务商的要求调整配置即可,建议先在测试环境运行,确认无误后再设置为定时任务。