Make mail stack optional for Infinito.Nexus deployments without Mailu (e.g. Raspberry Pi / robots)

Refactored mail-related roles to support running Infinito.Nexus on nodes without a dedicated mail server:
- Introduced sys-svc-mail as central mail orchestration role.
- Split msmtp handling into sys-svc-mail-msmtp.
- Added sys-svc-mail-smtp to provide a localhost-only Postfix relay when Mailu is not present.
- Updated alert/health roles to use the new mail orchestration.
- Avoid installing postfix inside containers via IS_CONTAINER guard.
- Adjusted WordPress role to use the new msmtp template path.

This allows lightweight deployments (e.g. Raspberry Pi, robots, edge nodes) to send mail via localhost without requiring a full Mailu stack.

ChatGPT discussion: https://chatgpt.com/share/6931edf1-cb98-800f-9e3c-a62d69ccb223
This commit is contained in:
2025-12-04 21:24:53 +01:00
parent d0aac64c67
commit 8e4ee723d7
22 changed files with 368 additions and 93 deletions

View File

@@ -0,0 +1,69 @@
# sys-svc-mail 📧
## Description
The `sys-svc-mail` role acts as the **central mail orchestration layer** in the Infinito.Nexus stack.
It wires together:
- [Mailu](https://mailu.io/) as a full-featured mail server (when available),
- [msmtp](https://marlam.de/msmtp/) as a lightweight sendmail-compatible SMTP client, and
- an optional local SMTP relay (Postfix) for hosts **without** Mailu.
For more background on the underlying protocol, see [Simple Mail Transfer Protocol (SMTP) on Wikipedia](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol).
## Overview
This role provides a **unified mail setup** for your hosts:
- If the host is part of the `web-app-mailu` group, it:
- checks the reachability of the Mailu endpoint,
- triggers Mailu startup via the Infinito.Nexus helper (`utils/load_app.yml`),
- and prepares the system to send emails through Mailu using the `sys-svc-mail-msmtp` role.
- If the host is **not** running Mailu, it:
- optionally configures a local SMTP relay via `sys-svc-mail-smtp` (Postfix on `localhost:25`),
- and still configures `msmtp` as a sendmail-compatible client.
This makes `sys-svc-mail` the canonical entrypoint for “mail capabilities” on a node, abstracting away whether the actual delivery happens via Mailu or a local relay.
## Purpose
The main purpose of this role is to:
- Provide a **consistent mail-sending interface** for all hosts in the Infinito.Nexus ecosystem.
- Automatically choose between:
- **Mailu-backed delivery** (with authentication tokens), or
- a **local SMTP relay on localhost**,
depending on the presence of `web-app-mailu` in the hosts groups.
- Ensure that system services and applications can always send notifications (e.g. health checks, alerts, job results) without each role having to care about the underlying mail plumbing.
## Features
- 🔄 **Mailu Integration (when available)**
- Checks Mailu reachability using Ansibles `uri` module.
- Triggers Mailu startup via `utils/load_app.yml`.
- Ensures handlers are flushed/reset via `utils/load_handlers.yml`.
- 💡 **Smart Fallback to Localhost**
- If no `web-app-mailu` is present, the role can configure a local Postfix-based SMTP relay via `sys-svc-mail-smtp`.
- Combined with `sys-svc-mail-msmtp`, this enables sending mail via `localhost:25` without additional configuration in other roles.
- 📨 **msmtp Client Configuration**
- Delegates installation and configuration of msmtp to `sys-svc-mail-msmtp`.
- Supports both authenticated Mailu delivery and unauthenticated localhost-based delivery.
- 🧩 **Composable Design**
- Uses internal `run_once_*` flags to avoid repeated setup.
- Cleanly integrates with the Infinito.Nexus stack and shared utilities.
## Further Resources
- Mail server:
- Mailu: <https://mailu.io/>
- SMTP (protocol): <https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol>
- SMTP client:
- msmtp: <https://marlam.de/msmtp/>
- msmtp on Wikipedia: <https://en.wikipedia.org/wiki/Msmtp>
- Infinito.Nexus:
- Main repository: <https://s.infinito.nexus/code>
- Documentation: <https://docs.infinito.nexus>

View File

@@ -0,0 +1,30 @@
---
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Central mail orchestration role for Infinito.Nexus, integrating Mailu, msmtp, and an optional local SMTP relay."
license: "Infinito.Nexus NonCommercial License"
license_url: "https://s.infinito.nexus/license"
company: |
Kevin Veen-Birkenbach
Consulting & Coaching Solutions
https://www.veen.world
min_ansible_version: "2.9"
platforms:
- name: Archlinux
versions:
- rolling
galaxy_tags:
- email
- smtp
- msmtp
- postfix
- automation
- monitoring
- archlinux
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://docs.infinito.nexus"
logo:
class: ""
run_after: []
dependencies: []

View File

@@ -0,0 +1,42 @@
- include_tasks: utils/once/flag.yml
- block:
- name: "Check if Mail Host is reachable"
uri:
url: "{{ WEB_PROTOCOL }}://{{ SYSTEM_EMAIL.HOST }}"
method: HEAD
validate_certs: yes
status_code: 200
register: mail_host_reachability
failed_when: false
changed_when: false
when:
- run_once_web_app_mailu is not defined
- SYSTEM_EMAIL.HOST == (domains | get_domain('web-app-mailu'))
- name: "Load Mailu Routines for '{{ role_name }}'"
include_tasks: 02_mailu.yml
when:
- >
(
mail_host_reachability is defined and
(mail_host_reachability.status | default(0) | int) != 200
)
or
(
users.get('no-reply', {}).get('mailu_token', '') | length == 0
)
when: "'web-app-mailu' in group_names"
- name: Setup emails via localhost
include_role:
name: sys-svc-mail-smtp
when:
- run_once_sys_svc_mail_smtp is not defined
- "'web-app-mailu' not in group_names"
- name: Setup msmtp client
include_role:
name: sys-svc-mail-msmtp
when:
- run_once_sys_svc_mail_msmtp is not defined

View File

@@ -0,0 +1,9 @@
- name: "Load Mailu before MSMTP config, to guaranty that server is up"
include_tasks: "utils/load_app.yml"
vars:
load_app_id: web-app-mailu
- name: "Reset compose handlers after Mailu include for MSMTP"
include_tasks: utils/load_handlers.yml
vars:
handler_role_name: "docker-compose"

View File

@@ -0,0 +1,3 @@
- name: "Load Mail (once)"
include_tasks: 01_core.yml
when: not (run_once_sys_svc_mail | default(false) | bool)