如何写一个脚本定时备份邮件

wen 实用脚本 2

本文目录导读:

如何写一个脚本定时备份邮件

  1. 使用 fetchmail + procmail 备份(Linux/Unix)
  2. 使用 Python + imaplib(跨平台方案)
  3. 使用 curl + getmail(简单方案)
  4. 设置定时任务(Cron)
  5. 使用 systemd 定时器
  6. 使用建议

使用 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

使用建议

  1. 安全性

    • 使用应用专用密码而非主密码
    • 配置文件设置权限 600
    • 考虑加密备份文件
  2. 存储管理

    # 定期清理旧备份
    find /path/to/backups -name "*.tar.gz" -mtime +90 -delete
  3. 备份验证

    # 验证备份完整性
    tar -tzf backup.tar.gz > /dev/null && echo "备份有效"
  4. 日志监控

    # 检查备份状态
    tail -f /var/log/email_backup.log

选择适合您需求的方案,根据邮箱服务商的要求调整配置即可,建议先在测试环境运行,确认无误后再设置为定时任务。

抱歉,评论功能暂时关闭!