巡检-域名-过期时间-邮件通知
mail_domains_check.py
通过脚本巡检即将到期的域名,并发送邮件到相关人
只需要修改***就可以添加发送人和接收人
巡检内容地址为:/data/domains_list,格式为域名+空格备注(liwork.cn 博客网站)
效果示意:
执行命令:
python3 mail_domains_check.py
代码内容
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import subprocess
import smtplib
import ssl
import re
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# ------------------ 配置参数 ------------------
SMTP_HOST = "***"
SMTP_PORT = ***
SMTP_USER = "***"
SMTP_PASSWORD = "***"
RECIPIENTS = [
"***",
"***"
]
DOMAIN_LIST_FILE = "/data/domains_list" # 域名列表文件
OUTPUT_FILE = "/data/domains_lists"
# ---------------------------------------------
def get_domain_expiry(domain):
"""获取域名过期时间"""
try:
# 针对.cn域名使用特定WHOIS服务器
if domain.endswith('.cn'):
cmd = f"timeout 30 whois -h whois.cnnic.cn {domain}"
else:
cmd = f"timeout 30 whois {domain}"
result = subprocess.run(
cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
encoding='utf-8'
)
if result.returncode != 0:
raise Exception(f"WHOIS错误: {result.stderr.strip()}")
# 解析过期日期
whois_output = result.stdout.lower()
patterns = [
r'expiry date\s*:\s*(\d{4}-\d{2}-\d{2})',
r'registry expiry date\s*:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})',
r'expiration time\s*:\s*(\d{4}-\d{2}-\d{2})',
r'registrar registration expiration date\s*:\s*(\d{4}-\d{2}-\d{2})'
]
expiry_date = None
for pattern in patterns:
match = re.search(pattern, whois_output)
if match:
expiry_date = match.group(1).split()[0] # 取日期部分
break
if not expiry_date:
raise Exception("未找到过期日期字段")
return datetime.strptime(expiry_date, '%Y-%m-%d')
except Exception as e:
print(f"[ERROR] {domain} 检测失败: {str(e)}")
return None
def check_domains():
"""主检查函数"""
if not os.path.exists(DOMAIN_LIST_FILE):
print(f"[FATAL] 配置文件 {DOMAIN_LIST_FILE} 不存在")
sys.exit(1)
warning_domains = []
with open(DOMAIN_LIST_FILE, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(maxsplit=1)
domain = parts[0]
note = parts[1] if len(parts) > 1 else ''
print(f"\n{'='*80}")
print(f"正在检测: {domain}")
expiry_date = get_domain_expiry(domain)
if not expiry_date:
print("查询失败,跳过该域名")
continue
now = datetime.now()
days_left = (expiry_date - now).days
print(f"剩余天数: {days_left}")
if days_left < 30: # 过期阈值设为30天
print("[WARNING] 域名即将过期")
with open(OUTPUT_FILE, 'a', encoding='utf-8') as f:
f.write(f"{domain}\n")
warning_domains.append({
'domain': domain,
'expire': expiry_date.strftime('%Y-%m-%d'),
'note': note
})
return warning_domains
def send_email(warnings):
"""发送邮件(完全保留原始样式)"""
if not warnings:
print("无域名过期预警")
return
current_date = datetime.now().strftime("%Y-%m-%d")
msg = MIMEMultipart('alternative')
msg['Subject'] = f'[{current_date}] 域名过期预警 - 需人工处理'
msg['From'] = f"Liwork自动巡检 <{SMTP_USER}>"
msg['To'] = ", ".join(RECIPIENTS)
# 生成表格内容
table_rows = []
for item in warnings:
table_rows.append(f"""
<tr style="border-bottom: 1px solid #eee;">
<td style="padding: 12px 0; color: #2c3e50; width: 40%;">{item['domain']}</td>
<td style="padding: 12px 0; color: #e74c3c; width: 30%;">{item['expire']}</td>
<td style="padding: 12px 0; color: #95a5a6; width: 30%;">{item['note']}</td>
</tr>
""")
# 完整保留原始邮件模板
html_content = f"""
<html>
<head>
<meta charset="UTF-8">
<style>
body {{
font-family: Helvetica, Arial, sans-serif;
margin: 0;
padding: 30px;
background: #fafafa;
}}
.header {{
background: #2c3e50;
color: white;
padding: 25px 30px;
border-radius: 8px;
margin-bottom: 25px;
}}
.alert-section {{
background: #ffe5e5;
color: #c0392b;
padding: 15px;
border-radius: 6px;
margin-bottom: 25px;
border-left: 4px solid #c0392b;
}}
.report-table {{
width: 100%;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
border-collapse: collapse;
margin-bottom: 30px;
}}
.report-table th {{
background: #f8f9fb;
padding: 16px 0;
color: #7f8c8d;
font-weight: 500;
text-align: left;
border-bottom: 2px solid #eee;
}}
.report-table td {{
padding: 14px 0;
}}
.footer {{
color: #95a5a6;
font-size: 0.9em;
padding-left: 10px;
line-height: 1.5;
}}
</style>
</head>
<body>
<div class="header">
<h1 style="margin:0; font-weight:300;">域名过期巡检报告</h1>
<h3 style="margin:10px 0 0; font-weight:400;">检测日期:{current_date}</h3>
</div>
<div class="alert-section">
发现 {len(warnings)} 个域名即将过期(剩余天数 < 30)
</div>
<table class="report-table">
<thead>
<tr>
<th style="padding-left: 30px;">域名</th>
<th>过期时间</th>
<th style="padding-right: 30px;">备注信息</th>
</tr>
</thead>
<tbody>
{''.join(table_rows)}
</tbody>
</table>
<div class="footer">
<p>技术支持:zhouli@liwork.cn</p>
<p style="margin-top:8px;">此邮件由系统自动生成,请勿直接回复</p>
</div>
</body>
</html>
"""
msg.attach(MIMEText(html_content, 'html', 'utf-8'))
try:
context = ssl.create_default_context()
with smtplib.SMTP_SSL(
host=SMTP_HOST,
port=SMTP_PORT,
context=context,
timeout=30
) as server:
server.login(SMTP_USER, SMTP_PASSWORD)
server.sendmail(SMTP_USER, RECIPIENTS, msg.as_string())
print("告警邮件已发送至:", RECIPIENTS)
except Exception as e:
print(f"[ERROR] 邮件发送失败: {str(e)}")
if __name__ == "__main__":
# 初始化输出文件
with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
f.write("")
print("=== 域名过期巡检开始 ===")
warnings = check_domains()
if warnings:
print(f"\n发现 {len(warnings)} 个域名即将过期")
send_email(warnings)
else:
print("\n所有域名状态正常")
print("=== 检查完成 ===")
评论
其他文章