1. Shell邮件发送脚本开发背景与价值
在运维和开发工作中,我们经常需要处理各种系统告警和统计报表的自动发送需求。传统手动操作不仅效率低下,还容易遗漏重要信息。通过Shell脚本实现邮件自动发送功能,可以完美解决以下痛点:
- 实时性差:人工检查系统状态存在时间延迟
- 工作重复:固定格式的报表需要反复手动发送
- 易出错:人工操作可能遗漏收件人或发错内容
- 无记录:缺乏发送日志难以追溯问题
我经手的一个典型案例:某电商平台大促期间,需要每小时发送服务器负载报表给10个不同部门的负责人。最初由值班人员手动操作,不仅占用人力,还出现过发送延误导致扩容不及时的情况。改用Shell脚本自动发送后,实现了:
- 准点自动发送,误差不超过10秒
- 发送成功率100%
- 完整记录发送日志
- 异常情况自动重试
2. 核心组件与技术选型
2.1 邮件发送协议对比
实现邮件发送主要有三种协议可选:
| 协议 | 端口 | 加密要求 | 适用场景 |
|---|---|---|---|
| SMTP | 25/465 | TLS/SSL | 标准邮件发送 |
| Sendmail | - | 无 | 本地邮件服务 |
| Mailx | - | 无 | 简单命令行发送 |
经过实测对比,我们选择SMTP协议方案,原因在于:
- 支持身份验证更安全
- 可配置加密传输
- 兼容各类邮件服务商
- 发送记录可追踪
2.2 关键命令行工具
# 基础工具 mailx # 简单邮件客户端 sendmail # 本地邮件传输代理 mutt # 功能更丰富的邮件客户端 # 网络工具 curl # 支持SMTP的HTTP请求 openssl # 加密连接工具 nc # 网络调试推荐使用mailx+mutt组合方案,既能满足基本需求,又支持高级功能扩展。
3. 完整实现方案
3.1 基础环境配置
首先确保系统已安装必要工具:
# CentOS/RHEL yum install mailx mutt openssl -y # Ubuntu/Debian apt-get install mailutils mutt openssl -y配置mailx参数(/etc/mail.rc):
set from="alert@example.com" set smtp="smtp.example.com:587" set smtp-auth-user="alert@example.com" set smtp-auth-password="yourpassword" set smtp-auth=login set ssl-verify=ignore3.2 核心发送脚本
创建send_mail.sh:
#!/bin/bash # 接收参数 TO=$1 SUBJECT=$2 CONTENT=$3 ATTACH=$4 # 检查必要参数 if [ -z "$TO" ]; then echo "Error: Recipient email is required" exit 1 fi # 生成邮件头 HEADER="From: System Alert <alert@example.com> To: ${TO} Subject: ${SUBJECT:-"System Notification"} Content-Type: text/html; charset=utf-8 " # 发送逻辑 if [ -n "$ATTACH" ]; then # 带附件发送 echo -e "${HEADER}\n$(cat ${CONTENT})" | mutt -e "set content_type=text/html" -s "${SUBJECT}" -a "${ATTACH}" -- "${TO}" else # 无附件发送 echo -e "${HEADER}\n$(cat ${CONTENT})" | /usr/sbin/sendmail -t fi # 记录日志 echo "$(date '+%Y-%m-%d %H:%M:%S') - Sent to ${TO}" >> /var/log/mail_sender.log3.3 定时任务配置
设置每天8:00发送日报:
# 编辑crontab crontab -e # 添加如下行 0 8 * * * /path/to/send_mail.sh "receiver@example.com" "Daily Report" /path/to/report.html4. 高级功能实现
4.1 HTML格式邮件
创建模板文件template.html:
<!DOCTYPE html> <html> <head> <style> .alert { color: red; } .normal { color: green; } </style> </head> <body> <h1>System Report</h1> <p>Time: $(date)</p> <p>Status: <span class="${STATUS_CLASS}">${STATUS}</span></p> </body> </html>在脚本中渲染模板:
# 替换模板变量 sed -e "s/\${STATUS_CLASS}/$status_class/g" \ -e "s/\${STATUS}/$status/g" \ template.html > output.html4.2 邮件队列管理
当需要处理大量邮件时,建议实现队列机制:
# 队列目录结构 mail_queue/ ├── pending ├── processing └── sent # 处理脚本 for mail in $(ls -1 /mail_queue/pending); do mv "/mail_queue/pending/$mail" "/mail_queue/processing/" /path/to/send_mail.sh $(cat "/mail_queue/processing/$mail") mv "/mail_queue/processing/$mail" "/mail_queue/sent/" done5. 实战问题排查
5.1 常见错误代码
| 错误代码 | 原因 | 解决方案 |
|---|---|---|
| 550 | 收件人不存在 | 检查邮箱地址拼写 |
| 535 | 认证失败 | 检查用户名密码/启用应用密码 |
| 421 | 服务器连接数过多 | 降低发送频率 |
| 452 | 存储空间不足 | 清理邮箱/联系管理员 |
5.2 调试技巧
- 使用telnet测试SMTP连通性:
telnet smtp.example.com 587 EHLO example.com AUTH LOGIN ...- 查看详细日志:
tail -f /var/log/maillog- 测试邮件发送:
echo "Test message" | mailx -s "Test" your@email.com6. 安全加固方案
6.1 凭证管理
不要将密码明文存储在脚本中,推荐方案:
- 使用环境变量:
export SMTP_PASSWORD="yourpassword"- 使用加密文件:
# 生成加密文件 openssl enc -aes-256-cbc -salt -in password.txt -out password.enc # 脚本中解密使用 PASS=$(openssl enc -d -aes-256-cbc -in password.enc)6.2 发送频率控制
防止被识别为垃圾邮件:
# 限制发送频率 MAX_MAILS=30 COUNT=$(grep -c $(date '+%Y-%m-%d') /var/log/mail_sender.log) if [ $COUNT -ge $MAX_MAILS ]; then echo "Daily limit reached" >&2 exit 1 fi7. 性能优化建议
- 连接复用:保持SMTP连接而不是每次新建
# 使用mutt的连接池功能 mutt -e "set smtp_pool=yes"- 并行发送:使用xargs处理大批量邮件
cat mail_list.txt | xargs -P 4 -n 1 /path/to/send_mail.sh- 模板预编译:提前渲染好静态部分
# 拆分模板为静态和动态部分 cat template_static.html > final.html echo "<div>$(date)</div>" >> final.html cat template_footer.html >> final.html8. 监控与告警
实现发送失败自动告警:
# 在发送脚本中添加 if [ $? -ne 0 ]; then echo "Failed to send mail to ${TO}" | \ mailx -s "Mail Delivery Failed" admin@example.com fi配置Prometheus监控指标:
# 暴露metrics接口 echo "mail_sent_total $(grep -c 'Sent' /var/log/mail_sender.log)" > /var/www/metrics/index.html