- 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>
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 vhostagilehub.agile.software/api/emails/*) email-automation-ms→ Postfix172.18.0.1:25(container→host, senza auth perchémynetworksinclude172.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 retrysent— 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 retryfailed_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:
smtplibusato con credenziali cleartext - Ruby, Go, ecc.: equivalenti
❌ Binari di sistema in container:
sendmail,mail,mutt,msmtp. ❌ File .env conSMTP_*in qualsiasi servizio diverso daemail-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.)
- Rimuovere ogni
SMTP_*dal.envdel prodotto - Aggiungere
INTERNAL_EMAIL_KEY=<value>al.env(coordinato con team AgileHub) - Sostituire chiamate dirette con
curl/fetch/requestsversohttps://agilehub.agile.software/api/emails/send - Rimuovere dipendenze SMTP (
nodemailer,PHPMailer, ecc.) dal manifest (package.json,composer.json)
Lato AgileHub
email-automation-msespone/send+/templates/list+/webhooks/bounce- Gestisce rate limit per tenant (
nexus_email_db.email_quota) - Tiene in vita la connessione SMTP a Postfix (connection pool)
- Retry exponential backoff su 4xx (1min, 5min, 30min), drop su 5xx
- 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) sendmaillocale: funziona (cron watchdog, claude-auth-check, ticket-agent)email-automation-mscanonical 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+.envdi 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) oINTERNAL_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/.envcontiene ancoraSMTP_*— 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:
- ✅ Rimuovere ogni
SMTP_*, credenziali Gmail, API key mailer-cloud dal proprio.env - ✅ Eliminare dipendenze mailer (nodemailer, PHPMailer, ecc.) dal manifest
- ✅ Sostituire ogni invio con POST verso
https://agilehub.agile.software/api/emails/send - ✅ Ottenere
INTERNAL_EMAIL_KEYda AgileHub team (via ticket tagemail-key-provision) - ✅ Aggiungere
INTERNAL_EMAIL_KEYal.envistanza con chmod 600 - ✅ Usare template definiti in
email-automation-ms/templates/(aprire PR per nuovi template) - ✅ Loggare
message_idricevuto 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(era172.18.0.1docker bridge) +name: 'agile.software'HELO esplicito - Aggiunto middleware
requireInternalKeysu/emails/send*,/sequences/*,/emails/templates/dbmutazioni — chiaveINTERNAL_SERVICE_KEY=nexus-internal-2026(aliasINTERNAL_EMAIL_KEY) - Registrato
INTERNAL_EMAIL_KEYin/etc/agilehub/internal-keys.env - Propagato
INTERNAL_EMAIL_KEY+EMAIL_MS_URLal.envdi 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.envin 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
sendmailfunziona (Massimo ha configurato IP allowlist da tempo). Il bug reale era inemail-automation-mstransport. - 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'.