# E-maily v kódu: zviditelni je, převeď je a vylepši je

Kanonická URL: https://brew.new/cs/blog/emails-in-code-visibility-migration-mcp
Autor: Thomas Park
Publikováno: 2026-10-12
Aktualizováno: 2026-10-15

E-maily v kódu jsou produktové e-maily definované ve tvém kódu a nasazované jako kterákoli jiná funkce. Zeptej se týmu postaveného na Resend a React Email, jaké e-maily produkt posílá, a nastane chvíle ticha. Uvítací e-mail je komponenta v `emails/`. Obnova hesla žije v administraci poskytovatele autentizace. E-mail o konci zkušební verze je řetězec v úloze v cronu. Účtenku posílá Stripe. A co posílá e-mail „chybíš nám“, si nepamatuje nikdo.

Každý e-mail šlo snadno nasadit, a tak celkový přehled nemá nikdo na starosti. My bychom to řešili v tomto pořadí: nejdřív viditelnost, pak migrace a nakonec vylepšení. Většinu práce zvládne programovací agent, kterého už používáš, když ho přes MCP připojíš k Brew.

## Hlavní body

- Začni soupisem, ne novým nástrojem: každý e-mail, jeho spouštěč, soubor a proměnné.
- Programovací agent dokáže najít volání, která e-maily odesílají, vykreslit každou šablonu a naimportovat ji MCP nástrojem `import_email`. Import je deterministický, nepoužívá AI a je zdarma.
- Každá skupina naimportovaných e-mailů má jedno plátno, takže je tým může procházet vedle sebe v zobrazení pro desktop i mobil.
- Při migraci se z odeslání ve stylu Resend stane spouštěč s publikovanou automatizací, který aktivuješ jedním voláním REST. Produkční kód používá REST, ne MCP.
- Přesouvej vždy jen jeden typ e-mailu, schovaný za feature flagem, a transakční e-maily přesuň až nakonec.

## Proč e-maily definované v kódu přestanou být vidět

React Email a Resend udělaly z e-mailu pro vývojáře mnohem příjemnější práci: typované komponenty, kontrola v pull requestech. Cena za to se ukáže až později.

**E-maily jsou rozházené.** Komponenty, inline HTML v úloze na pozadí, šablony v administraci třetí strany, e-maily, které za tebe posílá jiná služba. Žádný soubor je neuvádí všechny.

**Náhled není produkce.** Náhledový server React Email ukáže jednu šablonu s jejími ukázkovými props, ne to, co skutečně dostal zákazník, a pro ostatní šablony neukáže nic.

**Podívat se můžou jen vývojáři.** Produktový tým, design i podpora by museli o spuštění projektu požádat vývojáře, takže to většinou nedělají.

**Po spuštění už nikdo nic nekontroluje.** Dva roky starý e-mail má pořád staré logo a tarif, který už neprodáváš. Nikdo si toho nevšimne, protože je nikdo nevidí pohromadě.

## Krok 1: Viditelnost

Cílem je jeden společný pohled na všechny e-maily. Nic z toho se nedotkne produkce.

![Tři fáze přesunu e-mailů z kódu: viditelnost s import_email a plátnem pro každou skupinu, migrace s doménami, kontakty, spouštěči a automatizacemi a optimalizace s audity, testy zobrazení a analytikou.](/images/blog/emails-in-code-three-phases.png)

*Každá fáze je užitečná sama o sobě a po kterékoli z nich můžeš skončit.*

### Připoj svého programovacího agenta k Brew

MCP server Brew běží na `https://brew.new/api/mcp` a používá OAuth: přihlásíš se přes Brew a vybereš značku, ve které smí agent pracovat. V Claude Code:

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

Přidáním se server uloží jen do lokální konfigurace tohoto projektu. Aby byl dostupný ve všech projektech, přidej `--scope user`. Než začneš jeho nástroje používat, spusť `claude mcp login brew`, nebo otevři `/mcp` a ověř se u Brew.

[Dokumentace k nastavení klientů](https://docs.brew.new/api-reference/mcp/connect-your-client) má návody i pro Cursor a Codex. Klienti bez OAuth můžou použít API klíč pro konkrétní značku. Pak nech agenta zavolat `get_brew_capabilities`, aby si přečetl aktuální seznam nástrojů a nemusel hádat.

### Sestav soupis

Požádej agenta o seznam:

```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.
```

Sekci „Unknown“ si nech. Potvrzovací e-maily z autentizace a účtenky ze Stripe nejsou volání ve tvém kódu, ale na seznam patří. Soubor `EMAILS.md` commitni. I když tady skončíš, máš seznam, který ještě včera neexistoval.

### Vykresli každou šablonu s realistickými daty

Nejlepším vstupem pro import je HTML, které tvůj kód už vytváří. Tenhle řetězec ti dá [pomocná funkce render](https://react.email/docs/utilities/render) z React Email:

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

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

Starší projekty importují `render` z `@react-email/render`. Používej realistická testovací data, ne `"test"`, protože e-maily bude kontrolovat tvůj tým. Nech agenta napsat skript, který každou šablonu vykreslí do souboru.

Brew umí s `format: "jsx"` importovat i přímo modul React Email: přečte ho staticky, aniž by ho spustil. Props se vyhodnotí na výchozí hodnoty nebo na `PreviewProps`, komponenty importované z jiných lokálních souborů se vynechají nebo odmítnou a `await` a podobné konstrukce import nepřijme. Pokud nejde o jeden soběstačný soubor, použij vykreslené HTML.

### Naimportuj všechno na jedno místo

Pak každý vykreslený e-mail naimportuj přes `import_email`, s jedním `groupName` pro každou oblast produktu:

```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.
```

Vývojáři se oprávněně ptají, jestli import jejich e-maily přepíše. Nepřepíše:

- Je to deterministický kompilátor, ne AI model, a nestojí žádné kredity.
- Vytvoří upravitelný návrh v Brew, přičemž při doručení se u naimportovaných řádků použije původní zdrojové HTML.
- Veřejné obrázky přenese na vlastní hosting a `assetReport` vypíše ty, které se mu nepodařilo stáhnout.
- Odstraní skripty, iframy, formuláře a obsluhy událostí a zneškodní stávající pixely pro sledování otevření.
- Každý zdroj může mít až 5 MB. Vstup z URL neexistuje: nástroj přijímá přímo samotný kód a `baseUrl` slouží jen k doplnění relativních cest k obrázkům.

### Projdi e-maily společně s týmem

Každá skupina dostane vlastní plátno. Otevři `brew.new/emails/onboarding` a uvidíš celou sekvenci vedle sebe, s přepínačem mezi desktopem a mobilem a s komentáři u každého návrhu. Odkazy na plátno fungují pro lidi přihlášené do tvého pracovního prostoru v Brew. Veřejný odkaz ke sdílení neexistuje, takže lidi, kteří mají e-maily zkontrolovat, pozvi.

Právě tady vyplavou problémy: dvě loga, nefunkční odkaz v tlačítku, tři patičky. Než začneš cokoli opravovat, spusť `audit_email`. Kontroluje odkazy, obrázky, soulad s předpisy, celkovou velikost při načtení, podporu v e-mailových klientech, přístupnost a texty. Kompletní audit stojí 5 kreditů. Nástroj přijímá uložené `emailId` i surové HTML, takže můžeš auditovat i e-maily, které ještě nejsou naimportované. Náš [checklist kontroly před odesláním](/cs/blog/pre-send-email-qa-checklist) vysvětluje jednotlivé kontroly i jejich hranice.

Teď máš soupis, všechny e-maily na plátně a seznam problémů, a tvůj kód přitom pořád posílá všechno jako dřív.

## Krok 2: Migrace

Teď začne některé e-maily posílat Brew místo tvého kódu. Přesunout se nemusí každý e-mail a daný typ e-mailu vždy posílá jen jeden systém.

### Převod pojmů

| Dnes v tvém kódu | V Brew |
| --- | --- |
| `resend.emails.send({ react: <WelcomeEmail /> })` | Událost spouštěče a k ní publikovaná automatizace s jedním krokem Odeslání e-mailu |
| Props předávané komponentě | Pole payloadu spouštěče, použitá jako proměnné, např. `{{ firstName \| there }}` nebo `{{ trigger.planName }}` |
| Doména v `from` | Ověřená odesílací doména v Brew |
| Tvoje tabulka uživatelů | Kontakty vytvořené přes REST API nebo integraci |
| Úloha v cronu, která posílá sekvenci | Automatizace s kroky Čekání, Filtr a Odeslání e-mailu |

### 1. Nastav odesílací doménu

Agent zavolá `create_domain`, aby získal záznamy DNS, a jakmile jsou aktivní, zavolá `verify_domain`. Domény vytvořené přes MCP a API jsou marketingové. Pro obnovu hesla a účtenky nastav v aplikaci Brew doménu s účelem Transakční: e-maily z ní nemají patičku s odhlášením a doručují se i odhlášeným kontaktům. Záznamy podrobně popisuje [návod k ověření odesílací domény](https://docs.brew.new/get-started/verify-your-sending-domain).

### 2. Přenes kontakty

Přes MCP se kontakty dají aktualizovat, ale ne vytvářet. Vytvoř je z backendu přes `POST /v1/contacts`: endpoint vloží nebo aktualizuje (upsert) jeden kontakt či dávku až 1 000 kontaktů a vlastní pole vytvoří automaticky. Případně nahraj CSV v aplikaci. Aktivace spouštěče také vytvoří nebo aktualizuje kontakt ze svého payloadu. Importuj jen lidi, kteří souhlasili, že se jim budeš ozývat. Co Brew očekává, vysvětluje [návod k přidávání kontaktů](https://docs.brew.new/audience/add-contacts).

### 3. Nahraď ukázkové hodnoty proměnnými

Snadno se to přehlédne: naimportovaný uvítací e-mail doslova říká „Hi Ana“. Každou testovací hodnotu nahraď proměnnou, třeba `{{ firstName | there }}`, kde text za svislou čarou je záložní hodnota. Použij editor Brew, nebo nech agenta spustit `edit_email` omezený jen na tyhle náhrady. Je to úprava pomocí AI, která spotřebovává kredity, takže zkontroluj náhled. Syntaxi najdeš v [návodu k proměnným](https://docs.brew.new/create-emails/merge-tags).

### 4. Vytvoř spouštěč a automatizaci

Agent vytvoří spouštěč přes `save_trigger`. Schéma payloadu musí obsahovat `email` příjemce. Dej spouštěči typované schéma (`infer_payload_contract` ho navrhne z ukázkového payloadu, `set_trigger_contract` ho uloží) a pak si ho stáhni přes `get_trigger_contract` ve formátu `ts` nebo `zod`, aby se tvůj backend a Brew shodly na podobě payloadu.

`save_automation` pak sestaví spouštěč a krok Odeslání e-mailu s daným e-mailem, doménou a předmětem. Automatizace zůstane konceptem, dokud ji nepublikuješ. `dryRun` ověří graf, `test_automation` pošle skutečnou kopii na tvou adresu a `check_trigger` potvrdí, že publikovaná automatizace naslouchá, ještě než produkce cokoli spustí.

### 5. Vyměň místo volání

Tohle je jediná změna v kódu tvé aplikace. Předtím, s 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} />,
})
```

Potom, s 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` se splní i tehdy, když server událost odmítne, takže kontroluj `res.ok` a nech systém, který zpracovává úlohy, zkusit to znovu, nebo spustit upozornění. Endpoint vrací `202`, když událost přijme, a `422`, pokud na spouštěč nenaslouchá žádná publikovaná automatizace.

`Idempotency-Key` sestav ze stabilního ID, třeba uživatele nebo objednávky. Opakovaný klíč vrátí původní běh, místo aby se e-mail poslal dvakrát, a pokud stejný klíč použiješ s jiným tělem požadavku, dostaneš `409 IDEMPOTENCY_CONFLICT`. Brew uchovává klíč aktivace stejně dlouho jako záznam o přijetí události spouštěče, tedy 90 dní, ne 24 hodin jako mnoho jiných API. Ber klíče jako trvalé, jeden na každou akci. Klíč z časového razítka se při každém opakovaném pokusu změní a klíč, který o několik týdnů později použiješ pro jinou akci, může vrátit dřívější běh, místo aby se e-mail odeslal.

Produkční kód volá tento endpoint s API klíčem, ne přes MCP. Při připojení přes OAuth žádá MCP člověka o potvrzení ostrých rozesílek, aktivací spouštěčů a publikování: v chatu je to správně, v obsluze požadavku špatně. Jak práci rozdělit, popisuje [průvodce MCP vs. REST](/cs/blog/mcp-vs-rest-api-for-email-marketing-which-workflow-should-you-use).

### 6. Přepínej po jednom e-mailu

1. Dej nové volání vedle starého za feature flag, aby návrat zpátky byl jen změnou konfigurace.
2. Začni e-mailem s nízkým rizikem, třeba připomínkou ze sekvence životního cyklu, a pár dní sleduj doručení a prokliky.
3. Potom přesuň sekvence, jakmile se jejich spouštěče aktivují se správnými payloady.
4. Transakční e-maily přesuň až nakonec. Rozbitou obnovu hesla nebo magic link uživatelé poznají jako první.
5. Po týdnu bez problémů starou cestu smaž a aktualizuj `EMAILS.md`.

Stejný postup používá i [návod k přechodu z platformy Loops](https://docs.brew.new/migrations/loops).

### Co by mělo zůstat v kódu

Potvrzovací e-maily a magic linky ze Supabase dál chodí ze Supabase. Integrace Supabase v Brew naslouchá událostem uživatelů, aby spouštěla automatizace, a e-maily Supabase Auth nenahrazuje. Položkovou fakturu, která se při odeslání sestavuje ze složitých dat, může být také jednodušší nechat v kódu, takže si nejdřív ověř, co tvoje proměnné potřebují. Naimportované kopie si nech na plátně, aby tyhle e-maily zůstaly na očích.

## Krok 3: Optimalizace

**Proveď audit celé sady.** Spusť `audit_email` na celou skupinu, oprav chyby a před velkými rozesílkami ho spusť znovu.

**Zkontroluj skutečné klienty.** `test_email_rendering` vrátí snímky obrazovky z konkrétních e-mailových klientů a zařízení včetně tmavého režimu, za 10 kreditů za běh. `create_inbox_placement_test` pošle skutečnou kopii do testovacích schránek a ohlásí, kde skončila, také za 10 kreditů.

**Sjednoť celou sadu.** Nesrovnalosti oprav v editoru, nebo nech agenta přes `edit_email` provést jednu změnu, třeba novou patičku, v celé skupině.

**Čti výsledky.** `get_email_analytics` vykazuje rozesílky a zapojení. `list_insights` vrací zjištění, která Brew ve tvém účtu odhalil, každé i s metrikami, o které se opírá.

**Testuj varianty záměrně.** Vytvoř varianty na plátně a kontakty rozděluj krokem Rozdělení podle chování, třeba podle toho, jestli klikli. Brew za tebe vítěze náhodného rozdělení nevybírá, takže porovnání variant je na tobě.

**Udržuj nové e-maily na očích.** Přidej do `AGENTS.md` nebo podobného souboru řádek: nové produktové e-maily se vytvářejí v Brew, spouštějí se přes spouštěč a ve stejném pull requestu se přidávají do `EMAILS.md`.

## Časté dotazy

### Umí Brew importovat šablony React Email?

Ano. `import_email` přijímá vykreslené HTML, MJML, uloženou zprávu `.eml` nebo modul React Email. Nejspolehlivější je vykreslené HTML, protože modul se čte staticky: props dostanou své výchozí nebo ukázkové hodnoty a komponenty importované z jiných lokálních souborů se vynechají.

### Napojí se Brew na můj účet v Resend?

Ne. Integrace, import ani export pro Resend neexistují. Naimportuješ HTML, které vykreslí tvůj kód, a pokud přejdeš na Brew, tvůj kód místo volání Resend aktivuje spouštěč v Brew.

### Má můj backend volat Brew přes MCP?

Ne. MCP používej z programovacího agenta na nastavení, importy, audity a testování. Produkční kód by měl volat REST API s API klíčem, protože u připojení přes OAuth žádá MCP člověka o potvrzení ostrých rozesílek a aktivací spouštěčů.

### Změní import vzhled e-mailu?

Import převede e-mail na upravitelný návrh v Brew a pro doručení si ponechá původní zdrojové HTML. Odstraní skripty, iframy, formuláře a obsluhy událostí, zneškodní stávající sledovací pixely a veřejné obrázky přenese na vlastní hosting. Než e-mail začneš posílat z Brew, zkontroluj každý na plátně v zobrazení pro desktop i mobil.
