En guide för team vars mejl finns i koden: inventera dem med en kodagent, samla dem på en canvas i Brew via MCP och migrera och förbättra dem sedan säkert.

Mejl i kod är produktmejl som definieras i din kodbas och släpps som vilken annan funktion som helst. Fråga ett team som bygger på Resend och React Email vilka mejl produkten skickar, så blir det tyst en stund. Välkomstmejlet är en komponent i emails/. Lösenordsåterställningen finns i autentiseringsleverantörens kontrollpanel. Mejlet om att provperioden tar slut är en sträng i ett cron-jobb. Stripe skickar kvittot. Ingen minns vad som skickar mejlet ”vi saknar dig”.
Varje mejl var lätt att släppa, så ingen äger helheten. Vi skulle åtgärda det i den här ordningen: först överblick, sedan migrering och sist förbättring. Kodagenten som du redan använder kan göra det mesta, ansluten till Brew via MCP.
import_email. Importen är deterministisk, använder ingen AI och är gratis.React Email och Resend gjorde e-post betydligt bättre för utvecklare: typade komponenter som granskas i pull requests. Kostnaden visar sig senare.
Mejlen är utspridda. Komponenter, inline-HTML i ett bakgrundsjobb, mallar i en kontrollpanel hos en tredje part, mejl som en annan tjänst skickar åt dig. Ingen fil listar dem alla.
Förhandsvisningar är inte produktion. Förhandsvisningsservern i React Email visar en mall med dess props för förhandsvisning, inte det som en kund faktiskt fick, och inget alls för andra mallar.
Bara utvecklare kan titta. Produkt, design och support skulle behöva be en utvecklare att köra projektet, så oftast gör de inte det.
Ingenting granskas efter lanseringen. Det två år gamla mejlet har fortfarande den gamla logotypen och en plan som du inte längre säljer. Ingen märker det, eftersom ingen ser mejlen tillsammans.
Målet är en gemensam vy över alla mejl. Inget av det här rör produktionen.

Varje fas är användbar i sig, och du kan stanna efter vilken som helst av dem.
MCP-servern för Brew finns på https://brew.new/api/mcp och använder OAuth: du loggar in med Brew och väljer vilket varumärke agenten får arbeta i. I Claude Code:
claude mcp add --transport http brew "https://brew.new/api/mcp"När du lägger till servern sparas den bara i den lokala konfigurationen för det här projektet. Lägg till --scope user för att använda den i alla projekt. Kör claude mcp login brew, eller öppna /mcp och autentisera dig mot Brew, innan du använder verktygen i Brew.
Dokumentationen om att konfigurera klienter har avsnitt för Cursor och Codex. Klienter utan OAuth kan använda en varumärkesspecifik API-nyckel. Låt sedan agenten anropa get_brew_capabilities, så att den läser den aktuella verktygslistan i stället för att gissa.
Be agenten om en lista:
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.Behåll avsnittet ”Unknown”. Bekräftelsemejl från autentiseringen och kvitton från Stripe skickas inte av något anrop i din kod, men de hör hemma på listan. Committa EMAILS.md. Även om du stannar här har du en lista som du inte hade i går.
Det bästa underlaget för importen är den HTML som din kod redan producerar. Funktionen render i React Email ger dig den strängen:
import { render } from 'react-email'
import WelcomeEmail from './emails/welcome'
const html = await render(
<WelcomeEmail firstName="Ana" planName="Pro" trialDays={14} />
)Äldre projekt importerar render från @react-email/render. Använd realistisk testdata, inte "test", eftersom ditt team ska granska mejlen. Låt agenten skripta en rendering av varje mall till en fil.
Brew kan också importera en React Email-modul direkt med format: "jsx". Modulen läses då statiskt, utan att köras. Props får sina standardvärden eller värdena i PreviewProps, komponenter som importeras från andra lokala filer utelämnas eller avvisas, och await och liknande nekas. För allt utöver en enda fristående fil använder du renderad HTML.
Importera sedan varje rendering med import_email, med ett groupName per produktområde:
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.Utvecklare frågar med rätta om importen skriver om deras mejl. Det gör den inte:
assetReport listar de bilder som inte gick att hämta.baseUrl används bara för att lösa upp relativa sökvägar till bilder.Varje grupp får en canvas. Öppna brew.new/emails/onboarding, så ligger hela sekvensen sida vid sida, med ett reglage för datorvy och mobilvy och kommentarer på varje design. Länkar till en canvas fungerar för personer som är inloggade i din arbetsyta i Brew. Det finns ingen offentlig delningslänk, så bjud in dem som ska granska.
Det är här problemen dyker upp: två logotyper, en död länk i en knapp, tre olika sidfötter. Kör audit_email innan du åtgärdar något. Verktyget kontrollerar länkar, bilder, regelefterlevnad, inläst storlek, klientstöd, tillgänglighet och text, kostar 5 krediter per fullständig granskning och tar emot ett sparat emailId eller rå HTML, så att du kan granska mejl som du inte har importerat. Vår checklista för kvalitetskontroll före utskick förklarar varje kontroll och gränsvärde.
Nu har du en inventering, alla mejl på en canvas och en lista med problem, och din kod skickar fortfarande allt precis som förut.
Nu skickar Brew en del mejl i stället för din kod. Alla mejl behöver inte flyttas, och bara ett system åt gången skickar en viss mejltyp.
| I din kod i dag | I Brew |
|---|---|
resend.emails.send({ react: <WelcomeEmail /> }) |
En utlösarhändelse plus en publicerad automatisering med ett steg av typen Skicka mejl |
| Props som skickas till komponenten | Fält i utlösarens nyttolast, som används som personaliseringstaggar, till exempel {{ firstName | there }} eller {{ trigger.planName }} |
Domänen i from |
En verifierad avsändardomän i Brew |
| Din användartabell | Kontakter som skapas via REST-API:t eller en integration |
| Ett cron-jobb som skickar en sekvens | En automatisering med steg av typen Vänta, Filter och Skicka mejl |
Agenten anropar create_domain för att få DNS-posterna och sedan verify_domain när posterna är publicerade. Domäner som skapas via MCP och API är marknadsföringsdomäner. För lösenordsåterställningar och kvitton konfigurerar du en domän med transaktionellt syfte i webbappen: den hoppar över sidfoten för avregistrering och levererar även till avregistrerade kontakter. Verifiera din avsändardomän går igenom posterna.
MCP uppdaterar kontakter men skapar dem inte. Skapa dem från din backend med POST /v1/contacts, som skapar eller uppdaterar en kontakt eller en omgång på upp till 1 000 och skapar anpassade fält automatiskt, eller ladda upp en CSV-fil i appen. När du skickar en händelse till en utlösare skapas eller uppdateras också kontakten i nyttolasten. Importera bara personer som har sagt ja till att höra från dig. Lägg till kontakter förklarar vad Brew förväntar sig.
Lätt att missa: det importerade välkomstmejlet säger bokstavligen ”Hi Ana”. Byt ut varje testvärde mot en personaliseringstagg som {{ firstName | there }}, där texten efter lodstrecket är reservvärdet. Använd editorn i Brew, eller låt agenten köra edit_email begränsat till just de ersättningarna. Det är en redigering med AI som förbrukar krediter, så kontrollera förhandsvisningen. Personaliseringstaggar listar syntaxen.
Agenten skapar en utlösare med save_trigger. Nyttolastens schema måste innehålla mottagarens email. Ge utlösaren ett typat kontrakt (infer_payload_contract tar fram ett utkast utifrån en exempelnyttolast, set_trigger_contract sparar det) och hämta det sedan med get_trigger_contract i formatet ts eller zod, så att din backend och Brew är överens om nyttolastens form.
Sedan bygger save_automation utlösaren plus ett steg av typen Skicka mejl med mejlet, domänen och ämnesraden. Automatiseringen förblir ett utkast tills du publicerar den. dryRun validerar flödet, test_automation skickar ett riktigt exemplar till din adress och check_trigger bekräftar att en publicerad automatisering lyssnar innan produktionen skickar några händelser.
Det här är den enda ändringen i din applikationskod. Före, med Resend:
await resend.emails.send({
from: 'Acme <hello@acme.com>',
to: user.email,
subject: 'Welcome to Acme',
react: <WelcomeEmail firstName={user.firstName} planName={plan.name} />,
})Efter, med Brew:
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 kastar inget fel när servern avvisar anropet, så kontrollera res.ok och låt systemet som kör dina jobb göra nya försök eller larma. Slutpunkten returnerar 202 när den tar emot händelsen och 422 om ingen publicerad automatisering lyssnar på utlösaren.
Bygg Idempotency-Key utifrån ett stabilt id, till exempel användarens eller beställningens. En upprepad nyckel returnerar den ursprungliga körningen i stället för att skicka två gånger, och om du återanvänder en nyckel med ett annat innehåll i anropet får du 409 IDEMPOTENCY_CONFLICT. Brew sparar nyckeln för en händelse lika länge som utlösarens kvitto, alltså i 90 dagar, inte de 24 timmar som många API:er använder. Behandla nycklar som permanenta, en per åtgärd. En nyckel som bygger på en tidsstämpel ändras vid varje nytt försök, och en nyckel som återanvänds för en annan åtgärd flera veckor senare kan behandlas som en upprepning i stället för att skickas.
Produktionskod anropar den här slutpunkten med en API-nyckel, inte via MCP. Via OAuth ber MCP en person att bekräfta skarpa utskick, händelser till utlösare och publiceringar: rätt i en chatt, fel i koden som hanterar ett inkommande anrop. Guiden om MCP kontra REST går igenom uppdelningen.
EMAILS.md.Migreringsguiden för Loops följer samma mönster.
Bekräftelsemejl och mejl med magiska länkar från Supabase fortsätter att komma från Supabase. Supabase-integrationen i Brew lyssnar efter användarhändelser för att starta automatiseringar, i stället för att ersätta mejlen från Supabase Auth. En specificerad faktura som byggs av komplex data vid utskickstillfället kan också vara enklare att ha kvar i koden, så kontrollera först vad dina personaliseringstaggar behöver. Behåll importerade kopior på canvasen, så att även de här mejlen syns.
Granska alla mejl. Kör audit_email på en hel grupp, åtgärda och kör igen före stora utskick.
Kontrollera riktiga e-postklienter. test_email_rendering returnerar skärmbilder från specifika e-postklienter och enheter, även i mörkt läge, för 10 krediter per körning. create_inbox_placement_test skickar ett riktigt exemplar till testinkorgar och rapporterar var det hamnade, också för 10 krediter.
Gör mejlen enhetliga. Rätta inkonsekvenser i editorn, eller låt agenten göra en ändring, till exempel en ny sidfot, i en hel grupp med edit_email.
Läs resultaten. get_email_analytics rapporterar utskick och engagemang. list_insights returnerar fynd som Brew har upptäckt i ditt konto, vart och ett med måtten bakom.
Testa varianter medvetet. Skapa varianter på canvasen och styr kontakter med ett steg av typen Förgrening utifrån beteende, till exempel om de klickade. Brew utser ingen vinnare av en slumpmässig uppdelning åt dig, så jämför varianterna själv.
Håll nya mejl synliga. Lägg till en rad i AGENTS.md eller motsvarande: nya produktmejl skapas i Brew, startas via en utlösare och läggs till i EMAILS.md i samma pull request.
Ja. import_email tar emot renderad HTML, MJML, ett sparat .eml-meddelande eller en React Email-modul. Renderad HTML är mest tillförlitligt, eftersom en modul läses statiskt: props får sina standard- eller förhandsvisningsvärden, och komponenter som importeras från andra lokala filer utelämnas.
Nej. Det finns ingen integration, import eller export för Resend. Du importerar den HTML som din kod renderar, och om du migrerar skickar din kod en händelse till en utlösare i Brew i stället för att anropa Resend.
Nej. Använd MCP från en kodagent för konfiguration, importer, granskningar och tester. Produktionskod bör anropa REST-API:t med en API-nyckel, eftersom MCP vid anslutningar via OAuth ber en person att bekräfta skarpa utskick och händelser till utlösare.
Importen gör om mejlet till en redigerbar design i Brew och behåller den ursprungliga käll-HTML:en för utskicket. Den tar bort skript, iframes, formulär och händelsehanterare, oskadliggör befintliga spårningspixlar och hostar offentliga bilder på nytt. Granska varje mejl på canvasen, i datorvy och mobilvy, innan du skickar det från Brew.
