Appearance
4.1 邮件自动化
在现代办公环境中,邮件仍然是最常用的沟通方式之一。无论是发送日报、通知客户,还是自动发送报告,Python都可以帮助我们实现邮件发送的自动化,提高工作效率并减少重复劳动。
本文将介绍如何使用Python实现邮件自动化,包括基础邮件发送、发送带附件的邮件、群发个性化邮件以及定时发送邮件等功能。
邮件发送库简介
在Python中,有多个强大的库可用于邮件发送:
- smtplib:Python标准库中的SMTP客户端,用于发送邮件
- email:Python标准库中的模块,用于创建和解析邮件内容
- yagmail:第三方库,简化了邮件发送流程,支持直接传入文件路径作为附件
- schedule:用于实现定时任务的第三方库
安装所需依赖:
bash
pip install yagmail schedule
基础邮件发送
使用smtplib和email发送邮件
smtplib 是 Python 标准库中的 SMTP 客户端模块,可以用来发送邮件。配合 email 模块可以构建完整的邮件内容。
python
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 设置邮件服务器信息
mail_host = "smtp.qq.com" # QQ邮箱服务器
mail_user = "your@qq.com" # 填写你的邮箱
mail_pass = "your_password" # 填写你的邮箱授权码
# 邮件内容设置
content = "这是一封测试邮件,包含简单的文本信息。"
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = Header("发件人<your@qq.com>", 'utf-8') # 发送者
message['To'] = Header("收件人", 'utf-8') # 接收者
subject = 'Python SMTP 邮件测试'
message['Subject'] = Header(subject, 'utf-8') # 邮件标题
try:
# 创建 SMTP 对象
smtpObj = smtplib.SMTP()
# 连接 SMTP 服务器
smtpObj.connect(mail_host, 25) # 25 是 SMTP 端口号
# 登录邮箱
smtpObj.login(mail_user, mail_pass)
# 发送邮件
smtpObj.sendmail(mail_user, ['recipient@example.com'], message.as_string())
print("邮件发送成功")
except smtplib.SMTPException as e:
print(f"Error: 邮件发送失败 - {e}")
finally:
smtpObj.quit()
上面的代码使用 smtplib 和 email 模块发送一封简单的文本邮件。需要注意的是,为了安全起见,实际使用中应将邮箱账号和密码等敏感信息通过环境变量等方式进行管理。
使用yagmail发送邮件
我们可以使用 yagmail 库来进一步简化发送邮件的过程。以下是使用 yagmail 发送邮件的示例代码:
python
import yagmail
# 初始化服务器信息
yag = yagmail.SMTP(user="your@qq.com", password="your_password", host="smtp.qq.com")
# 邮件内容
contents = [
"这是一封测试邮件,",
"包含多行文本内容。",
"这是第三行内容。"
]
# 发送邮件
try:
yag.send(
to='recipient@example.com',
subject='Python 邮件测试',
contents=contents,
# attachments="/path/to/file.txt" # 如果需要发送附件,取消注释并填写文件路径
)
print("邮件发送成功")
except Exception as e:
print(f"Error: 邮件发送失败 - {e}")
这段代码展示了如何使用 yagmail 库发送一封包含多行文本的邮件。yagmail 的优势在于它简化了邮件发送流程,并支持直接传入文件路径作为附件。
发送带附件的邮件
使用MIME协议发送附件
要发送带附件的邮件,我们需要使用 MIMEMultipart 来构建邮件内容,并使用 MIMEBase 来处理附件。
python
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders
import os
def send_email_with_attachments(send_from, send_to, subject, text, files=[], server="localhost", port=587, username=None, password=None):
"""
发送带附件的邮件
Args:
send_from: 发件人邮箱
send_to: 收件人邮箱(列表)
subject: 邮件主题
text: 邮件正文
files: 附件路径列表
server: SMTP服务器地址
port: SMTP服务器端口
username: 登录用户名
password: 登录密码
"""
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
# 添加邮件正文
msg.attach(MIMEText(text))
# 添加附件
for path in files:
try:
part = MIMEBase('application', "octet-stream")
with open(path, 'rb') as file:
part.set_payload(file.read())
encoders.encode_base64(part)
filename = os.path.basename(path)
part.add_header('Content-Disposition', f'attachment; filename="{filename}"')
msg.attach(part)
except Exception as e:
print(f"添加附件 {path} 时出错: {e}")
try:
# 发送邮件
smtp = smtplib.SMTP(server, port)
smtp.starttls() # 启用TLS加密
if username and password:
smtp.login(username, password)
smtp.sendmail(send_from, send_to, msg.as_string())
print("带附件的邮件发送成功")
except Exception as e:
print(f"发送邮件时出错: {e}")
finally:
smtp.quit()
# 使用示例
# send_email_with_attachments(
# send_from="your@qq.com",
# send_to=["recipient@example.com"],
# subject="带附件的邮件测试",
# text="这是一封包含附件的测试邮件。",
# files=["/path/to/file1.txt", "/path/to/file2.pdf"],
# server="smtp.qq.com",
# port=587,
# username="your@qq.com",
# password="your_password"
# )
批量发送个性化邮件
在实际应用中,我们经常需要向多个收件人发送个性化邮件。以下是一个批量发送个性化邮件的示例:
python
import yagmail
import pandas as pd
def send_personalized_emails(csv_file, template_file):
"""
从CSV文件读取收件人信息并发送个性化邮件
Args:
csv_file: 包含收件人信息的CSV文件路径
template_file: 邮件模板文件路径
"""
try:
# 读取收件人信息
df = pd.read_csv(csv_file)
# 读取邮件模板
with open(template_file, 'r', encoding='utf-8') as f:
template = f.read()
# 初始化邮件服务器
yag = yagmail.SMTP(user="your@qq.com", password="your_password", host="smtp.qq.com")
# 遍历所有收件人
sent_count = 0
for _, row in df.iterrows():
# 替换模板中的占位符
personalized_content = template.replace("{name}", row['name'])
# 构建邮件标题
subject = f"{row['title_prefix']}周报 - {row['name']}"
try:
# 发送邮件
yag.send(
to=row['email'],
subject=subject,
contents=personalized_content,
# attachments=row['attachments'] # 如果需要附件,取消注释
)
print(f"已发送邮件给: {row['email']}")
sent_count += 1
except Exception as e:
print(f"发送邮件给 {row['email']} 时出错: {e}")
print(f"批量发送完成,共发送 {sent_count} 封邮件")
except Exception as e:
print(f"批量发送邮件时出错: {e}")
# 使用示例
# send_personalized_emails("recipients.csv", "email_template.txt")
定时发送邮件功能
使用schedule模块定时发送邮件
schedule 是一个轻量级的 Python 定时任务调度库,非常适合用来实现定时发送邮件的功能。
python
import schedule
import time
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 设置邮件服务器信息
mail_host = "smtp.qq.com" # QQ邮箱服务器
mail_user = "your@qq.com" # 填写你的邮箱
mail_pass = "your_password" # 填写你的邮箱授权码
def send_daily_report():
"""发送每日报告邮件"""
# 邮件内容设置
content = "这是今天的销售报告摘要..."
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = Header("数据团队<your@qq.com>", 'utf-8') # 发送者
message['To'] = Header("管理层", 'utf-8') # 接收者
subject = '每日销售报告'
message['Subject'] = Header(subject, 'utf-8') # 邮件标题
try:
# 创建 SMTP 对象
smtpObj = smtplib.SMTP()
# 连接 SMTP 服务器
smtpObj.connect(mail_host, 25) # 25 是 SMTP 端口号
# 登录邮箱
smtpObj.login(mail_user, mail_pass)
# 发送邮件
smtpObj.sendmail(mail_user, ['recipient@example.com'], message.as_string())
print("定时邮件发送成功")
except smtplib.SMTPException as e:
print(f"Error: 邮件发送失败 - {e}")
finally:
smtpObj.quit()
# 安排每天特定时间执行任务
schedule.every().day.at("09:00").do(send_daily_report)
# 保持程序运行
print("邮件定时任务已启动...")
while True:
schedule.run_pending()
time.sleep(60) # 每分钟检查一次任务
以上代码展示了如何使用 schedule 模块创建一个每天早上9点执行的定时邮件发送任务。请注意,为了让定时任务持续运行,代码需要保持在运行状态,一旦程序终止或计算机关机,任务也将停止。对于生产环境,建议将此类脚本部署在云服务器上以确保其持续运行。
实际应用场景
场景一:自动化日报系统
python
import pandas as pd
import matplotlib.pyplot as plt
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders
import smtplib
import os
import datetime
def generate_sales_report():
"""
生成销售报告
Returns:
销售报告内容字符串和图表文件路径
"""
# 获取当前日期
today = datetime.date.today()
# 生成模拟销售数据
data = {
'日期': [today - datetime.timedelta(days=i) for i in range(7)],
'销售额': [1200, 1500, 1300, 1700, 1800, 2000, 1900],
'订单数': [30, 35, 32, 38, 40, 42, 41]
}
df = pd.DataFrame(data)
# 生成销售趋势图
plt.figure(figsize=(10, 5))
plt.plot(df['日期'], df['销售额'], marker='o')
plt.title('最近7天销售趋势')
plt.xlabel('日期')
plt.ylabel('销售额(元)')
plt.grid(True)
# 保存图表
chart_path = f"sales_trend_{today}.png"
plt.savefig(chart_path)
plt.close()
# 构建报告内容
report = f"## 销售日报 - {today}\n\n"
report += "**最近7天销售摘要:**\n"
report += df.to_markdown(index=False)
return report, chart_path
def send_daily_sales_report():
"""
发送每日销售报告邮件
"""
try:
# 生成销售报告
report_content, chart_path = generate_sales_report()
# 构建邮件内容
msg = MIMEMultipart()
msg['From'] = "数据团队<your@qq.com>"
msg['To'] = COMMASPACE.join(["manager@example.com"])
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = "每日销售报告"
# 添加邮件正文
msg.attach(MIMEText(report_content, 'plain'))
# 添加图表附件
try:
part = MIMEBase('application', "octet-stream")
with open(chart_path, 'rb') as file:
part.set_payload(file.read())
encoders.encode_base64(part)
filename = os.path.basename(chart_path)
part.add_header('Content-Disposition', f'attachment; filename="{filename}"')
msg.attach(part)
except Exception as e:
print(f"添加图表附件时出错: {e}")
# 发送邮件
try:
# 设置SMTP服务器
smtp = smtplib.SMTP("smtp.qq.com", 587)
smtp.starttls() # 启用TLS加密
smtp.login("your@qq.com", "your_password")
# 发送邮件
smtp.sendmail("your@qq.com", ["manager@example.com"], msg.as_string())
print("每日销售报告邮件发送成功")
except Exception as e:
print(f"发送邮件时出错: {e}")
finally:
smtp.quit()
except Exception as e:
print(f"生成销售报告时出错: {e}")
finally:
# 清理临时文件
if os.path.exists(chart_path):
os.remove(chart_path)
# 如果作为主程序运行
if __name__ == "__main__":
send_daily_sales_report()
场景二:客户通知系统
python
import yagmail
import pandas as pd
from jinja2 import Template
import os
def send_customer_notifications(customers_csv, template_file):
"""
向客户发送个性化通知邮件
Args:
customers_csv: 包含客户信息的CSV文件路径
template_file: 邮件模板文件路径
"""
try:
# 读取客户信息
df = pd.read_csv(customers_csv)
# 读取邮件模板
with open(template_file, 'r', encoding='utf-8') as f:
template_str = f.read()
# 初始化邮件服务器
yag = yagmail.SMTP(user="your@qq.com", password="your_password", host="smtp.qq.com")
# 加载Jinja2模板
template = Template(template_str)
# 遍历所有客户
sent_count = 0
for _, row in df.iterrows():
# 为每个客户生成个性化内容
personalized_content = template.render(**row)
# 构建邮件标题
subject = f"重要通知: {row['title_prefix']}"
try:
# 发送邮件
yag.send(
to=row['email'],
subject=subject,
contents=personalized_content,
# attachments=row['attachments'] # 如果需要附件,取消注释
)
print(f"已发送通知给: {row['email']}")
sent_count += 1
except Exception as e:
print(f"发送通知给 {row['email']} 时出错: {e}")
print(f"客户通知发送完成,共发送 {sent_count} 封邮件")
except Exception as e:
print(f"发送客户通知时出错: {e}")
# 使用示例
# send_customer_notifications("customers.csv", "notification_template.txt")
场景三:邮件定时任务管理系统
python
import schedule
import time
import argparse
import json
import os
def load_config(config_file):
"""
加载配置文件
Args:
config_file: 配置文件路径
Returns:
配置字典
"""
try:
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
return config
except Exception as e:
print(f"加载配置文件时出错: {e}")
return None
def send_scheduled_email(task_name, config):
"""
发送定时邮件
Args:
task_name: 任务名称
config: 配置字典
"""
try:
task_config = config['tasks'][task_name]
# 提取任务配置
recipients = task_config['recipients']
subject = task_config['subject']
content = task_config['content']
attachments = task_config.get('attachments', [])
# 初始化邮件服务器
yag = yagmail.SMTP(
user=config['smtp']['user'],
password=config['smtp']['password'],
host=config['smtp']['host']
)
# 发送邮件
yag.send(
to=recipients,
subject=subject,
contents=content,
attachments=attachments
)
print(f"[{task_name}] 邮件发送成功")
except Exception as e:
print(f"[{task_name}] 邮件发送失败: {e}")
def run_scheduler(config):
"""
运行定时任务调度器
Args:
config: 配置字典
"""
try:
# 调度所有任务
for task_name, task_config in config['tasks'].items():
schedule_time = task_config['schedule_time']
schedule.every().day.at(schedule_time).do(send_scheduled_email, task_name=task_name, config=config)
print(f"已安排 [{task_name}] 在 {schedule_time} 发送")
# 保持程序运行
print("邮件定时任务系统已启动...")
while True:
schedule.run_pending()
time.sleep(60)
except KeyboardInterrupt:
print("\n邮件定时任务系统已停止")
except Exception as e:
print(f"运行定时任务时出错: {e}")
def main():
"""
主函数
"""
# 创建命令行参数解析器
parser = argparse.ArgumentParser(description='邮件定时任务管理系统')
parser.add_argument('--config', '-c', required=True, help='配置文件路径')
# 解析命令行参数
args = parser.parse_args()
# 加载配置文件
config = load_config(args.config)
if not config:
return
# 运行定时任务调度器
run_scheduler(config)
# 如果作为主程序运行
if __name__ == "__main__":
main()
小结
通过本文介绍的Python邮件自动化技术,我们可以轻松实现基础邮件发送、发送带附件的邮件、群发个性化邮件以及定时发送邮件等功能。这些技术可以广泛应用于日报发送、客户通知、报告分发等场景,大大提高工作效率。
要使用本文中的代码,需要安装以下Python库:
bash
pip install yagmail schedule pandas matplotlib jinja2
注意:发送邮件功能需要有效的邮箱账户和SMTP服务器信息。为了安全起见,建议将敏感信息存储在环境变量或配置文件中,而不是硬编码在代码中。
通过掌握这些邮件自动化技术,你可以大大减少重复性工作,为日常办公提供强大支持。