本文目录导读:

我来介绍几种批量下载邮件附件的方法,从简单到复杂:
使用邮件客户端(最简单)
Outlook客户端
# 使用Python的win32com库操作Outlook
import win32com.client
import os
from datetime import datetime, timedelta
def download_outlook_attachments():
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) # 6 = Inbox
# 获取最近7天的邮件
date_filter = datetime.now() - timedelta(days=7)
for message in inbox.Items:
try:
if message.ReceivedTime >= date_filter:
# 检查是否有附件
if message.Attachments.Count > 0:
print(f"处理邮件: {message.Subject}")
# 保存附件
for attachment in message.Attachments:
save_path = os.path.join("C:\\attachments", attachment.FileName)
attachment.SaveAsFile(save_path)
print(f" 已保存: {attachment.FileName}")
except Exception as e:
print(f"处理邮件时出错: {e}")
# 运行
download_outlook_attachments()
使用IMAP协议(推荐)
Python + imaplib
import imaplib
import email
from email.header import decode_header
import os
import base64
class EmailAttachmentDownloader:
def __init__(self, imap_server, email_address, password):
self.imap_server = imap_server
self.email_address = email_address
self.password = password
self.connection = None
self.save_dir = "C:\\downloaded_attachments"
def connect(self):
"""连接到IMAP服务器"""
self.connection = imaplib.IMAP4_SSL(self.imap_server)
self.connection.login(self.email_address, self.password)
print("成功连接到邮件服务器")
def select_mailbox(self, mailbox="INBOX"):
"""选择邮箱文件夹"""
status, messages = self.connection.select(mailbox)
if status == 'OK':
print(f"已选择 {mailbox},共有 {int(messages[0])} 封邮件")
else:
print(f"选择 {mailbox} 失败")
def decode_header(self, header_value):
"""解码邮件头信息"""
if isinstance(header_value, tuple):
return header_value[0]
try:
decoded = decode_header(header_value)
subject = ''
for part, encoding in decoded:
if isinstance(part, bytes):
subject += part.decode(encoding or 'utf-8', errors='ignore')
else:
subject += part
return subject
except:
return str(header_value)
def download_attachments_from_date(self, date_str):
"""按日期下载附件
date_str: 格式如 '2024-01-01'
"""
if not os.path.exists(self.save_dir):
os.makedirs(self.save_dir)
# 搜索该日期之后的所有邮件
status, messages = self.connection.search(None, f'SINCE {date_str}')
if status != 'OK':
print("搜索邮件失败")
return
email_ids = messages[0].split()
print(f"找到 {len(email_ids)} 封邮件")
for email_id in email_ids:
try:
# 获取邮件
status, msg_data = self.connection.fetch(email_id, '(RFC822)')
if status != 'OK':
continue
# 解析邮件
msg = email.message_from_bytes(msg_data[0][1])
subject = self.decode_header(msg['Subject'])
print(f"\n处理邮件: {subject}")
# 遍历邮件部分
for part in msg.walk():
# 检查是否有附件
if part.get_content_maintype() == 'multipart':
continue
filename = part.get_filename()
if filename:
# 解码文件名
filename = self.decode_header(filename)
print(f" 找到附件: {filename}")
# 处理文件名并发问题
if os.path.exists(os.path.join(self.save_dir, filename)):
filename = f"{os.path.splitext(filename)[0]}_{email_id.decode()}{os.path.splitext(filename)[1]}"
# 保存附件
filepath = os.path.join(self.save_dir, filename)
with open(filepath, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f" 已保存到: {filepath}")
except Exception as e:
print(f"处理邮件 {email_id} 时出错: {e}")
def download_attachments_by_sender(self, sender_email):
"""按发件人下载附件"""
# 构建搜索条件
criteria = f'FROM "{sender_email}"'
status, messages = self.connection.search(None, criteria)
if status != 'OK':
print("搜索邮件失败")
return
email_ids = messages[0].split()
print(f"从 {sender_email} 找到 {len(email_ids)} 封邮件")
# 继续处理...(类似上面的方法)
self._process_emails(email_ids)
def _process_emails(self, email_ids):
"""处理邮件列表,提取附件"""
for email_id in email_ids:
status, msg_data = self.connection.fetch(email_id, '(RFC822)')
if status != 'OK':
continue
msg = email.message_from_bytes(msg_data[0][1])
subject = self.decode_header(msg['Subject'])
print(f"处理邮件: {subject}")
for part in msg.walk():
if part.get_content_maintype() == 'multipart':
continue
filename = part.get_filename()
if filename:
filename = self.decode_header(filename)
filepath = os.path.join(self.save_dir, filename)
with open(filepath, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f" 已保存: {filename}")
def close(self):
"""关闭连接"""
if self.connection:
self.connection.close()
self.connection.logout()
print("已关闭连接")
# 使用示例
if __name__ == "__main__":
# 配置信息
IMAP_SERVER = "imap.gmail.com" # 如果使用Gmail
EMAIL = "your.email@gmail.com"
PASSWORD = "your_app_password" # 建议使用应用密码
# 创建下载器实例
downloader = EmailAttachmentDownloader(IMAP_SERVER, EMAIL, PASSWORD)
try:
# 连接并选择邮箱
downloader.connect()
downloader.select_mailbox("INBOX")
# 下载指定日期后的所有附件
downloader.download_attachments_from_date("01-Apr-2024")
# 或者按发件人下载
# downloader.download_attachments_by_sender("sender@example.com")
finally:
# 关闭连接
downloader.close()
使用Poplib(POP3协议)
import poplib
import email
from email.header import decode_header
import os
def download_pop3_attachments(server, username, password, max_emails=50):
"""使用POP3下载附件"""
# 连接POP3服务器
pop_conn = poplib.POP3_SSL(server)
pop_conn.user(username)
pop_conn.pass_(password)
# 获取邮件数量
num_messages = len(pop_conn.list()[1])
print(f"邮箱中共有 {num_messages} 封邮件")
# 创建保存目录
save_dir = "C:\\pop3_downloads"
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 只处理最近的邮件
messages_to_process = min(num_messages, max_emails)
for i in range(num_messages, num_messages - messages_to_process, -1):
try:
# 获取邮件
response, lines, octets = pop_conn.retr(i)
msg_content = b'\r\n'.join(lines)
# 解析邮件
msg = email.message_from_bytes(msg_content)
# 解码主题
subject = decode_header(msg['Subject'])[0][0]
if isinstance(subject, bytes):
subject = subject.decode(errors='ignore')
print(f"\n处理邮件: {subject}")
# 检查附件
for part in msg.walk():
if part.get_content_maintype() == 'multipart':
continue
filename = part.get_filename()
if filename:
# 解码文件名
decoded_header = decode_header(filename)
filename = decoded_header[0][0] if isinstance(decoded_header[0][0], str) else decoded_header[0][0].decode(errors='ignore')
# 保存附件
filepath = os.path.join(save_dir, filename)
with open(filepath, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f" 已保存: {filename}")
except Exception as e:
print(f"处理邮件 {i} 时出错: {e}")
# 关闭连接
pop_conn.quit()
# 使用示例
# download_pop3_attachments("pop.gmail.com", "your.email@gmail.com", "your_password")
Gmail API(功能最强大)
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
import base64
import os
import json
# Gmail API 设置
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
class GmailAttachmentDownloader:
def __init__(self, credentials_file):
self.credentials_file = credentials_file
self.service = None
self.creds = None
def authenticate(self):
"""认证Gmail API"""
# 如果token.json存在,使用已经保存的凭据
if os.path.exists('token.json'):
self.creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 如果没有有效的凭据,需要进行授权
if not self.creds or not self.creds.valid:
if self.creds and self.creds.expired and self.creds.refresh_token:
self.creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
self.credentials_file, SCOPES)
self.creds = flow.run_local_server(port=0)
# 保存凭据
with open('token.json', 'w') as token:
token.write(self.creds.to_json())
self.service = build('gmail', 'v1', credentials=self.creds)
print("Gmail API连接成功")
def get_attachments_from_query(self, query):
"""按查询条件搜索邮件并下载附件"""
save_dir = "G:\\gmail_attachments"
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 搜索邮件
results = self.service.users().messages().list(
userId='me', q=query).execute()
messages = results.get('messages', [])
print(f"找到 {len(messages)} 封邮件")
for message in messages:
try:
# 获取邮件详情
msg = self.service.users().messages().get(
userId='me', id=message['id'], format='full').execute()
# 获取主题
subject = ''
for header in msg['payload']['headers']:
if header['name'] == 'Subject':
subject = header['value']
break
print(f"\n处理邮件: {subject}")
# 递归处理邮件部分
self._process_parts(msg['payload'], save_dir, msg['id'])
except Exception as e:
print(f"处理邮件出错: {e}")
def _process_parts(self, parts, save_dir, msg_id):
"""递归处理邮件内容"""
if 'parts' in parts:
# 处理子部分
for part in parts['parts']:
self._process_parts(part, save_dir, msg_id)
else:
# 检查是否有附件
filename = parts.get('filename')
if filename:
print(f" 找到附件: {filename}")
# 获取附件数据
attachment_id = parts['body'].get('attachmentId')
if attachment_id:
attachment = self.service.users().messages().attachments().get(
userId='me', messageId=msg_id, id=attachment_id).execute()
# 解码附件数据
file_data = base64.urlsafe_b64decode(attachment['data'])
# 保存文件
filepath = os.path.join(save_dir, filename)
with open(filepath, 'wb') as f:
f.write(file_data)
print(f" 已保存: {filepath}")
# 使用示例
if __name__ == "__main__":
downloader = GmailAttachmentDownloader("client_secret.json")
downloader.authenticate()
# 按条件搜索邮件
# query示例:
# "from:example@gmail.com has:attachment" - 特定发件人的附件
# "subject:财务报表 has:attachment" - 特定主题
# "after:2024/01/01 has:attachment" - 特定日期后
downloader.get_attachments_from_query("has:attachment from:example@gmail.com")
邮件转发设置
如果你不想写代码,也可以通过邮箱设置来自动处理:
Gmail设置
- 打开Gmail设置 → 转发和POP/IMAP
- 创建过滤器
- 设置转发规则
最佳实践建议
安全考虑
# 不要硬编码密码,使用环境变量
import os
EMAIL_PASSWORD = os.getenv('EMAIL_PASSWORD')
# 或者使用配置文件
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
PASSWORD = config['email']['password']
错误处理
def safe_download(fn):
"""安全下载包装器"""
def wrapper(*args, **kwargs):
max_retries = 3
for attempt in range(max_retries):
try:
return fn(*args, **kwargs)
except Exception as e:
if attempt == max_retries - 1:
raise
print(f"重试 {attempt + 1}/{max_retries}: {e}")
time.sleep(5)
return wrapper
日志记录
import logging
logging.basicConfig(
filename='attachment_downloader.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
选择哪种方法取决于你的需求:
- 快速简单:使用邮件客户端
- 自动化:使用IMAP或POP3
- 高级功能:使用Gmail API
- 大规模处理:组合使用多种方法
需要更多具体帮助吗?我可以详细解释某个方法的实现。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播