# Email nel codice: rendile visibili, migrale e migliorale

URL canonico: https://brew.new/it/blog/emails-in-code-visibility-migration-mcp
Autore: Thomas Park
Pubblicato: 2026-10-12
Aggiornato: 2026-10-15

Le email nel codice sono email di prodotto definite nel tuo codebase e rilasciate come qualsiasi altra funzionalità. In un team che lavora con Resend e React Email, se chiedi quali email invia il prodotto, segue un attimo di silenzio. L’email di benvenuto è un componente in `emails/`. La reimpostazione della password sta nella dashboard del provider di autenticazione. L’email di fine prova è una stringa in un cron job. La ricevuta la invia Stripe. Nessuno ricorda cosa invii l’email “Ci manchi”.

Ogni email è stata facile da rilasciare, quindi nessuno ha il quadro completo. Noi risolveremmo il problema in quest’ordine: prima la visibilità, poi la migrazione, poi il miglioramento. Gran parte del lavoro può farla l’agente di coding che usi già, collegato a Brew tramite MCP.

## Punti chiave

- Parti da un inventario, non da un nuovo strumento: ogni email, il suo trigger, il suo file e le sue variabili.
- Un agente di coding può trovare le chiamate di invio, renderizzare ogni modello e importarlo con lo strumento MCP `import_email`. L’importazione è deterministica, non usa l’IA ed è gratuita.
- Le email importate finiscono su un canvas per ogni gruppo, così il team le rivede fianco a fianco, su desktop e su mobile.
- Per la migrazione, un invio in stile Resend diventa un trigger più un’automazione pubblicata, attivata con una sola chiamata REST. Il codice di produzione usa REST, non MCP.
- Sposta un tipo di email alla volta dietro un flag, e sposta per ultime le email transazionali.

## Perché le email definite nel codice diventano invisibili

React Email e Resend hanno migliorato di molto le email per gli sviluppatori: componenti tipizzati, revisionati nelle pull request. Il conto arriva dopo.

**Le email sono sparse.** Componenti, HTML inline in un job in background, modelli nella dashboard di un servizio esterno, email che un altro servizio invia per te. Nessun file le elenca tutte.

**Le anteprime non sono la produzione.** Il server di anteprima di React Email mostra un modello con le sue props di anteprima, non quello che ha ricevuto un cliente, e niente degli altri modelli.

**Solo gli sviluppatori possono vederle.** Prodotto, design e supporto dovrebbero chiedere a uno sviluppatore di avviare il progetto, quindi quasi sempre rinunciano.

**Dopo il lancio nessuno le rivede.** L’email di due anni fa ha ancora il vecchio logo e un piano che non vendi più. Nessuno se ne accorge, perché nessuno le vede tutte insieme.

## Passaggio 1: visibilità

L’obiettivo è una vista condivisa di tutte le email. Niente di quello che segue tocca la produzione.

![Le tre fasi per portare le email fuori dal codice: visibilità con import_email e un canvas per gruppo, migrazione con domini, contatti, trigger e automazioni, e ottimizzazione con audit, test di rendering e statistiche.](/images/blog/emails-in-code-three-phases.png)

*Ogni fase è utile anche da sola, e puoi fermarti dopo una qualsiasi.*

### Collega a Brew il tuo agente di coding

Il server MCP di Brew si trova all’indirizzo `https://brew.new/api/mcp` e usa OAuth: accedi con Brew e scegli il brand in cui l’agente può lavorare. In Claude Code:

```bash
claude mcp add --transport http brew "https://brew.new/api/mcp"
```

Il comando salva il server solo nella configurazione locale di questo progetto. Per usarlo in tutti i progetti, aggiungi `--scope user`. Prima di usarne gli strumenti, esegui `claude mcp login brew` oppure apri `/mcp` e autentica il collegamento a Brew.

La [documentazione sulla configurazione dei client](https://docs.brew.new/api-reference/mcp/connect-your-client) ha sezioni dedicate a Cursor e Codex. I client senza OAuth possono usare una chiave API limitata al brand. Poi fai richiamare all’agente `get_brew_capabilities`, così legge l’elenco aggiornato degli strumenti invece di tirare a indovinare.

### Crea l’inventario

Chiedi all’agente un elenco:

```text
Find every email this codebase sends. Search for provider calls
(resend.emails.send, postmark, sendgrid, nodemailer, SES), React Email
components and render() calls, and any email templates referenced from
config or a third-party dashboard.

For each email, record: a name, what triggers it, the file and line that
sends it, the template file, the provider, and the variables it uses.
Write the result as a table in EMAILS.md. List anything you could not
resolve under "Unknown" instead of guessing.
```

Tieni la sezione “Unknown”, quella delle email non identificate. Le conferme di autenticazione e le ricevute di Stripe non sono chiamate di invio nel tuo codice, ma devono stare nell’elenco. Fai il commit di `EMAILS.md`. Anche se ti fermi qui, hai un elenco che ieri non avevi.

### Renderizza ogni modello con dati realistici

Il miglior input per l’importazione è l’HTML che il tuo codice produce già. L’[utility render](https://react.email/docs/utilities/render) di React Email ti restituisce quella stringa:

```tsx
import { render } from 'react-email'
import WelcomeEmail from './emails/welcome'

const html = await render(
  <WelcomeEmail firstName="Ana" planName="Pro" trialDays={14} />
)
```

I progetti meno recenti importano `render` da `@react-email/render`. Usa dati di esempio realistici, non `"test"`, perché il tuo team rivedrà queste email. Fai scrivere all’agente uno script che renderizzi ogni modello in un file.

Brew importa anche direttamente un modulo React Email con `format: "jsx"`, leggendolo in modo statico senza eseguirlo. Le props prendono i valori predefiniti o quelli di `PreviewProps`, i componenti importati da altri file locali vengono scartati o rifiutati, e `await` e costrutti simili non sono accettati. Se il modello non sta in un unico file autosufficiente, usa l’HTML renderizzato.

### Importa tutto in un unico posto

Poi importa ogni render con `import_email`, con un `groupName` per ogni area del prodotto:

```text
For each rendered email in ./email-renders, call import_email with
format "html", the title and subject line from EMAILS.md, and a
groupName by area: "Auth", "Onboarding", "Billing" or "Lifecycle".
Report the emailId for each one and any warnings in its assetReport.
```

Gli sviluppatori si chiedono, giustamente, se l’importazione riscrive le loro email. Non lo fa:

- È un compilatore deterministico, non un modello di IA, e non consuma crediti.
- Produce un design di Brew modificabile, mentre al momento dell’invio viene mantenuto l’HTML sorgente originale per le righe importate.
- Copia le immagini pubbliche sull’hosting di Brew, e `assetReport` elenca quelle che non è riuscito a recuperare.
- Rimuove script, iframe, moduli e gestori di eventi, e neutralizza i pixel di tracciamento delle aperture già presenti.
- Ogni sorgente può arrivare a 5 MB. Non si può passare un URL: lo strumento riceve direttamente il markup, e `baseUrl` serve solo a risolvere i percorsi relativi delle immagini.

### Rivedi le email con il team

Ogni gruppo ha il suo canvas. Apri `brew.new/emails/onboarding` e trovi l’intera sequenza fianco a fianco, con un selettore desktop/mobile e i commenti su ogni design. I link al canvas funzionano per chi ha effettuato l’accesso al tuo workspace di Brew. Non esiste un link di condivisione pubblico, quindi invita i tuoi revisori.

È qui che emergono i problemi: due loghi, un pulsante con un link rotto, tre footer. Esegui `audit_email` prima di correggere qualsiasi cosa. Controlla link, immagini, conformità, dimensione caricata, supporto dei client, accessibilità e testi, costa 5 crediti per ogni audit completo e accetta un `emailId` salvato o HTML grezzo, quindi puoi fare l’audit anche delle email che non hai importato. La nostra [checklist di controllo qualità prima dell’invio](/it/blog/pre-send-email-qa-checklist) spiega ogni controllo e ogni soglia.

Ora hai un inventario, tutte le email su un canvas e un elenco di problemi, e il tuo codice invia ancora tutto come prima.

## Passaggio 2: migrazione

Ora alcune email le invia Brew al posto del tuo codice. Non tutte le email devono essere spostate, e un determinato tipo di email lo invia sempre un solo sistema alla volta.

### Mappa i concetti

| Oggi nel tuo codice | In Brew |
| --- | --- |
| `resend.emails.send({ react: <WelcomeEmail /> })` | Un evento trigger più un’automazione pubblicata con un passaggio Invia email |
| Props passate al componente | Campi del payload del trigger, usati come merge tag, per esempio `{{ firstName \| there }}` o `{{ trigger.planName }}` |
| Il dominio `from` | Un dominio di invio verificato in Brew |
| La tua tabella degli utenti | Contatti, creati tramite l’API REST o un’integrazione |
| Un cron job che invia una sequenza | Un’automazione con passaggi Attesa, Filtro e Invia email |

### 1. Configura il dominio di invio

L’agente richiama `create_domain` per ottenere i record DNS, poi `verify_domain` quando sono attivi. I domini creati tramite MCP e API sono domini di marketing. Per le reimpostazioni della password e le ricevute, configura nell’app di Brew un dominio con finalità transazionale: non aggiunge il footer di disiscrizione e consegna anche ai contatti disiscritti. La pagina [Verificare il dominio di invio](https://docs.brew.new/get-started/verify-your-sending-domain) della documentazione spiega i record.

### 2. Importa i contatti

MCP aggiorna i contatti ma non li crea. Creali dal tuo backend con `POST /v1/contacts`, che crea o aggiorna un singolo contatto o un lotto fino a 1.000 contatti e crea automaticamente i campi personalizzati, oppure carica un CSV nell’app. Anche l’attivazione di un trigger crea o aggiorna il contatto presente nel suo payload. Importa solo le persone che hanno accettato di ricevere tue comunicazioni. La pagina [Aggiungere contatti](https://docs.brew.new/audience/add-contacts) della documentazione spiega cosa si aspetta Brew.

### 3. Sostituisci i valori di anteprima con i merge tag

È facile non accorgersene: l’email di benvenuto importata dice letteralmente “Hi Ana”. Sostituisci ogni valore di esempio con un merge tag come `{{ firstName | there }}`, dove il testo dopo la barra verticale è il valore di riserva. Usa l’editor di Brew, oppure fai eseguire all’agente `edit_email` limitando la modifica a quelle sostituzioni. È una modifica con l’IA che consuma crediti, quindi controlla l’anteprima. La pagina [Merge tag](https://docs.brew.new/create-emails/merge-tags) della documentazione riporta la sintassi.

### 4. Crea il trigger e l’automazione

L’agente crea un trigger con `save_trigger`. Lo schema del payload deve includere l’`email` del destinatario. Assegnagli un contratto tipizzato (`infer_payload_contract` ne prepara una bozza a partire da un payload di esempio, `set_trigger_contract` lo salva), poi recuperalo con `get_trigger_contract` in formato `ts` o `zod`, così il tuo backend e Brew concordano sulla struttura del payload.

Poi `save_automation` crea il trigger più un passaggio Invia email con l’email, il dominio e l’oggetto. L’automazione resta in bozza finché non la pubblichi. `dryRun` convalida il diagramma, `test_automation` invia una copia reale al tuo indirizzo e `check_trigger` conferma che un’automazione pubblicata è in ascolto prima che la produzione attivi qualcosa.

### 5. Sostituisci la chiamata nel codice

È l’unica modifica al codice della tua applicazione. Prima, con Resend:

```ts
await resend.emails.send({
  from: 'Acme <hello@acme.com>',
  to: user.email,
  subject: 'Welcome to Acme',
  react: <WelcomeEmail firstName={user.firstName} planName={plan.name} />,
})
```

Dopo, con Brew:

```ts
const res = await fetch(
  `https://brew.new/api/v1/automations/triggers/${process.env.BREW_WELCOME_TRIGGER_ID}/fire`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.BREW_API_KEY}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': `welcome-${user.id}`,
    },
    body: JSON.stringify({
      payload: { email: user.email, firstName: user.firstName, planName: plan.name },
    }),
  }
)

if (!res.ok) {
  // 422 means the automation is still a draft; 400 means the payload failed the schema.
  throw new Error(`Brew trigger failed: ${res.status} ${await res.text()}`)
}
```

`fetch` si risolve anche quando la richiesta viene rifiutata, quindi controlla `res.ok` e lascia che il tuo job runner riprovi o invii un avviso. L’endpoint restituisce `202` quando accetta l’evento e `422` se nessuna automazione pubblicata è in ascolto sul trigger.

Costruisci la `Idempotency-Key` a partire da un ID stabile, come quello dell’utente o dell’ordine. Una chiave ripetuta restituisce l’esecuzione originale invece di inviare due volte, e riutilizzare una chiave con un corpo diverso restituisce `409 IDEMPOTENCY_CONFLICT`. Brew conserva la chiave di un’attivazione finché conserva la ricevuta del trigger, cioè 90 giorni, non le 24 ore usate da molte API. Considera le chiavi permanenti, una per azione. Una chiave basata su un timestamp cambia a ogni nuovo tentativo, e una chiave riutilizzata settimane dopo per un’azione diversa può essere trattata come una ripetizione, senza che l’email parta.

Il codice di produzione chiama questo endpoint con una chiave API, non tramite MCP. Sui collegamenti OAuth, MCP chiede a una persona di confermare invii reali, attivazioni dei trigger e pubblicazioni: giusto in una chat, sbagliato in un gestore di richieste. La [guida MCP o REST](/it/blog/mcp-vs-rest-api-for-email-marketing-which-workflow-should-you-use) spiega come dividere il lavoro.

### 6. Passa a Brew un’email alla volta

1. Metti la nuova chiamata dietro un feature flag, accanto a quella vecchia, così tornare indietro è solo una modifica di configurazione.
2. Inizia da un’email a basso rischio, come un promemoria del ciclo di vita, e tieni d’occhio consegne e clic per qualche giorno.
3. Poi sposta le sequenze, quando i loro trigger partono con i payload giusti.
4. Sposta per ultime le email transazionali. Le reimpostazioni della password e i magic link che non funzionano sono le prime cose che gli utenti notano.
5. Elimina il vecchio percorso dopo una settimana senza problemi e aggiorna `EMAILS.md`.

La [guida alla migrazione da Loops](https://docs.brew.new/migrations/loops) segue lo stesso schema.

### Cosa dovrebbe restare nel codice

Le email di conferma e i magic link di Supabase continuano a partire da Supabase. L’integrazione di Brew con Supabase ascolta gli eventi degli utenti per avviare le automazioni, non sostituisce le email di Supabase Auth. Anche una fattura dettagliata, costruita al momento dell’invio a partire da dati complessi, può essere più semplice da gestire nel codice, quindi verifica prima di cosa hanno bisogno i tuoi merge tag. Tieni sul canvas le copie importate, così anche queste email restano visibili.

## Passaggio 3: ottimizzazione

**Fai l’audit dell’intero insieme.** Esegui `audit_email` su un gruppo, correggi e ripeti prima degli invii più grandi.

**Controlla i client reali.** `test_email_rendering` restituisce screenshot da client di posta e dispositivi specifici, modalità scura compresa, per 10 crediti a esecuzione. `create_inbox_placement_test` invia una copia reale a delle inbox di test e riporta dove è arrivata, sempre per 10 crediti.

**Rendi coerente l’insieme.** Correggi le incoerenze nell’editor, oppure fai applicare all’agente una modifica, come un nuovo footer, a tutto un gruppo con `edit_email`.

**Leggi i risultati.** `get_email_analytics` riporta invii ed engagement. `list_insights` restituisce gli insight che Brew ha rilevato nel tuo account, ciascuno con le metriche su cui si basa.

**Testa le varianti in modo mirato.** Crea le varianti sul canvas e smista i contatti con un passaggio Divisione basato sul comportamento, per esempio se hanno cliccato. Brew non sceglie per te la variante vincente di una divisione casuale, quindi confronta tu le varianti.

**Mantieni visibili le nuove email.** Aggiungi una riga ad `AGENTS.md` o a un file simile: le nuove email di prodotto si creano in Brew, partono tramite trigger e si aggiungono a `EMAILS.md` nella stessa pull request.

## Domande frequenti

### Brew può importare i modelli React Email?

Sì. `import_email` accetta HTML renderizzato, MJML, un messaggio `.eml` salvato o un modulo React Email. L’HTML renderizzato è l’opzione più affidabile, perché un modulo viene letto in modo statico: le props assumono i valori predefiniti o di anteprima, e i componenti importati da altri file locali vengono esclusi.

### Brew si collega al mio account Resend?

No. Non esiste un’integrazione con Resend, né un’importazione o un’esportazione. Importi l’HTML che il tuo codice renderizza e, se fai la migrazione, il tuo codice attiva un trigger di Brew invece di chiamare Resend.

### Il mio backend dovrebbe chiamare Brew tramite MCP?

No. Usa MCP da un agente di coding per configurazione, importazioni, audit e test. Il codice di produzione dovrebbe chiamare l’API REST con una chiave API, perché sui collegamenti OAuth MCP chiede a una persona di confermare gli invii reali e le attivazioni dei trigger.

### Importare un’email ne cambia l’aspetto?

L’importazione converte l’email in un design di Brew modificabile e mantiene l’HTML sorgente originale per l’invio. Rimuove script, iframe, moduli e gestori di eventi, neutralizza i pixel di tracciamento già presenti e copia le immagini pubbliche sull’hosting di Brew. Rivedi ogni email sul canvas, nelle viste desktop e mobile, prima di inviarla da Brew.
