服务器定时发送邮件设置

服务器定时发送邮件设置

crontab -e

bash 复制代码
"/tmp/crontab.srYPTQ" 1L, 72B
*/10 * * * * /usr/bin/python3 /root/send_mail.py >> /root/mail.log 2>&1

检查日志,并发送邮件

python 复制代码
import os
import re
import smtplib
from datetime import datetime, date
from email.mime.text import MIMEText
from email.header import Header

# ========== 日志监控配置 ==========
LOG_FILE = "/root/xxx.log"
KEYWORD = "youtube"
STATE_FILE = "/root/mail_auto/log_monitor.state"

# ========== QQ邮箱配置 ==========
SMTP_HOST = "smtp.qq.com"
SMTP_PORT = 465

SENDER = "你的QQ邮箱@qq.com"
AUTH_CODE = "你的QQ邮箱授权码"
RECEIVER = "接收报警的邮箱@example.com"


def send_email(subject, body):
    msg = MIMEText(body, "plain", "utf-8")
    msg["From"] = SENDER
    msg["To"] = RECEIVER
    msg["Subject"] = Header(subject, "utf-8")

    with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server:
        server.login(SENDER, AUTH_CODE)
        server.sendmail(SENDER, [RECEIVER], msg.as_string())


def get_last_position():
    if not os.path.exists(STATE_FILE):
        return None

    try:
        with open(STATE_FILE, "r") as f:
            return int(f.read().strip())
    except Exception:
        return None


def save_position(position):
    with open(STATE_FILE, "w") as f:
        f.write(str(position))


def parse_log_time(line):
    """
    匹配日志时间格式:
    2026/05/03 14:20:00
    """

    pattern = r"(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})"
    match = re.search(pattern, line)

    if not match:
        return None

    try:
        return datetime.strptime(match.group(1), "%Y/%m/%d %H:%M:%S")
    except Exception:
        return None


def filter_today_lines(content):
    today = date.today()

    today_lines = []
    for line in content.splitlines():
        log_time = parse_log_time(line)

        if log_time is not None and log_time.date() == today:
            today_lines.append(line)

    return "\n".join(today_lines)


def monitor_log():
    if not os.path.exists(LOG_FILE):
        print(f"日志文件不存在: {LOG_FILE}")
        return

    current_size = os.path.getsize(LOG_FILE)
    last_position = get_last_position()

    with open(LOG_FILE, "r", encoding="utf-8", errors="ignore") as f:
        if last_position is None:
            # 首次运行:读取整个日志,但只检查今天的内容
            print("首次运行:只检查今天的日志")
            content = f.read()
            check_content = filter_today_lines(content)
        else:
            # 如果日志被清空或轮转,从头开始
            if current_size < last_position:
                last_position = 0

            f.seek(last_position)
            content = f.read()

            # 后续运行:只检查新增内容,并且只保留今天的日志
            check_content = filter_today_lines(content)

        new_position = f.tell()

    # 无论是否命中,都保存当前位置,避免重复检查
    save_position(new_position)

    if KEYWORD.lower() in check_content.lower():
        matched_lines = []
        for line in check_content.splitlines():
            if KEYWORD.lower() in line.lower():
                matched_lines.append(line)

        matched_text = "\n".join(matched_lines[:20])

        subject = f"服务器日志报警:检测到关键词 {KEYWORD}"
        body = f"""
检测到日志中出现关键词:{KEYWORD}

日志文件:
{LOG_FILE}

匹配关键词:
{KEYWORD}

匹配到的日志如下:

{matched_text}
"""

        send_email(subject, body)
        print(f"检测到关键词 {KEYWORD},已发送邮件")
    else:
        print(f"今天的新增日志中未检测到关键词 {KEYWORD}")


if __name__ == "__main__":
    monitor_log()
相关推荐
修己xj17 小时前
服务器无法解析域名?一次 DNS 配置缺失的排查与修复
运维
爱吃奥利奥_wen19 小时前
SQL Server 基础语法详解:从建库建表到约束与增删改查
服务器·数据库·oracle
xbzb1 天前
自定义 yum 软件源:Linux 上 createrepo,Windows 上纯 Python 也能造
linux·运维·windows·python·yum·createrepo
Android系统攻城狮1 天前
Linux FFmpeg深度解析之avio_open调用流程与实战(三十八)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
瑞克-桑切斯1 天前
ERP 企业生产管理系统部署手册
运维·docker·云原生·容器·eureka
江屿风1 天前
【Git-组件】【Git入门:从文档灾难到版本掌控】流食般投喂
运维·笔记·git·组件·版本控制
我不会起名字3221 天前
K8s 节点磁盘打满导致 Pod 被驱逐:4 类占用与回收顺序
运维·kubernetes·k8s·diskpressure·evicted
雪落漂泊1 天前
Linux进程(五):进程地址空间篇
linux·运维·服务器
瑞克-桑切斯1 天前
docker mail商城
运维·docker·容器
AR-26710-1 天前
Linux Day32——网络,ROCE-IB与以太网
linux·运维