核心概念
在开始之前,你需要了解几个关键角色:

- 发件人:你的邮箱地址(
your_email@gmail.com)。 - 收件人:你要发送邮件的地址(
recipient@example.com)。 - SMTP 服务器:你的邮箱服务商提供的邮件发送服务器,你需要知道它的地址和端口。
- 授权码:非常重要! 为了安全,现在大多数邮箱服务商(如 Gmail, QQ邮箱, 163邮箱)不再允许直接使用你的登录密码进行 SMTP 认证,你需要在你邮箱的账户设置中开启“SMTP服务”或“POP3/SMTP服务”,并获取一个专用授权码(App Password),而不是你的登录密码。
第一步:准备工作 - 获取 SMTP 服务器信息
你需要从你的邮箱服务商那里获取以下信息:
| 邮箱服务商 | SMTP 服务器地址 | 端口 (SSL/TLS) | 端口 (STARTTLS) | 是否需要授权码 |
|---|---|---|---|---|
| Gmail | smtp.gmail.com |
465 |
587 |
是 |
| QQ邮箱 | smtp.qq.com |
465 |
587 |
是 |
| 163邮箱 | smtp.163.com |
465 |
587 |
是 |
| Outlook/Hotmail | smtp-mail.outlook.com |
465 |
587 |
是 |
| 企业邮箱/其他 | 请咨询你的邮件服务提供商 | - | - | - |
如何获取授权码(以 Gmail 为例):
- 登录你的 Google 账户。
- 前往 Google 账户的安全设置。
- 在“登录 Google”部分,确保开启了“两步验证”(2-Step Verification)。这是获取授权码的前提。
- 在“两步验证”下方,找到“应用密码”。
- 点击“应用密码”,选择“邮件”作为应用,选择“其他(自定义名称)”并给你的 Python 脚本起个名字("Python Mailer")。
- 系统会生成一个 16 位的字符串,这就是你的授权码,请妥善保管,只会显示一次。
第二步:发送一封纯文本邮件
这是最基础、最简单的邮件发送方式,我们将使用 smtplib 和 email.mime.text。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 1. 邮件基础信息
sender = 'your_email@gmail.com' # 你的邮箱
receiver = 'recipient@example.com' # 收件人邮箱
subject = '来自 Python 的测试邮件' # 邮件主题
# 2. 邮件正文内容
# plain 表示纯文本邮件
# 如果邮件内容包含中文,需要指定编码为 'utf-8'
message = MIMEText('你好,这是一封使用 Python 发送的测试邮件。', 'plain', 'utf-8')
message['From'] = Header(f'发件人 <{sender}>', 'utf-8') # 设置发件人,并指定编码
message['To'] = Header(f'收件人 <{receiver}>', 'utf-8') # 设置收件人
message['Subject'] = Header(subject, 'utf-8') # 设置主题
# 3. SMTP 服务器配置
smtp_server = 'smtp.gmail.com' # SMTP 服务器地址
smtp_port = 465 # SMTP 端口 (SSL)
# smtp_port = 587 # 如果使用 STARTTLS,端口是 587
# 4. 发送邮件
try:
# 使用 SSL 加密连接
# 如果端口是 587,则使用 smtplib.SMTP(smtp_server, smtp_port) 并调用 starttls()
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
# 登录邮箱
# 如果是 Gmail 或其他需要授权码的邮箱,这里使用 授权码,而不是登录密码
server.login(sender, '你的邮箱授权码')
# 发送邮件
server.sendmail(sender, [receiver], message.as_string())
print("邮件发送成功!")
except smtplib.SMTPAuthenticationError:
print("错误:认证失败,请检查邮箱地址和授权码是否正确。")
except smtplib.SMTPException as e:
print(f"邮件发送失败,错误信息: {e}")
except Exception as e:
print(f"发生未知错误: {e}")
代码解释:

MIMEText('内容', 'plain', 'utf-8'): 创建一个邮件对象。- 邮件的正文。
'plain': 邮件类型,表示纯文本,如果换成'html',HTML 邮件。'utf-8': 字符编码,强烈建议使用,特别是处理中文时。
message['From'],message['To'],message['Subject']: 设置邮件头信息,使用Header可以确保非英文字符(如中文)能被正确编码。smtplib.SMTP_SSL(smtp_server, smtp_port): 创建一个使用 SSL 加密的 SMTP 连接,端口465通常用于 SSL。server.login(sender, '授权码'): 登录邮箱。这里必须是授权码,不是密码!server.sendmail(sender, [receiver], message.as_string()): 发送邮件。as_string(): 将MIMEText对象转换成字符串格式的邮件内容。
try...except: 错误处理非常重要。SMTPAuthenticationError通常是授权码或邮箱错误导致的。
第三步:发送 HTML 邮件
发送 HTML 邮件可以让你的邮件内容更丰富,支持加粗、颜色、图片、链接等。
只需将上面的 'plain' 改成 'html',并提供 HTML 代码即可。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
sender = 'your_email@gmail.com'
receiver = 'recipient@example.com'
subject = '一封精美的 HTML 邮件'
# HTML 邮件正文
html_content = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">HTML 邮件</title>
</head>
<body>
<h1 style="color: blue;">你好!</h1>
<p>这是一封使用 <strong>Python</strong> 发送的 <font color="red">HTML</font> 邮件。</p>
<p>你可以在这里插入图片:<img src="https://www.python.org/static/community_logos/python-logo-master-v3-TM.png"></p>
<p>或者点击这个链接:<a href="https://www.python.org">访问 Python 官网</a></p>
</body>
</html>
"""
message = MIMEText(html_content, 'html', 'utf-8')
message['From'] = Header(f'发件人 <{sender}>', 'utf-8')
message['To'] = Header(f'收件人 <{receiver}>', 'utf-8')
message['Subject'] = Header(subject, 'utf-8')
# SMTP 服务器配置 (同上)
smtp_server = 'smtp.gmail.com'
smtp_port = 465
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender, '你的邮箱授权码')
server.sendmail(sender, [receiver], message.as_string())
print("HTML 邮件发送成功!")
except Exception as e:
print(f"邮件发送失败,错误信息: {e}")
第四步:发送带附件的邮件
发送附件需要使用 email.mime.multipart.MIMEMultipart 来创建一个可以包含多个部分(文本、附件)的邮件。
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.header import Header
import os # 用于获取文件名
sender = 'your_email@gmail.com'
receiver = 'recipient@example.com'
subject = '带附件的邮件'
# 1. 创建一个带附件的邮件对象
# 'mixed' 表示邮件包含多个部分,如文本和附件
message = MIMEMultipart('mixed')
message['From'] = Header(f'发件人 <{sender}>', 'utf-8')
message['To'] = Header(f'收件人 <{receiver}>', 'utf-8')
message['Subject'] = Header(subject, 'utf-8')
# 2. 添加邮件正文(纯文本或HTML)
body_part = MIMEText('请查收附件中的文件。', 'plain', 'utf-8')
message.attach(body_part)
# 3. 添加附件
# 假设你的脚本和要发送的文件在同一个目录下
file_path = 'your_attachment.txt' # 替换成你的文件路径
# 检查文件是否存在
if os.path.exists(file_path):
with open(file_path, 'rb') as f:
# 创建附件对象
# MIMEApplication 适用于二进制文件(如 pdf, zip, 图片等)
# 如果是文本文件,也可以用 MIMEText
attachment = MIMEApplication(f.read(), Name=os.path.basename(file_path))
# 设置附件的 Content-Disposition 为 attachment,这样邮件客户端会将其识别为附件
attachment['Content-Disposition'] = f'attachment; filename="{os.path.basename(file_path)}"'
message.attach(attachment)
else:
print(f"警告:附件文件 {file_path} 不存在,将不发送附件。")
# SMTP 服务器配置 (同上)
smtp_server = 'smtp.gmail.com'
smtp_port = 465
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender, '你的邮箱授权码')
server.sendmail(sender, [receiver], message.as_string())
print("带附件的邮件发送成功!")
except Exception as e:
print(f"邮件发送失败,错误信息: {e}")
第五步:同时发送给多个收件人
只需要在 server.sendmail() 方法中,将收件人列表作为一个列表传递即可。

# ... (前面的代码都一样)
# 收件人列表
receivers = ['recipient1@example.com', 'recipient2@example.com', 'recipient3@example.com']
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender, '你的邮箱授权码')
# 注意这里的 [receiver] 变成了 [receivers]
server.sendmail(sender, receivers, message.as_string())
print(f"邮件已成功发送给 {len(receivers)} 位收件人!")
except Exception as e:
print(f"邮件发送失败,错误信息: {e}")
总结与最佳实践
- 安全第一:永远不要将邮箱和授权码硬编码在脚本中,尤其是在上传到代码仓库(如 GitHub)时,应该使用环境变量、配置文件或密钥管理服务来存储敏感信息。
- 示例 (使用环境变量):
import os sender = os.environ.get('EMAIL_SENDER') password = os.environ.get('EMAIL_PASSWORD') # 存储的是授权码
- 示例 (使用环境变量):
- 使用
with语句:with smtplib.SMTP_SSL(...) as server:可以确保连接在使用完毕后自动关闭,即使发生异常。 - 错误处理:总是使用
try...except来捕获smtplib可能抛出的异常,特别是SMTPAuthenticationError和SMTPException。 - HTML 和附件:发送复杂邮件时,
MIMEMultipart是你的好朋友,邮件正文是MIMEText对象,附件可以是MIMEApplication、MIMEImage或MIMEText(针对文本附件)。 - 本地开发测试:如果你只是想在本地测试邮件发送功能,而不想用真实邮箱,可以使用一个临时的 SMTP 服务器,如
smtp4dev或MailHog,它们会拦截所有发送的邮件并显示在本地网页上,非常方便。
希望这份详细的指南能帮助你成功配置 Python 的邮件发送功能!
