邮件发送脚本怎么写?从零到一构建自动化邮件系统实战指南
目录导读
- 为什么需要邮件发送脚本?
- Python vs Shell vs 其他语言:哪种更适合你?
- 核心知识:SMTP协议与邮件发送原理
- 手把手教你写一个Python邮件发送脚本
- 进阶技巧:批量发送、附件、HTML模板
- 常见错误与排查方法(问答环节)
- 安全与合规:避免被标记为垃圾邮件
- 实战案例:监控告警邮件自动发送
- 总结与最佳实践
为什么需要邮件发送脚本?
在日常工作中,无论是系统运维监控、用户注册通知、定时报告推送,还是营销邮件群发,手动发送邮件都是低效且容易出错的,邮件发送脚本能帮你实现:

- 自动化:按预设规则自动发送,无需人工干预
- 批量处理:同时向数百甚至数千人发送个性化内容
- 定时触发:结合cron或任务调度器实现周期性发送
- 集成能力:无缝对接监控系统、数据库、API等
根据Stack Overflow 2024年开发者调查,超过60%的后端开发者需要编写邮件发送程序,掌握这项技能,你将能快速构建报警系统、订阅通知、客户联系等实用功能。
Python vs Shell vs 其他语言:哪种更适合你?
| 语言/工具 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| Python | 通用、复杂逻辑 | 库丰富(smtplib/email),代码易读 | 需安装Python环境 |
| Shell | 简单发送、Linux环境 | 原生支持mail/sendmail命令 |
功能有限,附件处理麻烦 |
| Node.js | 前端/全栈项目 | 异步非阻塞,npm包丰富 | 回调地狱,内存占用较高 |
| Go | 高性能、并发场景 | 编译为单文件,部署简便 | 语法稍复杂,生态不如Python成熟 |
对于大多数用户,Python是最平衡的选择——门槛低、文档多、能处理复杂需求,本文将以Python为主进行演示。
核心知识:SMTP协议与邮件发送原理
1 SMTP是什么?
简单邮件传输协议(SMTP)是互联网上发送邮件的标准协议,当你通过脚本发送邮件时,实际上是在与SMTP服务器通信(如smtp.gmail.com、smtp.qq.com等)。
2 发送流程
你的脚本 → SMTP服务器 → 收件方邮件服务器 → 收件人收件箱
3 关键术语
- 发件人地址:用于身份验证,通常需要用户名和密码
- 收件人地址:可以设置To、Cc(抄送)、Bcc(密送)
- 邮件头:包含Subject(主题)、From、To、Date等
- 邮件体:可以是纯文本或HTML格式
4 端口选择
- 587:TLS加密端口(推荐,如Gmail、QQ邮箱)
- 465:SSL加密端口(部分服务商仍使用)
- 25:非加密端口(需自行配置加密,不建议)
手把手教你写一个Python邮件发送脚本
1 准备工作
- 开启邮箱的SMTP服务(以QQ邮箱为例):
- 登录QQ邮箱 → 设置 → 账户 → 开启“POP3/IMAP/SMTP服务”
- 生成一个授权码(不是登录密码)
- 安装Python(如未安装,从python.org下载)
2 基础脚本:发送一封纯文本邮件
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 配置信息
smtp_server = "smtp.qq.com" # 发件人邮箱SMTP地址
port = 587 # 端口(QQ邮箱使用587)
sender = "your_email@qq.com" # 发件人邮箱
password = "your_authorization_code" # QQ邮箱授权码(不是登录密码)
receiver = "receiver@example.com" # 收件人邮箱
# 构建邮件内容
message = MIMEText("这是一封由Python发送的测试邮件。", "plain", "utf-8")
message["From"] = Header("脚本小助手", "utf-8") # 发件人显示名称
message["To"] = Header("亲爱的用户", "utf-8") # 收件人显示名称
message["Subject"] = Header("Python邮件测试", "utf-8")
try:
# 连接SMTP服务器并发送
server = smtplib.SMTP(smtp_server, port)
server.starttls() # 启用TLS加密
server.login(sender, password)
server.sendmail(sender, [receiver], message.as_string())
print("✅ 邮件发送成功!")
except Exception as e:
print(f"❌ 发送失败:{e}")
finally:
server.quit()
运行方法:将上述代码保存为send_mail.py,在终端执行python send_mail.py。
进阶技巧:批量发送、附件、HTML模板
1 批量发送(带个性化内容)
import smtplib
from email.mime.text import MIMEText
# 收件人列表(姓名+邮箱)
recipients = [
{"name": "张三", "email": "zhangsan@example.com"},
{"name": "李四", "email": "lisi@example.com"},
]
for person in recipients:
content = f"""
尊敬的{person['name']}:
您好!您的账户已验证成功。
此致
敬礼
"""
msg = MIMEText(content, "plain", "utf-8")
msg["Subject"] = f"验证通知 - {person['name']}"
msg["From"] = sender
msg["To"] = person["email"]
# 发送逻辑同上(可复用连接)
server.sendmail(sender, [person["email"]], msg.as_string())
print("批量发送完成!")
2 添加附件
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
msg = MIMEMultipart()
msg["Subject"] = "含有附件的邮件"
msg["From"] = sender
msg["To"] = receiver
body = MIMEText("请查收附件。", "plain", "utf-8")
msg.attach(body)
# 添加附件(如:report.pdf)
filename = "report.pdf"
attachment = open(filename, "rb")
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header("Content-Disposition", f"attachment; filename= {filename}")
msg.attach(part)
# 发送
server.sendmail(sender, [receiver], msg.as_string())
3 使用HTML模板(推荐)
html_template = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; }
.btn { background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; }
</style>
</head>
<body>
<h2>尊敬的用户,您好!</h2>
<p>请点击下方按钮验证您的邮箱:</p>
<a class="btn" href="https://your-domain.com/verify?token=abc123">验证邮箱</a>
<p>如果按钮无法点击,请复制以下链接到浏览器:</p>
<p>https://your-domain.com/verify?token=abc123</p>
</body>
</html>
"""
msg = MIMEText(html_template, "html", "utf-8")
常见错误与排查方法(问答环节)
Q1:收到“535 Authentication failed”错误?
A:最常见的原因是SMTP用户名或密码错误,注意:
- 密码不是邮箱登录密码,而是授权码(需单独生成)
- 部分邮箱(如163)需使用“客户端授权码”而非登录密码
Q2:为什么发送成功但收件人没收到?(进入垃圾箱)
A:可能是被SPF/DKIM验证拦截,解决方案:
- 发件人域名配置SPF记录(DNS中添加TXT记录)
- 避免使用过于营销性的词汇(如“免费”“折扣”)
- 控制发送频率,单次别超过100封
Q3:遇到“Connection refused”怎么办?
A:检查:
- SMTP服务器地址是否写对(如QQ邮箱是smtp.qq.com)
- 端口是否被防火墙屏蔽(尝试587或465)
- 网络是否能访问外部SMTP服务器
Q4:如何发送定时邮件?
A:结合系统调度工具:
- Linux/Mac:使用crontab,例如每天早8点运行:
0 8 * * * /usr/bin/python3 /path/to/your_script.py - Windows:使用“任务计划程序”设置定时执行
安全与合规:避免被标记为垃圾邮件
1 通用安全准则
- 不要硬编码密码:使用环境变量或配置文件
- 加日志记录:记录每次发送的收件人、时间、状态
- 设置发送频率限制:每5分钟发送不超过50封
2 腾讯云/阿里云邮件推送(替代方案)
对于较大规模发送(>100封/天),建议使用邮件推送服务:
- 阿里云邮件推送:提供高可用API,自动处理退回/投诉
- 腾讯云邮件推送:支持模板管理、统计分析
3 域名授权
在DNS中添加以下TXT记录可提升送达率:
v=spf1 include:spf.your-email-provider.com ~all
同时开启DKIM签名(多数服务商有向导)。
实战案例:监控告警邮件自动发送
假设你的服务器磁盘使用率超过85%,需要自动发送告警:
import subprocess
import smtplib
from email.mime.text import MIMEText
def check_disk_usage():
result = subprocess.run(["df", "-h", "/"], capture_output=True, text=True)
lines = result.stdout.split("\n")
if len(lines) > 1:
usage_percent = lines[1].split()[4].rstrip("%")
return int(usage_percent)
return 0
def send_alert(usage):
if usage > 85:
msg = MIMEText(f"⚠️ 磁盘使用率已达到 {usage}%,请立即清理!", "plain", "utf-8")
msg["Subject"] = f"服务器磁盘告警: {usage}%"
server.sendmail(sender, [admin_email], msg.as_string())
# 在主程序中调用
usage = check_disk_usage()
send_alert(usage)
将此脚本加入crontab(每5分钟执行一次):
*/5 * * * * python3 /path/to/disk_alert.py
总结与最佳实践
1 核心关键点
- SMTP配置:正确提供服务器地址、端口、账号密码是关键
- 代码结构:将配置与逻辑分离,使用
config.py或环境变量 - 测试先行:先用
[test@yourserver.com]测试,再扩展到真实用户 - 日志记录:每次发送写入日志,便于排查问题
2 推荐阅读与工具
- Python官方文档:
smtplib和email模块 - 在线测试工具:
smtpbucket.com(测试邮件发送,不实际投递) - 开源项目:
yagmail(简化邮件发送)、flask-mail(集成Flask框架)
3 下一步学习
- 集成HTML模板引擎(如Jinja2)提升邮件美观度
- 使用异步框架(如
aiofiles+aiosmtplib)提升批量发送性能 - 学习邮件营销规范:退订链接、真实发件人、内容许可
邮件发送脚本不仅仅是技术实现,更是可靠性与合规性的平衡,从一个小脚本开始,逐步构建你的自动化通信系统吧!