邮件与 XML/JSON 处理
本教程共 70 篇 · 第 59 篇 · 更新于 2026-07-22 · 约 5 分钟阅读
59. 邮件与 XML/JSON 处理
本节目标:学会用 Python 发送邮件,掌握 XML 和 JSON 的解析与生成方法,理解什么时候该用哪种格式。
程序之间交换数据,光会 socket 还不够。邮件是最古老也最可靠的异步通信方式,XML 和 JSON 则是两种主流的数据序列化格式。这节把这三件事一次讲清楚。
SMTP 发送邮件
SMTP(Simple Mail Transfer Protocol)是发邮件的标准协议。Python 内置 smtplib 和 email 模块,不需要额外安装。
下面是一段发送纯文本邮件的完整示例,以 QQ 邮箱为例:
from smtplib import SMTP_SSL
from email.mime.text import MIMEText
from email.header import Header
smtp_server = 'smtp.qq.com'
port = 465
sender = 'your_qq@qq.com'
password = '你的授权码' # 不是邮箱密码,是 SMTP 授权码
receiver = 'friend@example.com'
msg = MIMEText('这是一封来自 Python 的测试邮件。', 'plain', 'utf-8')
msg['From'] = Header('Python机器人', 'utf-8')
msg['To'] = Header('朋友', 'utf-8')
msg['Subject'] = Header('测试邮件', 'utf-8')
with SMTP_SSL(smtp_server, port) as server:
server.login(sender, password)
server.sendmail(sender, [receiver], msg.as_string())
print("邮件已发送")
关键点:
- QQ 邮箱、网易邮箱等主流服务商都强制要求 SSL/TLS 加密,端口一般是 465 或 587。
login()需要的不是网页登录密码,而是专门的授权码。去邮箱设置里开启 SMTP 服务就能拿到。MIMEText构造邮件正文,plain表示纯文本,html表示 HTML 格式。
如果要发送带附件的邮件,需要改用 MIMEMultipart:
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
msg = MIMEMultipart()
msg['From'] = sender
msg['To'] = receiver
msg['Subject'] = '带附件的邮件'
msg.attach(MIMEText('请查收附件。', 'plain', 'utf-8'))
with open('report.pdf', 'rb') as f:
mime = MIMEBase('application', 'octet-stream')
mime.set_payload(f.read())
encoders.encode_base64(mime)
mime.add_header('Content-Disposition', 'attachment; filename="report.pdf"')
msg.attach(mime)
Warning不要把授权码硬编码在代码里。实际项目中应从环境变量或配置文件读取,避免泄露。
POP3 收取邮件
POP3(Post Office Protocol v3)用于从邮件服务器下载邮件。如果只是读取自己的邮箱,IMAP 更灵活;POP3 的特点是简单、下载后通常从服务器删除。
from poplib import POP3_SSL
from email.parser import BytesParser
server = POP3_SSL('pop.qq.com', 995)
server.user('your_qq@qq.com')
server.pass_('授权码')
msg_count, msg_size = server.stat()
print(f"共有 {msg_count} 封邮件,总大小 {msg_size} 字节")
if msg_count > 0:
resp, lines, octets = server.retr(1)
msg_content = b'\r\n'.join(lines)
msg = BytesParser().parsebytes(msg_content)
print(f"主题: {msg['Subject']}")
print(f"发件人: {msg['From']}")
server.quit()
Tip现在新项目中收邮件更推荐用
imaplib(IMAP 协议),支持文件夹管理和已读标记同步。POP3 更适合简单的「下载并清空」场景。
JSON:程序世界的通用语
JSON(JavaScript Object Notation)是现代 API 的事实标准,读写都极其简单。
Python 对象转 JSON 字符串:
import json
data = {
'name': 'Alice',
'age': 30,
'skills': ['Python', 'SQL']
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
JSON 字符串转 Python 对象:
obj = json.loads(json_str)
print(obj['name'])
直接读写文件:
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
with open('data.json', 'r', encoding='utf-8') as f:
loaded = json.load(f)
NoteJSON 只支持字符串、数字、布尔、null、数组和对象。Python 的
datetime、set、自定义类不能直接序列化,需要先转成字符串或列表。
XML:老一辈的格式
XML(eXtensible Markup Language)曾经称霸数据交换领域,现在逐渐被 JSON 取代。但配置文件、Office 文档底层、企业接口中仍大量存在,有必要会读会写。
Python 内置 xml.etree.ElementTree 模块处理 XML:
import xml.etree.ElementTree as ET
xml_str = '''<root>
<person id="1">
<name>Alice</name>
<age>30</age>
</person>
</root>'''
root = ET.fromstring(xml_str)
# 遍历
for person in root.findall('person'):
name = person.find('name').text
age = int(person.find('age').text)
pid = person.get('id')
print(f"ID={pid}, 名字={name}, 年龄={age}")
生成 XML:
root = ET.Element('catalog')
book = ET.SubElement(root, 'book', {'id': 'bk001'})
ET.SubElement(book, 'title').text = 'Python 教程'
ET.SubElement(book, 'price').text = '59.00'
tree = ET.ElementTree(root)
tree.write('catalog.xml', encoding='utf-8', xml_declaration=True)
Tip如果 XML 结构复杂或需要验证 Schema,第三方库
lxml比标准库更快更强大,支持 XPath、XSLT 等高级功能。
JSON vs XML 怎么选
| 维度 | JSON | XML |
|---|---|---|
| 可读性 | 简洁 | 标签冗余 |
| 解析速度 | 快 | 较慢 |
| 数据类型 | 有限 | 全靠字符串 |
| 注释 | 不支持 | 支持 |
| Schema 验证 | JSON Schema | DTD/XSD |
| 适用场景 | Web API、配置 | 复杂文档、遗留系统 |
新项目优先 JSON,遇到老系统或需要严格验证的场合再请 XML 出场。
小结
smtplib+email模块可以发送纯文本、HTML、带附件的邮件。json模块让 Python 对象和 JSON 字符串之间无缝转换。xml.etree.ElementTree足以应对大部分 XML 解析和生成需求。- 数据交换优先 JSON,配置或遗留接口再考虑 XML。
来源:参考了 runoob「Python3 SMTP发送邮件/JSON/XML解析」、liaoxuefeng「20. 电子邮件/16.11. XML」等,改写后所得。