Notification rework - SMTP v0.2 - WIP👷‍♂️

This commit is contained in:
Jokob-sk
2023-10-08 22:00:24 +11:00
parent e4a64a11bd
commit 1e693abfc4
7 changed files with 740 additions and 550 deletions

View File

@@ -24,7 +24,7 @@ import multiprocessing
import conf
from const import *
from logger import mylog
from helper import filePermissions, timeNowTZ, updateState, get_setting_value, noti_obj
from helper import filePermissions, timeNowTZ, updateState, get_setting_value, noti_obj
from api import update_api
from networkscan import process_scan
from initialise import importConfigs

View File

@@ -6,6 +6,9 @@ from cron_converter import Cron
from pathlib import Path
import datetime
import json
import shutil
import re
import conf
from const import fullConfPath
@@ -62,6 +65,9 @@ def importConfigs (db):
# Only import file if the file was modifed since last import.
# this avoids time zone issues as we just compare the previous timestamp to the current time stamp
# rename settings that have changed names due to code cleanup and migration to plugins
renameSettings(config_file)
fileModifiedTime = os.path.getmtime(config_file)
mylog('debug', ['[Import Config] checking config file '])
@@ -114,18 +120,6 @@ def importConfigs (db):
# Notification gateways
# ----------------------------------------
# Email
conf.REPORT_MAIL = ccd('REPORT_MAIL', False , c_d, 'Enable email', 'boolean', '', 'Email', ['test'])
conf.SMTP_SERVER = ccd('SMTP_SERVER', '' , c_d,'SMTP server URL', 'text', '', 'Email')
conf.SMTP_PORT = ccd('SMTP_PORT', 587 , c_d, 'SMTP port', 'integer', '', 'Email')
conf.REPORT_TO = ccd('REPORT_TO', 'user@gmail.com' , c_d, 'Email to', 'text', '', 'Email')
conf.REPORT_FROM = ccd('REPORT_FROM', 'Pi.Alert <user@gmail.com>' , c_d, 'Email Subject', 'text', '', 'Email')
conf.SMTP_SKIP_LOGIN = ccd('SMTP_SKIP_LOGIN', False , c_d, 'SMTP skip login', 'boolean', '', 'Email')
conf.SMTP_USER = ccd('SMTP_USER', '' , c_d, 'SMTP user', 'text', '', 'Email')
conf.SMTP_PASS = ccd('SMTP_PASS', '' , c_d, 'SMTP password', 'password', '', 'Email')
conf.SMTP_SKIP_TLS = ccd('SMTP_SKIP_TLS', False , c_d, 'SMTP skip TLS', 'boolean', '', 'Email')
conf.SMTP_FORCE_SSL = ccd('SMTP_FORCE_SSL', False , c_d, 'Force SSL', 'boolean', '', 'Email')
# Webhooks
conf.REPORT_WEBHOOK = ccd('REPORT_WEBHOOK', False , c_d, 'Enable Webhooks', 'boolean', '', 'Webhooks', ['test'])
conf.WEBHOOK_URL = ccd('WEBHOOK_URL', '' , c_d, 'Target URL', 'text', '', 'Webhooks')
@@ -283,4 +277,56 @@ def read_config_file(filename):
code = compile(filename.read_text(), filename.name, "exec")
confDict = {} # config dictionary
exec(code, {"__builtins__": {}}, confDict)
return confDict
return confDict
#-------------------------------------------------------------------------------
replacements = {
r'\bREPORT_TO\b': 'SMTP_REPORT_TO',
r'\bREPORT_FROM\b': 'SMTP_REPORT_FROM'
}
def renameSettings(config_file):
# Check if the file contains any of the old setting code names
contains_old_settings = False
# Open the original config_file for reading
with open(str(config_file), 'r') as original_file: # Convert config_file to a string
for line in original_file:
# Use regular expressions with word boundaries to check for the old setting code names
if any(re.search(key, line) for key in replacements.keys()):
contains_old_settings = True
break # Exit the loop if any old setting is found
# If the file contains old settings, proceed with renaming and backup
if contains_old_settings:
# Create a backup file with the suffix "_old_setting_names" and timestamp
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
backup_file = f"{config_file}_old_setting_names_{timestamp}.bak"
mylog('debug', f'[Config] Old setting names will be replaced and a backup ({backup_file}) of the config created.')
shutil.copy(str(config_file), backup_file) # Convert config_file to a string
# Open the original config_file for reading and create a temporary file for writing
with open(str(config_file), 'r') as original_file, open(str(config_file) + "_temp", 'w') as temp_file: # Convert config_file to a string
for line in original_file:
# Use regular expressions with word boundaries for replacements
for key, value in replacements.items():
line = re.sub(key, value, line)
# Write the modified line to the temporary file
temp_file.write(line)
# Close both files
original_file.close()
temp_file.close()
# Replace the original config_file with the temporary file
shutil.move(str(config_file) + "_temp", str(config_file)) # Convert config_file to a string
else:
mylog('debug', '[Config] No old setting names found in the file. No changes made.')

View File

@@ -1,100 +0,0 @@
""" Pi.Alert module to send notification emails """
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import conf
import socket
from helper import hide_email, noti_obj
from logger import mylog, print_log
#-------------------------------------------------------------------------------
def check_config ():
if conf.SMTP_SERVER == '' or conf.REPORT_FROM == '' or conf.REPORT_TO == '':
mylog('none', ['[Email Check Config] Error: Email service not set up correctly. Check your pialert.conf SMTP_*, REPORT_FROM and REPORT_TO variables.'])
return False
else:
return True
#-------------------------------------------------------------------------------
def send (msg: noti_obj):
pText = msg.text
pHTML = msg.html
mylog('debug', '[Send Email] REPORT_TO: ' + hide_email(str(conf.REPORT_TO)) + ' SMTP_USER: ' + hide_email(str(conf.SMTP_USER)))
# Compose email
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Pi.Alert Report'
msg['From'] = conf.REPORT_FROM
msg['To'] = conf.REPORT_TO
msg.attach (MIMEText (pText, 'plain'))
msg.attach (MIMEText (pHTML, 'html'))
failedAt = ''
failedAt = print_log ('SMTP try')
try:
# Send mail
failedAt = print_log('Trying to open connection to ' + str(conf.SMTP_SERVER) + ':' + str(conf.SMTP_PORT))
# Set a timeout for the SMTP connection (in seconds)
smtp_timeout = 30
if conf.SMTP_FORCE_SSL:
failedAt = print_log('SMTP_FORCE_SSL == True so using .SMTP_SSL()')
if conf.SMTP_PORT == 0:
failedAt = print_log('SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER)')
smtp_connection = smtplib.SMTP_SSL(conf.SMTP_SERVER)
else:
failedAt = print_log('SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER, SMTP_PORT)')
smtp_connection = smtplib.SMTP_SSL(conf.SMTP_SERVER, conf.SMTP_PORT, timeout=smtp_timeout)
else:
failedAt = print_log('SMTP_FORCE_SSL == False so using .SMTP()')
if conf.SMTP_PORT == 0:
failedAt = print_log('SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER)')
smtp_connection = smtplib.SMTP (conf.SMTP_SERVER)
else:
failedAt = print_log('SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER, SMTP_PORT)')
smtp_connection = smtplib.SMTP (conf.SMTP_SERVER, conf.SMTP_PORT)
failedAt = print_log('Setting SMTP debug level')
# Log level set to debug of the communication between SMTP server and client
if conf.LOG_LEVEL == 'debug':
smtp_connection.set_debuglevel(1)
failedAt = print_log( 'Sending .ehlo()')
smtp_connection.ehlo()
if not conf.SMTP_SKIP_TLS:
failedAt = print_log('SMTP_SKIP_TLS == False so sending .starttls()')
smtp_connection.starttls()
failedAt = print_log('SMTP_SKIP_TLS == False so sending .ehlo()')
smtp_connection.ehlo()
if not conf.SMTP_SKIP_LOGIN:
failedAt = print_log('SMTP_SKIP_LOGIN == False so sending .login()')
smtp_connection.login (conf.SMTP_USER, conf.SMTP_PASS)
failedAt = print_log('Sending .sendmail()')
smtp_connection.sendmail (conf.REPORT_FROM, conf.REPORT_TO, msg.as_string())
smtp_connection.quit()
except smtplib.SMTPAuthenticationError as e:
mylog('none', [' ERROR: Failed at - ', failedAt])
mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPAuthenticationError), skipping Email (enable LOG_LEVEL=debug for more logging)'])
mylog('none', [' ERROR: ', str(e)])
except smtplib.SMTPServerDisconnected as e:
mylog('none', [' ERROR: Failed at - ', failedAt])
mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPServerDisconnected), skipping Email (enable LOG_LEVEL=debug for more logging)'])
mylog('none', [' ERROR: ', str(e)])
except socket.gaierror as e:
mylog('none', [' ERROR: Failed at - ', failedAt])
mylog('none', [' ERROR: Could not resolve hostname (socket.gaierror), skipping Email (enable LOG_LEVEL=debug for more logging)'])
mylog('none', [' ERROR: ', str(e)])
mylog('debug', '[Send Email] Last executed - ' + str(failedAt))

View File

@@ -24,8 +24,6 @@ from const import pialertPath, logPath, apiPath
from helper import noti_obj, generate_mac_links, removeDuplicateNewLines, timeNowTZ, hide_email, updateState, get_file_content, write_file
from logger import logResult, mylog, print_log
from publishers.email import (check_config as email_check_config,
send as send_email )
from publishers.ntfy import (check_config as ntfy_check_config,
send as send_ntfy )
from publishers.webhook import (check_config as webhook_check_config,