Skip to Content

← SMTP Email Alerts from a Monitoring Server with Python

Geotechnical slope monitoringServer (Node-RED)SMTPAlerts

SMTP Email Alerts from a Monitoring Server with Python — full example

Send automatic email alerts from an industrial monitoring server with Python smtplib and a Gmail app password. Restart and alarm notification script.

Complete, runnable program for the Server (Node-RED) (email-alerts-smtp-gmail.py): wiring header, requirements and integration notes included.

Download the full project pack — freeThis example + the related ones + bill of materials

Read-only preview.

#!/usr/bin/env python3
"""
COMPLETE EXAMPLE — Email alerts (SMTP Gmail) from the concentrator

Hardware:  Server (Node-RED + Python) on a Raspberry Pi
Based on:  geotechnical slope monitoring project (4 stations,
           ESP32 PLC 14 Ethernet)

Architecture:
  - The Node-RED concentrator detects events that require human attention:
    device or Node-RED restart, a station not responding, or alert
    level 3-4 in the HTTP polling classification.
  - An exec node launches this script with subject and body as arguments:
        python3 email-alerts-smtp-gmail.py "SUBJECT" "BODY"
    (with no arguments it sends the reboot notice, useful in cron @reboot).
  - Sending uses smtp.gmail.com:587 with STARTTLS and a Gmail
    "app password" (the account must have 2-step verification enabled).

Credentials: always as placeholders; in production load them from
environment variables or from a file outside the repository.
"""

import socket
import sys
import smtplib
from datetime import datetime
from email.mime.text import MIMEText

# --- Configuration (fill in for production) ------------------------------
EMAIL_SENDER = "[email protected]"   # sending Gmail account
APP_PASSWORD = "APP_PASSWORD"                   # placeholder: Gmail app password
EMAIL_RECEIVER = "[email protected]"          # support team mailbox

SMTP_HOST = "smtp.gmail.com"
SMTP_PORT = 587

EQUIPMENT = "Slope concentrator (Raspberry Pi + Node-RED)"


def build_message(subject, body):
    """Builds the MIMEText with full headers to avoid spam filters."""
    message = MIMEText(body, "plain", "utf-8")
    message["Subject"] = subject
    message["From"] = EMAIL_SENDER
    message["To"] = EMAIL_RECEIVER
    return message


def send_email(subject, body):
    """Sends the notice over SMTP with STARTTLS. Returns True on success."""
    message = build_message(subject, body)
    try:
        server = smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=30)
        server.starttls()                       # encrypt before authenticating
        server.login(EMAIL_SENDER, APP_PASSWORD)
        server.sendmail(EMAIL_SENDER, EMAIL_RECEIVER, message.as_string())
        server.quit()
        print(f"Email sent to {EMAIL_RECEIVER}: {subject}")
        return True
    except Exception as e:
        # Email is the last line of notification: if it fails, at least
        # a trace remains in the Node-RED log / journalctl for diagnosis.
        print(f"ERROR sending email: {e}")
        return False


def reboot_notice():
    """Standard notice after a device or Node-RED restart."""
    now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
    hostname = socket.gethostname()

    subject = f"[SLOPE] Reboot detected on {hostname}"
    body = (
        f"Equipment: {EQUIPMENT}\n"
        f"Host: {hostname}\n"
        f"Boot date and time: {now}\n\n"
        "The device or the Node-RED service has restarted.\n"
        "Polling of the 4 stations and FTP delivery to the official\n"
        "monitoring platform resume automatically.\n\n"
        "Check the dashboard to confirm that all 4 stations\n"
        "report again on the next measurement interval.\n"
    )
    return send_email(subject, body)


def main():
    if len(sys.argv) >= 3:
        # Generic mode: Node-RED passes subject and body (level 3-4 alerts,
        # silent station, FTP delivery failure...)
        ok = send_email(sys.argv[1], sys.argv[2])
    else:
        # Default mode: reboot notice (cron @reboot / startup)
        ok = reboot_notice()

    sys.exit(0 if ok else 1)


if __name__ == "__main__":
    main()
Download the full project pack — freeThis example + the related ones + bill of materials