Generate email content from ninja2 templates

This commit is contained in:
2026-01-22 20:23:13 +01:00
parent 453ef1ba80
commit f879532755
7 changed files with 129 additions and 35 deletions

View File

@@ -5,6 +5,28 @@ import smtplib
from . import datetime_str
from email.mime.text import MIMEText
from jinja2 import Environment, BaseLoader
def load_template(path):
"""
Load template from file.
Args:
path: Path to template.
Returns:
Template if path was not None, None otherwise.
"""
if path is None:
return
with open(path) as fh:
data = fh.read()
return Environment(
loader=BaseLoader(),
trim_blocks=True
).from_string(data)
class EmailService:
@@ -20,6 +42,13 @@ class EmailService:
self.config = config.get("email", {})
self.enabled = self.config.get("enabled", False)
self.change_template = load_template(self.config.get("change_notification_template", None))
self.expiry_template = load_template(self.config.get("expiry_notification_template", None))
if not self.change_template and not self.expiry_template and self.enabled:
logging.warning("No templates configured, disabling Email")
self.enabled = False
def send(self, to, subject, body):
"""
Send email using configured SMTP server.
@@ -65,15 +94,58 @@ class EmailService:
logging.error(f"Email send failed: to={to} error={e}")
return False
def send_changed_notification(
self,
email,
hostname,
ipv4_changed,
ipv6_changed
):
"""
Send hostname changed notification email.
Args:
email: Recipient email.
hostname: Changed hostname.
ipv4_changed: Wheter IPv4 address changed.
ipv6_changed: Wheter IPv6 address changed.
Returns:
True if sent successfully.
"""
if not self.enabled:
logging.debug("Email disabled, skipping")
return False
if not self.change_template:
logging.debug("No change notification template configured, skipping")
return False
fqdn = f"{hostname.hostname}.{hostname.zone}"
template_variables = {
"hostname": hostname.hostname,
"zone": hostname.zone,
"fqdn": fqdn,
"ipv4_changed": ipv4_changed,
"ipv4": hostname.last_ipv4,
"last_ipv4_update": datetime_str(hostname.last_ipv4_update),
"ipv6_changed": ipv6_changed,
"ipv6": hostname.last_ipv6,
"last_ipv6_update": datetime_str(hostname.last_ipv6_update),
"expiry_ttl": hostname.expiry_ttl,
}
subject = f"DDNS hostname expired: {fqdn}"
body = self.expiry_template.render(**template_variables)
return self.send(email, subject, body)
def send_expiry_notification(
self,
email,
hostname,
last_ipv4,
last_ipv4_update,
last_ipv6,
last_ipv6_update,
expiry_ttl
ipv4_expired,
ipv6_expired
):
"""
Send hostname expiry notification email.
@@ -81,27 +153,35 @@ class EmailService:
Args:
email: Recipient email.
hostname: Expired hostname.
last_ipv4: Tuple containing last IPv4 address and last update timestamp.
last_ipv6: Tuple containing last IPv6 address and last update timestamp.
expiry_ttl: Expiry TTL in seconds.
ipv4_expired: Wheter IPv4 address expired.
ipv6_expired: Wheter IPv6 address expired.
Returns:
True if sent successfully.
"""
if not self.enabled:
logging.debug("Email disabled, skipping")
return False
expired = ""
if last_ipv4 and last_ipv4_update:
expired += f"IPv4 address: {last_ipv4} (last update: {last_ipv4_update})\n"
if last_ipv6 and last_ipv6_update:
expired += f"IPv6 address: {last_ipv6} (last update: {last_ipv6_update})\n"
if not self.expiry_template:
logging.debug("No expiry notification template configured, skipping")
return False
subject = f"DDNS hostname expired: {hostname}"
body = f"""Your dynamic DNS entry has expired due to inactivity.
fqdn = f"{hostname.hostname}.{hostname.zone}"
template_variables = {
"hostname": hostname.hostname,
"zone": hostname.zone,
"fqdn": fqdn,
"ipv4_expired": ipv4_expired,
"last_ipv4": hostname.last_ipv4,
"last_ipv4_update": datetime_str(hostname.last_ipv4_update),
"ipv6_expired": ipv6_expired,
"last_ipv6": hostname.last_ipv6,
"last_ipv6_update": datetime_str(hostname.last_ipv6_update),
"expiry_ttl": hostname.expiry_ttl,
}
Hostname: {hostname}
{expired}
Expiry TTL: {expiry_ttl} seconds
subject = f"DDNS hostname expired: {fqdn}"
body = self.expiry_template.render(**template_variables)
The DNS records have been removed. Update your client to restore them.
"""
return self.send(email, subject, body)