1. email模块 #
email 模块是 Python 标准库中用于处理电子邮件消息的强大工具。它提供了创建、解析和操作电子邮件消息的功能,支持各种邮件标准和格式。
email 模块包含多个子模块,主要功能包括:
- 解析电子邮件消息
- 创建电子邮件消息
- 操作电子邮件消息的各个部分
- 编码和解码邮件内容
- 处理 MIME 类型
2. 主要组件 #
2.1 核心类 #
email.message.EmailMessage (Python 3.6+) #
内容讲解: EmailMessage 是Python 3.6+版本中推荐的创建和操作电子邮件的主要类。它提供了更现代、更易用的API,支持多部分内容、附件和内嵌资源。相比传统的Message类,EmailMessage具有更好的类型安全性和更清晰的接口设计。
这是创建和操作电子邮件的主要类。
# 导入必要的模块
from email.message import EmailMessage
import smtplib
# 创建邮件对象
msg = EmailMessage()
# 设置邮件头信息
msg['Subject'] = '测试邮件'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
# 设置纯文本内容
msg.set_content('这是纯文本内容')
# 添加HTML替代内容
msg.add_alternative('<html><body><h1>这是HTML内容</h1></body></html>', subtype='html')
# 连接到SMTP服务器并发送邮件
with smtplib.SMTP('smtp.example.com', 587) as smtp:
# 启用TLS加密
smtp.starttls()
# 登录到邮件服务器
smtp.login('username', 'password')
# 发送邮件
smtp.send_message(msg)2.1.1 email.message.Message (传统方式) #
内容讲解: Message 类是较旧的API,但仍然被广泛使用。它提供了更底层的控制,适合需要精确控制邮件结构的场景。虽然代码相对复杂,但兼容性更好,特别是在处理复杂的MIME结构时。
较旧的 API,但仍然可用。
# 导入必要的MIME模块
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# 创建多部分邮件对象,类型为alternative(文本和HTML替代)
msg = MIMEMultipart('alternative')
# 设置邮件头信息
msg['Subject'] = '测试邮件'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
# 创建纯文本部分
text_part = MIMEText('这是纯文本内容', 'plain')
# 将文本部分附加到邮件中
msg.attach(text_part)
# 创建HTML部分
html_part = MIMEText('<html><body><h1>这是HTML内容</h1></body></html>', 'html')
# 将HTML部分附加到邮件中
msg.attach(html_part)2.2 解析电子邮件 #
内容讲解: 解析电子邮件是从各种来源(字符串、文件、字节流)中提取邮件信息的过程。Python的email模块提供了多种解析方法,可以根据数据来源选择最合适的方法。解析后的邮件对象可以方便地访问头信息、内容和附件。
2.2.1 从字符串解析 #
# 导入email模块的解析函数
from email import message_from_string
# 定义邮件文本内容(包含头信息和正文)
email_text = """From: sender@example.com
To: recipient@example.com
Subject: 测试邮件
Content-Type: text/plain; charset="utf-8"
这是邮件内容。
"""
# 从字符串解析邮件
msg = message_from_string(email_text)
# 提取并打印邮件的各个部分
print(f"发件人: {msg['From']}")
print(f"收件人: {msg['To']}")
print(f"主题: {msg['Subject']}")
print(f"内容: {msg.get_payload()}")2.2.2 从文件解析 #
# 导入email模块的解析函数
from email import message_from_file
# 打开邮件文件并解析
with open('email.eml', 'r', encoding='utf-8') as f:
# 从文件对象解析邮件
msg = message_from_file(f)
# 这里可以处理邮件内容
print(f"邮件主题: {msg['Subject']}")
print(f"邮件内容: {msg.get_payload()}")2.2.3 从字节解析 #
# 导入email模块的解析函数
from email import message_from_bytes
# 以二进制模式打开邮件文件
with open('email.eml', 'rb') as f:
# 读取文件内容为字节
email_bytes = f.read()
# 从字节数据解析邮件
msg = message_from_bytes(email_bytes)
# 这里可以处理邮件内容
print(f"邮件主题: {msg['Subject']}")
print(f"邮件内容: {msg.get_payload()}")2.3 MIME 处理 #
内容讲解: MIME(Multipurpose Internet Mail Extensions)是互联网标准,用于扩展电子邮件的功能,支持文本、图像、音频、视频和应用程序等多媒体内容。Python的email模块提供了多种MIME类型处理器,可以创建包含各种内容类型的复杂邮件。
email 模块提供了多种 MIME 类型处理器:
# 导入各种MIME类型处理器
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
from email.mime.audio import MIMEAudio
# 创建多部分邮件对象
msg = MIMEMultipart()
# 设置邮件主题
msg['Subject'] = '带附件的邮件'
# 创建并添加文本内容部分
text_part = MIMEText('这是邮件正文', 'plain')
msg.attach(text_part)
# 创建并添加文件附件
with open('document.pdf', 'rb') as f:
# 读取PDF文件内容
pdf_content = f.read()
# 创建PDF附件对象
attachment = MIMEApplication(pdf_content, Name='document.pdf')
# 设置附件的处理方式为下载
attachment['Content-Disposition'] = 'attachment; filename="document.pdf"'
# 将附件添加到邮件中
msg.attach(attachment)
# 创建并添加图片附件
with open('image.jpg', 'rb') as f:
# 读取图片文件内容
image_content = f.read()
# 创建图片附件对象
image = MIMEImage(image_content, name='image.jpg')
# 设置图片的处理方式为下载
image['Content-Disposition'] = 'attachment; filename="image.jpg"'
# 将图片添加到邮件中
msg.attach(image)2.4 头信息处理 #
内容讲解: 邮件头信息包含了邮件的元数据,如发件人、收件人、主题、日期等。Python的email模块提供了强大的头信息处理功能,包括编码解码、格式化、解析等。正确处理头信息对于创建符合标准的邮件和解决编码问题非常重要。
# 导入头信息处理相关的模块
from email.header import Header, decode_header
from email.utils import formatdate, make_msgid, parseaddr
# 编码包含特殊字符的头信息(如中文)
subject = Header('包含中文的标题', 'utf-8').encode()
msg['Subject'] = subject
# 解码头信息(将编码后的头信息转换回可读形式)
decoded_subject = ''.join(
str(part, encoding or 'utf8') if isinstance(part, bytes) else part
for part, encoding in decode_header(msg['Subject'])
)
# 格式化当前日期为RFC标准格式
msg['Date'] = formatdate(localtime=True)
# 生成唯一的消息ID
msg['Message-ID'] = make_msgid()
# 解析邮件地址(提取姓名和邮箱地址)
name, addr = parseaddr('John Doe <john@example.com>')
print(f"姓名: {name}")
print(f"邮箱: {addr}")2.5 内容处理 #
内容讲解: 邮件内容处理是email模块的核心功能之一,包括获取邮件正文、处理多部分内容、提取附件等。这部分内容展示了如何遍历邮件的各个部分,识别内容类型,并正确处理不同格式的内容。
# 检查邮件是否为多部分邮件
if msg.is_multipart():
# 遍历邮件的所有部分
for part in msg.walk():
# 获取当前部分的内容类型
content_type = part.get_content_type()
# 获取当前部分的处理方式
content_disposition = str(part.get("Content-Disposition"))
# 跳过附件部分(不处理附件内容)
if "attachment" in content_disposition:
continue
# 处理纯文本内容
if content_type == "text/plain":
# 获取文本内容并解码
body = part.get_payload(decode=True).decode()
print(f"纯文本内容: {body}")
# 处理HTML内容
elif content_type == "text/html":
# 获取HTML内容并解码
html_body = part.get_payload(decode=True).decode()
print(f"HTML内容: {html_body}")
else:
# 处理单部分邮件
body = msg.get_payload(decode=True).decode()
print(f"邮件内容: {body}")
# 处理字符集问题
charset = msg.get_content_charset() or 'utf-8'
content = msg.get_payload(decode=True).decode(charset)
print(f"使用字符集 {charset} 解码后的内容: {content}")2.6 生成邮件字符串 #
内容讲解: 生成邮件字符串是将邮件对象转换为可发送的文本或字节格式的过程。Python的email模块提供了多种生成方法,可以根据不同的发送需求选择合适的格式。这部分内容展示了如何生成符合RFC标准的邮件格式。
# 生成完整的邮件字符串(用于文本处理)
email_string = msg.as_string()
print("邮件字符串长度:", len(email_string))
# 生成字节形式的邮件(用于网络传输)
email_bytes = msg.as_bytes()
print("邮件字节长度:", len(email_bytes))
# 使用Generator生成符合RFC标准的邮件
from email.generator import Generator
from io import StringIO
# 创建字符串IO对象
fp = StringIO()
# 创建邮件生成器
g = Generator(fp, mangle_from_=False)
# 将邮件对象写入IO对象
g.flatten(msg)
# 获取生成的邮件内容
email_content = fp.getvalue()
print("RFC标准邮件内容长度:", len(email_content))3. 实际应用示例 #
3.1 示例1:发送带附件的邮件 #
内容讲解: 这个示例展示了如何创建一个完整的邮件发送函数,包含附件处理、头信息设置和SMTP连接。这是一个实用的邮件发送工具,可以直接用于生产环境。代码包含了完整的错误处理和资源管理。
# 导入必要的模块
import smtplib
from email.message import EmailMessage
from email.utils import formatdate
import os
def send_email_with_attachment(sender, recipients, subject, body, attachment_path):
"""
发送带附件的邮件
参数:
sender: 发件人邮箱地址
recipients: 收件人邮箱地址列表
subject: 邮件主题
body: 邮件正文
attachment_path: 附件文件路径
"""
# 创建邮件对象
msg = EmailMessage()
# 设置邮件头信息
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = ', '.join(recipients)
msg['Date'] = formatdate(localtime=True)
# 设置邮件正文
msg.set_content(body)
# 检查附件文件是否存在
if os.path.exists(attachment_path):
# 读取附件文件内容
with open(attachment_path, 'rb') as f:
file_data = f.read()
# 获取文件名(不包含路径)
file_name = os.path.basename(attachment_path)
# 添加附件到邮件中
msg.add_attachment(file_data, maintype='application',
subtype='octet-stream', filename=file_name)
print(f"已添加附件: {file_name}")
else:
print(f"警告: 附件文件 {attachment_path} 不存在")
try:
# 连接到SMTP服务器
with smtplib.SMTP('smtp.example.com', 587) as server:
# 启用TLS加密
server.starttls()
# 登录到邮件服务器
server.login('username', 'password')
# 发送邮件
server.send_message(msg)
print("邮件发送成功!")
except Exception as e:
print(f"邮件发送失败: {e}")
# 使用示例(需要替换为真实的SMTP服务器信息)
if __name__ == "__main__":
# 创建测试用的附件文件
test_content = "这是一个测试文件的内容。"
with open('test_attachment.txt', 'w', encoding='utf-8') as f:
f.write(test_content)
# 发送邮件(注意:需要配置真实的SMTP服务器)
send_email_with_attachment(
'sender@example.com',
['recipient1@example.com', 'recipient2@example.com'],
'重要文件',
'请查看附件中的文件。',
'test_attachment.txt'
)3.2 示例2:解析和提取邮件信息 #
内容讲解: 这个示例展示了如何解析现有的邮件文件并提取其中的关键信息,包括头信息、正文内容和附件列表。这对于邮件分析、归档和自动化处理非常有用。代码处理了各种邮件格式和编码问题。
# 导入必要的模块
from email import message_from_file
from email.header import decode_header
import email.utils
import os
def parse_email(file_path):
"""
解析邮件文件并提取信息
参数:
file_path: 邮件文件路径
返回:
包含邮件信息的字典
"""
# 检查文件是否存在
if not os.path.exists(file_path):
print(f"错误: 邮件文件 {file_path} 不存在")
return None
# 打开邮件文件并解析
with open(file_path, 'r', encoding='utf-8') as f:
msg = message_from_file(f)
# 初始化邮件信息字典
info = {
'subject': '',
'from': '',
'to': '',
'date': None,
'attachments': [],
'text_body': '',
'html_body': ''
}
# 解析头信息
if msg['Subject']:
# 解码头信息中的特殊字符
decoded_subject = decode_header(msg['Subject'])[0][0]
info['subject'] = decoded_subject if isinstance(decoded_subject, str) else decoded_subject.decode()
# 获取发件人、收件人和日期
info['from'] = msg['From'] or '未知'
info['to'] = msg['To'] or '未知'
# 解析日期
if msg['Date']:
try:
info['date'] = email.utils.parsedate_to_datetime(msg['Date'])
except:
info['date'] = msg['Date']
# 提取邮件内容和附件
if msg.is_multipart():
# 处理多部分邮件
for part in msg.walk():
# 获取内容类型和处理方式
content_type = part.get_content_type()
content_disposition = str(part.get("Content-Disposition"))
if "attachment" in content_disposition:
# 处理附件
filename = part.get_filename()
if filename:
# 解码头信息中的文件名
decoded_filename = decode_header(filename)[0][0]
if isinstance(decoded_filename, bytes):
decoded_filename = decoded_filename.decode()
info['attachments'].append({
'filename': decoded_filename,
'content_type': content_type,
'size': len(part.get_payload(decode=True))
})
elif content_type == "text/plain":
# 处理纯文本内容
charset = part.get_content_charset() or 'utf-8'
try:
info['text_body'] = part.get_payload(decode=True).decode(charset)
except:
info['text_body'] = part.get_payload(decode=True).decode('utf-8', errors='ignore')
elif content_type == "text/html":
# 处理HTML内容
charset = part.get_content_charset() or 'utf-8'
try:
info['html_body'] = part.get_payload(decode=True).decode(charset)
except:
info['html_body'] = part.get_payload(decode=True).decode('utf-8', errors='ignore')
else:
# 处理单部分邮件
charset = msg.get_content_charset() or 'utf-8'
try:
info['text_body'] = msg.get_payload(decode=True).decode(charset)
except:
info['text_body'] = msg.get_payload(decode=True).decode('utf-8', errors='ignore')
return info
# 使用示例
if __name__ == "__main__":
# 创建测试用的邮件文件
test_email = """From: sender@example.com
To: recipient@example.com
Subject: 测试邮件
Date: Mon, 1 Jan 2024 12:00:00 +0000
Content-Type: text/plain; charset="utf-8"
这是一个测试邮件的内容。
包含中文测试。
"""
# 写入测试邮件文件
with open('test_email.eml', 'w', encoding='utf-8') as f:
f.write(test_email)
# 解析邮件
email_info = parse_email('test_email.eml')
if email_info:
# 打印解析结果
print(f"主题: {email_info['subject']}")
print(f"发件人: {email_info['from']}")
print(f"收件人: {email_info['to']}")
print(f"日期: {email_info['date']}")
print(f"正文: {email_info.get('text_body', '无正文')}")
print(f"附件数量: {len(email_info['attachments'])}")
# 清理测试文件
os.remove('test_email.eml')3.3 示例3:创建复杂的多部分邮件 #
内容讲解: 这个示例展示了如何创建包含多种内容类型的复杂邮件,包括文本、HTML、内嵌图片和附件。这种邮件结构在现代邮件客户端中能够提供丰富的用户体验,同时保持向后兼容性。代码演示了MIME多部分邮件的层次结构设计。
# 导入必要的MIME模块
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.application import MIMEApplication
import smtplib
import os
def create_complex_email():
"""
创建复杂的多部分邮件
返回:
配置好的邮件对象
"""
# 创建根消息对象,类型为mixed(混合内容)
msg = MIMEMultipart('mixed')
# 设置邮件头信息
msg['Subject'] = '复杂邮件示例'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
# 创建alternative部分(文本和HTML替代内容)
alternative = MIMEMultipart('alternative')
msg.attach(alternative)
# 创建并添加纯文本部分
text_content = '这是纯文本内容\n查看图片和附件。'
text_part = MIMEText(text_content, 'plain', 'utf-8')
alternative.attach(text_part)
# 创建并添加HTML部分
html_content = '''
<html>
<head>
<meta charset="utf-8">
<title>复杂邮件示例</title>
</head>
<body>
<h1>这是HTML内容</h1>
<p>查看图片:<img src="cid:image1" alt="内嵌图片"></p>
<p>下载附件。</p>
<hr>
<p style="color: gray; font-size: 12px;">此邮件包含多种内容类型</p>
</body>
</html>
'''
html_part = MIMEText(html_content, 'html', 'utf-8')
alternative.attach(html_part)
# 添加内嵌图片(如果图片文件存在)
image_path = 'image.jpg'
if os.path.exists(image_path):
with open(image_path, 'rb') as f:
# 读取图片内容
image_data = f.read()
# 创建图片对象
image = MIMEImage(image_data)
# 设置图片的Content-ID(用于HTML中引用)
image.add_header('Content-ID', '<image1>')
# 设置图片为内嵌显示
image.add_header('Content-Disposition', 'inline', filename='image.jpg')
# 将图片添加到邮件中
msg.attach(image)
print("已添加内嵌图片")
else:
print(f"警告: 图片文件 {image_path} 不存在")
# 添加PDF附件(如果文件存在)
pdf_path = 'document.pdf'
if os.path.exists(pdf_path):
with open(pdf_path, 'rb') as f:
# 读取PDF内容
pdf_data = f.read()
# 创建PDF附件对象
attachment = MIMEApplication(pdf_data, Name='document.pdf')
# 设置附件为下载
attachment['Content-Disposition'] = 'attachment; filename="document.pdf"'
# 将附件添加到邮件中
msg.attach(attachment)
print("已添加PDF附件")
else:
print(f"警告: PDF文件 {pdf_path} 不存在")
return msg
def send_complex_email():
"""
发送复杂邮件
"""
try:
# 创建复杂邮件
msg = create_complex_email()
# 连接到SMTP服务器并发送
with smtplib.SMTP('smtp.example.com', 587) as server:
# 启用TLS加密
server.starttls()
# 登录到邮件服务器
server.login('username', 'password')
# 发送邮件
server.sendmail(
'sender@example.com',
'recipient@example.com',
msg.as_string()
)
print("复杂邮件发送成功!")
except Exception as e:
print(f"邮件发送失败: {e}")
# 使用示例
if __name__ == "__main__":
# 创建测试用的图片文件(简单的文本文件模拟)
test_image_content = "这是模拟的图片内容"
with open('image.jpg', 'w', encoding='utf-8') as f:
f.write(test_image_content)
# 创建测试用的PDF文件(简单的文本文件模拟)
test_pdf_content = "这是模拟的PDF内容"
with open('document.pdf', 'w', encoding='utf-8') as f:
f.write(test_pdf_content)
# 创建复杂邮件(不发送,只创建)
complex_msg = create_complex_email()
# 打印邮件结构信息
print(f"邮件主题: {complex_msg['Subject']}")
print(f"邮件类型: {complex_msg.get_content_type()}")
print(f"邮件部分数量: {len(complex_msg.get_payload())}")
# 清理测试文件
os.remove('image.jpg')
os.remove('document.pdf')
print("复杂邮件创建完成!")4. 最佳实践和注意事项 #
内容讲解: 这部分内容总结了在使用Python email模块时应该遵循的重要原则和常见陷阱。遵循这些最佳实践可以确保代码的可靠性、安全性和性能,同时避免常见的编码和兼容性问题。
字符编码:始终指定正确的字符编码,特别是处理非ASCII字符时。
安全性:处理邮件附件时要小心,避免执行不受信任的代码。
性能:处理大附件时使用流式处理,避免内存问题。
错误处理:添加适当的异常处理来处理网络问题和格式错误。
RFC合规性:确保生成的邮件符合RFC标准,以提高兼容性。
5. 常见问题解决 #
内容讲解: 这部分内容提供了解决使用email模块时常见问题的具体方法。这些问题在实际开发中经常遇到,掌握这些解决方案可以大大提高开发效率,减少调试时间。
5.1 中文编码问题 #
# 导入头信息处理模块
from email.header import Header
# 正确设置中文主题
subject = Header('中文主题', 'utf-8').encode()
msg['Subject'] = subject
# 设置中文发件人姓名
from_name = Header('张三', 'utf-8').encode()
msg['From'] = f'{from_name} <sender@example.com>'
# 设置中文收件人姓名
to_name = Header('李四', 'utf-8').encode()
msg['To'] = f'{to_name} <recipient@example.com>'5.2 附件文件名乱码 #
# 导入头信息处理模块
from email.header import Header
# 正确设置中文文件名
filename = Header('中文文件.txt', 'utf-8').encode()
attachment.add_header('Content-Disposition', 'attachment', filename=filename)
# 处理包含特殊字符的文件名
import urllib.parse
safe_filename = urllib.parse.quote('包含空格和特殊字符@#$%.txt')
attachment.add_header('Content-Disposition', 'attachment', filename=safe_filename)5.3 邮件被标记为垃圾邮件 #
# 添加必要的头信息以避免被标记为垃圾邮件
from email.utils import formatdate, make_msgid
# 设置正确的日期格式
msg['Date'] = formatdate(localtime=True)
# 生成唯一的消息ID
msg['Message-ID'] = make_msgid()
# 设置邮件优先级
msg['X-Priority'] = '3'
# 添加用户代理信息
msg['User-Agent'] = 'Python Email Module'
# 设置内容类型和字符集
msg['Content-Type'] = 'text/plain; charset="utf-8"'
msg['Content-Transfer-Encoding'] = '8bit'5.4 处理大附件 #
# 使用流式处理大附件,避免内存问题
def add_large_attachment(msg, file_path, chunk_size=8192):
"""
添加大附件,使用流式处理
参数:
msg: 邮件对象
file_path: 附件文件路径
chunk_size: 每次读取的字节数
"""
from email.mime.application import MIMEApplication
# 获取文件名
filename = os.path.basename(file_path)
# 创建附件对象
attachment = MIMEApplication('', Name=filename)
attachment['Content-Disposition'] = f'attachment; filename="{filename}"'
# 流式读取文件内容
with open(file_path, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
# 将数据块添加到附件中
attachment.set_payload(attachment.get_payload() + chunk)
# 将附件添加到邮件中
msg.attach(attachment)
print(f"已添加大附件: {filename}")
# 使用示例
if __name__ == "__main__":
# 创建测试邮件
from email.message import EmailMessage
msg = EmailMessage()
msg['Subject'] = '大附件测试'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
# 创建测试文件
test_content = "测试内容" * 1000 # 创建较大的测试文件
with open('large_test_file.txt', 'w', encoding='utf-8') as f:
f.write(test_content)
# 添加大附件
add_large_attachment(msg, 'large_test_file.txt')
# 清理测试文件
os.remove('large_test_file.txt')
print("大附件处理完成!")总结 #
内容讲解: email 模块是Python标准库中处理电子邮件的强大工具,通过掌握其各种功能,你可以创建、解析和操作各种复杂的电子邮件消息。本教程涵盖了从基础概念到高级应用的各个方面,提供了完整的代码示例和最佳实践指导。
email 模块是处理电子邮件的强大工具,通过掌握其各种功能,你可以创建、解析和操作各种复杂的电子邮件消息。本教程涵盖了从基础概念到高级应用的各个方面,提供了完整的代码示例和最佳实践指导。
主要特点:
- 支持多种邮件格式和MIME类型
- 提供完整的头信息处理功能
- 支持附件和内嵌资源
- 符合RFC标准,兼容性好
- 包含丰富的编码处理功能
适用场景:
- 自动化邮件发送系统
- 邮件内容分析和处理
- 邮件格式转换和标准化
- 邮件客户端开发
- 邮件服务器集成
通过本教程的学习,你应该能够熟练使用Python的email模块来处理各种邮件相关的任务,并能够解决实际开发中遇到的各种问题。