# nuzantara-send-email **Per:** Claude Code, Gemini CLI, OpenClaw **Versione:** 1.0.0 **Attivazione:** quando si deve inviare email, configurare email, debug email, o lavorare su servizi che mandano email --- ## Quick Reference ### Inviare una email ```bash # Via MCP tool (modo più semplice) mcp__nuzantara-mcp__send_email(to="dest@email.com", subject="Oggetto", body="
HTML body
") # Via curl (da script/cron) curl -X POST https://nuzantara-rag.fly.dev/api/notifications/send-email \ -H "X-API-Key: REDACTED-ROTATED-KEY" \ -H "Content-Type: application/json" \ -d '{"to":"dest@email.com","subject":"Oggetto","body":"HTML body
"}' # Con CC -d '{"to":"dest@email.com","subject":"Oggetto","body":"Body
","cc":"cc1@email.com,cc2@email.com"}' ``` ### Routing automatico (non devi scegliere) | Destinatario | Canale primario | Fallback | Perché | | --------------- | --------------- | --------- | ---------------------------------------------------------------- | | `@balizero.com` | Zoho SMTP | Brevo | Zoho rifiuta email intra-dominio da Brevo (554 policy violation) | | Tutti gli altri | Brevo HTTP API | Zoho SMTP | Brevo ha migliore deliverability e tracking | **Sender sempre:** `zantara@balizero.com` (alias di `damar@balizero.com` in Zoho Mail) **Display name:** "Zantara" --- ## Architettura ### Endpoint centrale `POST /api/notifications/send-email` — **UNICO punto di invio.** Tutti i servizi CRM lo usano. File: `backend/app/modules/notifications/router.py` ### Provider 1. **Brevo** (ex SendGrid/Sendinblue) - API key: `SENDGRID_API_KEY` (inizia con `xkeysib-`) - URL: `https://api.brevo.com/v3/smtp/email` - Account: `zero@balizero.com`, free plan, 300 email/giorno - Dominio `balizero.com` autenticato (DKIM + DMARC + SPF) 2. **Zoho SMTP** - Host: `smtppro.zoho.com:587` (STARTTLS) - User: `zero@balizero.com` - Password: App Password in `ZOHO_SMTP_PASSWORD` (NON la password di login) - Può mandare come `zantara@balizero.com` (alias configurato in Zoho Mail) 3. **Zoho OAuth** (per ZohoEmailService — usato da invoice con allegati) - Self Client ID: `1000.PRPSP7KG3NZU9KYCVMZHGSGFXYSJMZ` - Tokens in tabella `zoho_email_tokens` - Se scade: api-console.zoho.com → Self Client → genera code → scambia via API --- ## Email automatiche attive ### Trigger da cambio status practice (in `crm_practices.py`) | Status | Email | Destinatario | Servizio | | --------------------- | ------------------- | --------------------- | ---------------------------- | | → `waiting_documents` | Richiesta documenti | Cliente + Team leader | WaitingDocumentsService | | → `sending_invoice` | Invoice PDF | Cliente + Asya | InvoiceAutomationService | | → `on_process` | Conferma inizio | Cliente + Team leader | ProcessAutomationService | | → `completed` | Congratulazioni | Cliente + Team leader | CompletedProcessService | | → `completed` | HR Bonus pending | asya@balizero.com | `_notify_hr_bonus_pending()` | ### Trigger da creazione | Evento | Email | Destinatario | Note | | -------------- | ------------------- | ------------ | ---------------------------------------------------------------------- | | Nuovo cliente | Welcome email | Cliente | 30min delay (APScheduler) — **ATTENZIONE: non funziona con auto_stop** | | Nuova practice | Kickoff + checklist | Cliente | Immediata via BackgroundTasks | ### Cron notifiers ```bash # Tutti e 3 insieme curl -X POST https://nuzantara-rag.fly.dev/api/cron/notifiers/all \ -H "X-API-Key: REDACTED-ROTATED-KEY" # Singoli /api/cron/notifiers/visa-expiry # Scadenze visa/KITAS/passaporto → team leader + zero@ /api/cron/notifiers/unpaid-invoices # Fatture non pagate 7+ giorni → asya@ /api/cron/notifiers/stale-practices # Pratiche ferme 7+ giorni → team leader + zero@ ``` --- ## Regole IMPORTANTI 1. **MAI mandare email direttamente** — usa sempre l'endpoint `/api/notifications/send-email` o il MCP tool `send_email` 2. **MAI usare `SendGridProvider` direttamente** — la key è Brevo, non SendGrid. L'endpoint gestisce tutto 3. **Sender SEMPRE `zantara@balizero.com`** — mai `zero@`, `nuzantara@`, `notifications@` 4. **HTML nel body** — l'endpoint accetta HTML. `\n` viene convertito in `