SMTP(Simple Mail Transfer Protocol)是用于发送电子邮件的协议。Python 的 smtplib 模块提供了发送邮件的功能,email 模块用于构建邮件内容。
安装与基本导入
SMTP 模块是 Python 标准库的一部分,无需额外安装:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.header import Header
from email.utils import formataddr
import os基本邮件发送
1. 发送纯文本邮件
def send_simple_email():
# 邮件服务器配置
smtp_server = "smtp.163.com" # 以163邮箱为例
smtp_port = 25 # 端口:25(普通), 465(SSL), 587(TLS)
sender_email = "your_email@163.com"
password = "your_password" # 如果是163邮箱,使用授权码而非登录密码
# 收件人
receiver_email = "receiver@example.com"
# 创建邮件内容
subject = "测试邮件主题"
body = "这是一封测试邮件的正文内容。"
# 构建邮件
message = MIMEText(body, 'plain', 'utf-8')
message['From'] = formataddr(("发件人名称", sender_email))
message['To'] = formataddr(("收件人名称", receiver_email))
message['Subject'] = Header(subject, 'utf-8')
try:
# 连接服务器并发送
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message.as_string())
print("邮件发送成功!")
except Exception as e:
print(f"邮件发送失败: {e}")
# send_simple_email()2. 不同加密方式连接
def connect_with_different_encryption():
smtp_server = "smtp.163.com"
sender_email = "your_email@163.com"
password = "your_password"
# 方式1: 普通连接(不推荐,可能被拦截)
try:
server = smtplib.SMTP(smtp_server, 25)
server.login(sender_email, password)
print("普通连接成功")
server.quit()
except Exception as e:
print(f"普通连接失败: {e}")
# 方式2: SSL加密连接
try:
server = smtplib.SMTP_SSL(smtp_server, 465)
server.login(sender_email, password)
print("SSL连接成功")
server.quit()
except Exception as e:
print(f"SSL连接失败: {e}")
# 方式3: STARTTLS加密连接
try:
server = smtplib.SMTP(smtp_server, 587)
server.starttls() # 启用加密
server.login(sender_email, password)
print("STARTTLS连接成功")
server.quit()
except Exception as e:
print(f"STARTTLS连接失败: {e}")复杂邮件发送
1. 发送HTML格式邮件
def send_html_email():
smtp_server = "smtp.163.com"
smtp_port = 465
sender_email = "your_email@163.com"
password = "your_password"
receiver_email = "receiver@example.com"
# HTML内容
subject = "HTML格式测试邮件"
html_body = """
<html>
<body>
<h1 style="color: #ff6600;">这是一封HTML邮件</h1>
<p>欢迎使用<strong>Python SMTP</strong>模块发送邮件!</p>
<ul>
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</ul>
<p><a href="https://www.python.org">访问Python官网</a></p>
</body>
</html>
"""
# 创建HTML邮件
message = MIMEText(html_body, 'html', 'utf-8')
message['From'] = formataddr(("发件人", sender_email))
message['To'] = formataddr(("收件人", receiver_email))
message['Subject'] = Header(subject, 'utf-8')
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message.as_string())
print("HTML邮件发送成功!")
except Exception as e:
print(f"HTML邮件发送失败: {e}")2. 发送带附件的邮件
def send_email_with_attachment():
smtp_server = "smtp.163.com"
smtp_port = 465
sender_email = "your_email@163.com"
password = "your_password"
receiver_email = "receiver@example.com"
# 创建多部分邮件
message = MIMEMultipart()
message['From'] = formataddr(("发件人", sender_email))
message['To'] = formataddr(("收件人", receiver_email))
message['Subject'] = Header("带附件的测试邮件", 'utf-8')
# 邮件正文
text_body = """
您好!
这是一封带有附件的测试邮件。
请查收附件中的文件。
祝好!
Python发件程序
"""
# 添加文本部分
text_part = MIMEText(text_body, 'plain', 'utf-8')
message.attach(text_part)
# 添加附件1:文本文件
attachment1 = MIMEApplication(open('example.txt', 'rb').read())
attachment1.add_header('Content-Disposition', 'attachment',
filename=Header('示例文件.txt', 'utf-8').encode())
message.attach(attachment1)
# 添加附件2:图片文件
try:
with open('image.jpg', 'rb') as f:
attachment2 = MIMEApplication(f.read())
attachment2.add_header('Content-Disposition', 'attachment',
filename=Header('图片.jpg', 'utf-8').encode())
message.attach(attachment2)
except FileNotFoundError:
print("图片文件未找到,跳过添加图片附件")
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message.as_string())
print("带附件的邮件发送成功!")
except Exception as e:
print(f"邮件发送失败: {e}")3. 发送混合内容邮件(文本+HTML)
def send_mixed_email():
smtp_server = "smtp.163.com"
smtp_port = 465
sender_email = "your_email@163.com"
password = "your_password"
receiver_email = "receiver@example.com"
# 创建多部分邮件(alternative类型)
message = MIMEMultipart('alternative')
message['From'] = formataddr(("发件人", sender_email))
message['To'] = formataddr(("收件人", receiver_email))
message['Subject'] = Header("混合内容测试邮件", 'utf-8')
# 纯文本版本(用于不支持HTML的邮件客户端)
text_body = """
这是一封测试邮件。
如果您看到这条消息,说明您的邮件客户端不支持HTML格式。
请使用支持HTML的邮件客户端查看完整内容。
"""
# HTML版本
html_body = """
<html>
<body>
<h1 style="color: #3366cc;">欢迎!</h1>
<p>这是一封<strong>HTML格式</strong>的测试邮件。</p>
<p>如果您的邮件客户端支持HTML,您将看到格式化的内容。</p>
<table border="1" style="border-collapse: collapse;">
<tr>
<th>项目</th>
<th>值</th>
</tr>
<tr>
<td>名称</td>
<td>测试数据</td>
</tr>
</table>
</body>
</html>
"""
# 添加两个版本(邮件客户端会选择支持的格式)
text_part = MIMEText(text_body, 'plain', 'utf-8')
html_part = MIMEText(html_body, 'html', 'utf-8')
message.attach(text_part)
message.attach(html_part)
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message.as_string())
print("混合内容邮件发送成功!")
except Exception as e:
print(f"邮件发送失败: {e}")高级功能
1. 批量发送邮件
def send_batch_emails():
smtp_server = "smtp.163.com"
smtp_port = 465
sender_email = "your_email@163.com"
password = "your_password"
# 收件人列表
receivers = [
{"name": "张三", "email": "zhangsan@example.com"},
{"name": "李四", "email": "lisi@example.com"},
{"name": "王五", "email": "wangwu@example.com"}
]
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender_email, password)
for receiver in receivers:
# 为每个收件人个性化邮件
subject = f"亲爱的{receiver['name']},这是一封个性化邮件"
body = f"""
尊敬的{receiver['name']}:
这是一封个性化测试邮件。
感谢您使用我们的服务!
祝好!
Python发件系统
"""
message = MIMEText(body, 'plain', 'utf-8')
message['From'] = formataddr(("系统发件人", sender_email))
message['To'] = formataddr((receiver['name'], receiver['email']))
message['Subject'] = Header(subject, 'utf-8')
server.sendmail(sender_email, receiver['email'], message.as_string())
print(f"发送给 {receiver['name']} 的邮件成功!")
# 避免发送过快被服务器限制
import time
time.sleep(1)
except Exception as e:
print(f"批量发送失败: {e}")2. 邮件发送类封装
class EmailSender:
def __init__(self, smtp_server, smtp_port, sender_email, password, use_ssl=True):
self.smtp_server = smtp_server
self.smtp_port = smtp_port
self.sender_email = sender_email
self.password = password
self.use_ssl = use_ssl
def connect(self):
"""连接邮件服务器"""
try:
if self.use_ssl:
self.server = smtplib.SMTP_SSL(self.smtp_server, self.smtp_port)
else:
self.server = smtplib.SMTP(self.smtp_server, self.smtp_port)
self.server.starttls() # 启用TLS加密
self.server.login(self.sender_email, self.password)
return True
except Exception as e:
print(f"连接失败: {e}")
return False
def send_email(self, to_email, to_name, subject, body,
html_body=None, attachments=None):
"""发送邮件"""
try:
# 创建邮件
if html_body or attachments:
message = MIMEMultipart()
if html_body:
message = MIMEMultipart('alternative')
else:
message = MIMEText(body, 'plain', 'utf-8')
message['From'] = formataddr(("系统发件人", self.sender_email))
message['To'] = formataddr((to_name, to_email))
message['Subject'] = Header(subject, 'utf-8')
# 添加正文
if html_body:
text_part = MIMEText(body, 'plain', 'utf-8')
html_part = MIMEText(html_body, 'html', 'utf-8')
message.attach(text_part)
message.attach(html_part)
elif attachments:
text_part = MIMEText(body, 'plain', 'utf-8')
message.attach(text_part)
# 添加附件
if attachments:
for attachment_path in attachments:
if os.path.exists(attachment_path):
with open(attachment_path, 'rb') as f:
attachment = MIMEApplication(f.read())
filename = os.path.basename(attachment_path)
attachment.add_header('Content-Disposition', 'attachment',
filename=Header(filename, 'utf-8').encode())
message.attach(attachment)
# 发送邮件
self.server.sendmail(self.sender_email, to_email, message.as_string())
return True
except Exception as e:
print(f"发送失败: {e}")
return False
def disconnect(self):
"""断开连接"""
if hasattr(self, 'server'):
self.server.quit()
# 使用示例
def use_email_sender():
# 创建发送器实例
sender = EmailSender(
smtp_server="smtp.163.com",
smtp_port=465,
sender_email="your_email@163.com",
password="your_password",
use_ssl=True
)
# 连接服务器
if sender.connect():
# 发送简单邮件
sender.send_email(
to_email="receiver@example.com",
to_name="收件人",
subject="测试邮件",
body="这是一封测试邮件。"
)
# 发送带HTML的邮件
sender.send_email(
to_email="receiver@example.com",
to_name="收件人",
subject="HTML测试邮件",
body="纯文本内容",
html_body="<h1>HTML内容</h1><p>这是HTML版本</p>"
)
# 断开连接
sender.disconnect()3. 常见邮箱服务器配置
# 常见邮箱服务器配置
EMAIL_CONFIGS = {
'163': {
'smtp_server': 'smtp.163.com',
'smtp_port': 465,
'use_ssl': True
},
'qq': {
'smtp_server': 'smtp.qq.com',
'smtp_port': 465,
'use_ssl': True
},
'gmail': {
'smtp_server': 'smtp.gmail.com',
'smtp_port': 587, # Gmail 使用 STARTTLS
'use_ssl': False
},
'outlook': {
'smtp_server': 'smtp.office365.com',
'smtp_port': 587,
'use_ssl': False
}
}
def get_email_config(email_address):
"""根据邮箱地址获取配置"""
if '@163.com' in email_address:
return EMAIL_CONFIGS['163']
elif '@qq.com' in email_address:
return EMAIL_CONFIGS['qq']
elif '@gmail.com' in email_address:
return EMAIL_CONFIGS['gmail']
elif '@outlook.com' in email_address or '@hotmail.com' in email_address:
return EMAIL_CONFIGS['outlook']
else:
raise ValueError("不支持的邮箱类型")错误处理与调试
def robust_email_sending():
smtp_server = "smtp.163.com"
sender_email = "your_email@163.com"
password = "your_password"
try:
# 测试连接
server = smtplib.SMTP_SSL(smtp_server, 465)
server.set_debuglevel(1) # 开启调试模式,显示通信详情
# 登录
server.login(sender_email, password)
print("登录成功")
# 发送测试邮件
message = MIMEText("测试邮件内容", 'plain', 'utf-8')
message['From'] = sender_email
message['To'] = "receiver@example.com"
message['Subject'] = "测试邮件"
server.sendmail(sender_email, "receiver@example.com", message.as_string())
print("邮件发送成功")
server.quit()
except smtplib.SMTPAuthenticationError:
print("认证失败:用户名或密码错误")
except smtplib.SMTPConnectError:
print("连接服务器失败")
except smtplib.SMTPRecipientsRefused:
print("收件人被拒绝")
except smtplib.SMTPSenderRefused:
print("发件人被拒绝")
except smtplib.SMTPDataError:
print("服务器拒绝数据")
except Exception as e:
print(f"其他错误: {e}")安全注意事项
import getpass
from configparser import ConfigParser
def secure_email_sending():
# 安全地获取密码(不显示在终端)
password = getpass.getpass("请输入邮箱密码/授权码: ")
# 或者从配置文件读取(推荐)
config = ConfigParser()
config.read('email_config.ini')
smtp_server = config.get('email', 'smtp_server')
sender_email = config.get('email', 'sender_email')
password = config.get('email', 'password') # 加密存储
# 使用环境变量(更安全)
import os
password = os.getenv('EMAIL_PASSWORD')
# 发送邮件...总结
主要优点:
- Python 标准库,无需额外安装
- 支持多种邮件格式(文本、HTML、附件等)
- 支持多种加密方式(SSL/TLS)
- 灵活的邮件构建功能
常见问题解决:
- 认证失败:检查是否使用授权码而非登录密码
- 连接超时:检查网络连接和防火墙设置
- 被拒收:检查发件人信誉和邮件内容是否被标记为垃圾邮件
最佳实践:
- 使用加密连接(SSL/TLS)
- 密码/授权码安全存储
- 添加适当的错误处理
- 避免发送垃圾邮件
- 测试不同的邮件客户端兼容性
SMTP 模块是 Python 发送邮件的标准解决方案,适用于各种邮件发送需求。
















