nis2-agile/docs/STANDARD_EMAIL_RELAY.md
DevEnv nis2-agile c0bf7b6c15 [DOCS] Standard cross-suite AgileHub + governance CLAUDE.md + registri agent
- CLAUDE.md: TZ, SSO, vault-steward, versioning, persona v2.0, multitenant, KB RAG
- docs/standards: persona-conversational-rules v2.0
- docs/STANDARD_*: installer-integration, email-relay, AI-prodotto, marketing-tenant, multitenant
- AGENT_CHANGES.md + OPEN_TICKETS.md (registri agent automatico)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 15:41:54 +02:00

11 KiB

STANDARD AgileHub — Email Relay centralizzato (canonico)

Autorità: AgileHub (single source of truth per la suite Agile Software). Versione: 1.0 — 2026-04-21 Stato: ADOTTATO. Vincolante per tutti i prodotti della suite. Destinatari: team TRPG, SustainAI, NIS2, TAXAI (AllTax), LG231, DFM, MKTG, ALLRISK, WMS, MADEBYCLOUD, CertiSource. Registry DB: record master in nexus_hub.hub_standards (slug=email-relay, version=1.0).


1. Principio

Tutte le email generate dalla suite AgileHub passano da UN SOLO punto: il microservizio email-automation-ms (PM2 id 21, porta 4004).

Nessun prodotto, microservizio, container DevEnv, cron o agent AI può accedere direttamente a:

  • Postfix host Hetzner (172.18.0.1:25)
  • Server Gmail (smtp-relay.gmail.com, smtp.gmail.com)
  • Altri provider SMTP (SendGrid, Mailgun, AWS SES, ecc.)

2. Architettura

┌──────────────────┐    HTTPS + X-Internal-Key
│ Prodotto cliente │──────────────┐
│ (TRPG/SustAI...) │              │
└──────────────────┘              ▼
                         ┌──────────────────────┐
┌──────────────────┐     │ email-automation-ms  │      SMTP (internal)
│ Microservizio    │────▶│   porta 4004         │──────────┐
│ AgileHub         │     │                      │          ▼
│ (ticket/lead/..) │     │ Rate limit + Template│   ┌──────────────┐
└──────────────────┘     │ Audit DB + Retry     │   │ Postfix host │
                         └──────────────────────┘   │ 172.18.0.1:25│
                                                    └──────┬───────┘
                                                           │ SASL auth
                                                           ▼
                                                    ┌──────────────┐
                                                    │ Gmail        │
                                                    │ smtp-relay   │
                                                    │ .gmail.com   │
                                                    └──────────────┘

Relay chain:

  • Prodotto → email-automation-ms:4004 (via Apache vhost agilehub.agile.software/api/emails/*)
  • email-automation-ms → Postfix 172.18.0.1:25 (container→host, senza auth perché mynetworks include 172.18.0.0/16)
  • Postfix → Gmail SMTP relay :587 (richiede SASL auth service-account Workspace)

3. Contratto API

Endpoint canonico

POST https://agilehub.agile.software/api/emails/send
Headers:
  X-Internal-Key: <INTERNAL_EMAIL_KEY>       (shared via /etc/agilehub/internal-keys.env)
  Content-Type: application/json

Body:
{
  "to": "user@example.com",                  // string o array
  "from_tenant_id": 5,                        // int — attribuzione log
  "template": "demo-registration-verify",     // nome template in email-automation-ms/templates/
  "variables": { "name": "Mario", ... },      // placeholder per il template
  "product": "TRPG",                          // slug prodotto (audit)
  "reply_to": "support@trpg.agile.software",  // opzionale
  "priority": "transactional"                 // "transactional" | "marketing" | "system"
}

Response

{
  "success": true,
  "message_id": "<agilehub-7c3f-20260421@smtp-relay.gmail.com>",
  "queued_at": "2026-04-21T15:30:00.000Z"
}

Log audit

Ogni invio viene registrato in nexus_email_db.email_log:

  • id, message_id, to, from, subject, template, product, tenant_id, status, sent_at, smtp_response, retry_count

Status delivery

  • queued — accettato dal service, in coda retry
  • sent — accettato dal Postfix host (risposta 250 OK)
  • delivered — accettato dal Gmail relay (webhook o check log mail.log)
  • bounced — Gmail ha rifiutato (bad recipient, spam, auth failure)
  • failed_permanent — 5xx, no retry
  • failed_transient — 4xx, retry backoff (max 3)

4. VIETATO

Qualsiasi alternativa al percorso email-automation-ms. In particolare:

Connessione SMTP diretta a 172.18.0.1:25 da container prodotto o DevEnv. Provider cloud (SendGrid, Mailgun, SES, Postmark) — se necessari, integrarli DENTRO email-automation-ms come alternative transport. Librerie SMTP client in codice prodotto:

  • JS: nodemailer, emailjs, smtp-connection
  • PHP: PHPMailer, Swift_Mailer, mail() built-in, mb_send_mail()
  • Python: smtplib usato con credenziali cleartext
  • Ruby, Go, ecc.: equivalenti Binari di sistema in container: sendmail, mail, mutt, msmtp. File .env con SMTP_* in qualsiasi servizio diverso da email-automation-ms.

Deroghe

Solo via ticket AgileHub tag email-bypass-exception. Motivazioni accettabili:

  • Integrazione legacy in dismissione con data di fine (es. mktg-agile oggi)
  • Volume massimo > 100k/mese che giustifica provider dedicato (richiede integrazione in email-automation-ms, non bypass)
  • Test E2E isolati (usa container mailpit dedicato, non produzione)

Deroghe hanno scadenza obbligatoria (max 90gg). AgileHub tiene registro in nexus_hub.hub_standards_adoption.exemption_reason/exemption_expires_at.


5. Come integrare

Lato prodotto (TRPG, SustainAI, ecc.)

  1. Rimuovere ogni SMTP_* dal .env del prodotto
  2. Aggiungere INTERNAL_EMAIL_KEY=<value> al .env (coordinato con team AgileHub)
  3. Sostituire chiamate dirette con curl/fetch/requests verso https://agilehub.agile.software/api/emails/send
  4. Rimuovere dipendenze SMTP (nodemailer, PHPMailer, ecc.) dal manifest (package.json, composer.json)

Lato AgileHub

  1. email-automation-ms espone /send + /templates/list + /webhooks/bounce
  2. Gestisce rate limit per tenant (nexus_email_db.email_quota)
  3. Tiene in vita la connessione SMTP a Postfix (connection pool)
  4. Retry exponential backoff su 4xx (1min, 5min, 30min), drop su 5xx
  5. Webhook bounce da Gmail (future) → aggiorna status=bounced + notifica tenant admin

6. Stato attuale (2026-04-22 — FIX APPLICATO)

Operativo end-to-end

  • Architettura centralizzata implementata e funzionante
  • IP allowlist Workspace attiva per 135.181.149.254 (configurata da Massimo Tagliavini)
  • sendmail locale: funziona (cron watchdog, claude-auth-check, ticket-agent)
  • email-automation-ms canonical path: funziona dopo fix 2026-04-22
  • Endpoint protetti da X-Internal-Key (auth middleware aggiunto)
  • Env vars propagate in /etc/agilehub/internal-keys.env + .env di 5 prodotti produzione

Fix applicato al transport Nodemailer

File: email-automation-ms/src/services/emailService.js:25-40

transporter = nodemailer.createTransport({
  host,     // da SMTP_HOST=127.0.0.1 (era 172.18.0.1)
  port,
  secure,
  name: process.env.SMTP_HELO_NAME || 'agile.software', // HELO esplicito
  ...
});

File: email-automation-ms/.env

SMTP_HOST=127.0.0.1   # era 172.18.0.1 (docker bridge) → Postfix vedeva connessione "esterna"
INTERNAL_SERVICE_KEY=nexus-internal-2026  # alias INTERNAL_EMAIL_KEY

Auth endpoint

File: email-automation-ms/src/index.js:27-55 — middleware requireInternalKey:

  • Protegge: /emails/send, /emails/send-raw, /sequences/*, /emails/templates/db (POST/PUT/DELETE)
  • Legge la chiave da INTERNAL_EMAIL_KEY (preferita) o INTERNAL_SERVICE_KEY (retrocompat cron)
  • Senza header → 401 UNAUTHORIZED
  • Con header valido → passa al controller
  • Se nessuna chiave configurata → warn + pass (fallback legacy)

Test E2E superati (2026-04-22)

Test Risultato
POST /emails/send-raw senza X-Internal-Key 401
POST /emails/send-raw con X-Internal-Key (locale) 201 + messageId + SENT in DB
POST HTTPS https://agilehub.agile.software/api/emails/send-raw da container TRPG 201 + SENT in DB, product=TRPG
Consegna su Gmail 250 2.0.0 OK via smtp-relay.gmail.com:587 confermato in /var/log/mail.log

Bypass noti

  • /var/www/mktg-agile/.env contiene ancora SMTP_* — tollerato perché prodotto in dismissione Fase C (spegnimento 2026-04-21+)

7. Obblighi prodotti della suite

Per essere conforme a email-relay v1.0 ogni prodotto DEVE:

  1. Rimuovere ogni SMTP_*, credenziali Gmail, API key mailer-cloud dal proprio .env
  2. Eliminare dipendenze mailer (nodemailer, PHPMailer, ecc.) dal manifest
  3. Sostituire ogni invio con POST verso https://agilehub.agile.software/api/emails/send
  4. Ottenere INTERNAL_EMAIL_KEY da AgileHub team (via ticket tag email-key-provision)
  5. Aggiungere INTERNAL_EMAIL_KEY al .env istanza con chmod 600
  6. Usare template definiti in email-automation-ms/templates/ (aprire PR per nuovi template)
  7. Loggare message_id ricevuto nella response per debug

Un prodotto non conforme entra in pending adoption nel registry. Deroghe formali con scadenza obbligatoria.


8. Riferimenti

  • Microservizio: /var/www/agile-services/email-automation-ms/ (Hetzner) + /projects/agile-services/email-automation-ms/ (container)
  • Entry point: email-automation-ms/src/index.js:45 (SMTP transport config)
  • Template repo: email-automation-ms/templates/ (Handlebars-like .hbs)
  • Log DB: nexus_email_db.email_log (MySQL host Hetzner)
  • Postfix config: /etc/postfix/main.cf (Hetzner host)
  • Gmail Workspace Admin Console: account admin@agile.software

9. Changelog

v1.2 — 2026-04-22 (fix applicato — operativo)

  • Fix transport Nodemailer: SMTP_HOST=127.0.0.1 (era 172.18.0.1 docker bridge) + name: 'agile.software' HELO esplicito
  • Aggiunto middleware requireInternalKey su /emails/send*, /sequences/*, /emails/templates/db mutazioni — chiave INTERNAL_SERVICE_KEY=nexus-internal-2026 (alias INTERNAL_EMAIL_KEY)
  • Registrato INTERNAL_EMAIL_KEY in /etc/agilehub/internal-keys.env
  • Propagato INTERNAL_EMAIL_KEY + EMAIL_MS_URL al .env di 5 prodotti produzione (trpg-agile, sustainai-agile, nis2-agile, mktg-agile, allrisk-agile). Altri 5 prodotti (trpg-pro-agile, taxai-agile, lg231-agile, dfm-pro-agile, wms-agile) non hanno .env in produzione — useranno la registry centrale.
  • Test E2E passati: invio da container TRPG via HTTPS verso agilehub.agile.software/api/emails/send-raw → consegnato Gmail 250 OK.

v1.1 — 2026-04-22 (correzione narrativa, pre-fix)

  • Correzione narrativa sezione 6: SMTP NON è bloccato. Il path sendmail funziona (Massimo ha configurato IP allowlist da tempo). Il bug reale era in email-automation-ms transport.
  • Rimosso "fix A/B Postfix SASL" (errore di analisi del 2026-04-21 — non serviva).

v1.0 — 2026-04-21

  • Versione iniziale — formalizza architettura esistente
  • Distribuita a 11 prodotti suite via DB registry hub_standards
  • Richiesta conformità prodotti: rimuovere SMTP diretti dove presenti

Firma autorità: AgileHub. Violazioni vanno in hub_standards_distribution_log con result='non_compliant'.