E-postaları kodda duran ekipler için rehber: kodlama ajanıyla envanter çıkarın, MCP ile tek bir Brew tuvalinde toplayın, sonra güvenle taşıyıp iyileştirin.

Koddaki e-postalar, kod tabanınızda tanımlanan ve diğer tüm özellikler gibi yayına alınan ürün e-postalarıdır. Resend ve React Email üzerine kurulu bir ekibe ürünün hangi e-postaları gönderdiğini sorun; kısa bir sessizlik olur. Hoş geldin e-postası emails/ klasöründe bir bileşen. Şifre sıfırlama e-postası kimlik doğrulama sağlayıcısının kontrol panelinde duruyor. Deneme süresinin bittiğini bildiren e-posta, bir cron işinin içinde bir metin dizesi. Makbuzu Stripe gönderiyor. “Sizi özledik” e-postasını neyin gönderdiğini ise kimse hatırlamıyor.
Her e-postayı yayına almak kolaydı; bu yüzden resmin tamamından kimse sorumlu değil. Biz bunu şu sırayla düzeltirdik: önce görünürlük, sonra geçiş, ardından iyileştirme. İşin çoğunu, hâlihazırda kullandığınız kodlama ajanı MCP üzerinden Brew ile bağlanarak yapabilir.
import_email MCP aracıyla içe aktarabilir. İçe aktarma deterministiktir, yapay zekâ kullanmaz ve ücretsizdir.React Email ve Resend, e-postayı geliştiriciler için çok daha iyi hâle getirdi: tipli bileşenler ve pull request aşamasında gözden geçirilen kod. Bedeli ise daha sonra ortaya çıkıyor.
E-postalar dağınık. Bileşenler, bir arka plan işinin içindeki satır içi HTML, üçüncü taraf bir kontrol panelindeki şablonlar, başka bir hizmetin sizin adınıza gönderdiği e-postalar. Hepsini listeleyen bir dosya yok.
Önizleme, üretim ortamı değildir. React Email önizleme sunucusu bir şablonu, önizleme için tanımlanmış props değerleriyle gösterir; bir müşterinin gerçekte ne aldığını göstermez, diğer şablonlar içinse hiçbir şey göstermez.
Yalnızca mühendisler bakabiliyor. Ürün, tasarım ve destek ekiplerinin projeyi çalıştırması için bir mühendisten rica etmesi gerekir; bu yüzden çoğu zaman bunu yapmazlar.
Yayından sonra hiçbir şey gözden geçirilmiyor. İki yıllık e-postada hâlâ eski logo ve artık satmadığınız bir plan duruyor. Kimse fark etmiyor, çünkü kimse e-postaları bir arada görmüyor.
Amaç, tüm e-postaları ortak tek bir görünümde toplamak. Bu adımda üretim ortamına hiç dokunulmaz.

Her aşama tek başına işe yarar; herhangi birinden sonra durabilirsiniz.
Brew MCP sunucusu https://brew.new/api/mcp adresindedir ve OAuth kullanır: Brew hesabınızla giriş yapar ve ajanın çalışabileceği markayı seçersiniz. Claude Code’da:
claude mcp add --transport http brew "https://brew.new/api/mcp"Bu komut, sunucuyu yalnızca bu projenin yerel yapılandırmasına kaydeder. Sunucuyu tüm projelerde kullanmak için --scope user ekleyin. Brew araçlarını kullanmadan önce claude mcp login brew komutunu çalıştırın ya da /mcp menüsünü açıp Brew için kimlik doğrulamasını tamamlayın.
İstemci kurulum dokümantasyonunda Cursor ve Codex için de talimatlar var. OAuth desteklemeyen istemciler markaya özel bir API anahtarı kullanabilir. Ardından ajana get_brew_capabilities aracını çağırtın; böylece tahmin yürütmek yerine canlı araç listesini okur.
Ajandan bir liste isteyin:
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.“Unknown” bölümünü silmeyin. Kimlik doğrulama onayları ve Stripe makbuzları kodunuzdaki gönderim çağrıları değildir, ama listede yer almaları gerekir. EMAILS.md dosyasını sürüm kontrolüne ekleyin. Burada dursanız bile, dün elinizde olmayan bir listeye sahip olursunuz.
İçe aktarma için en iyi girdi, kodunuzun zaten ürettiği HTML’dir. React Email’in render yardımcı fonksiyonu bu HTML’i bir metin dizesi olarak verir:
import { render } from 'react-email'
import WelcomeEmail from './emails/welcome'
const html = await render(
<WelcomeEmail firstName="Ana" planName="Pro" trialDays={14} />
)Eski projeler render fonksiyonunu @react-email/render paketinden içe aktarır. Bu e-postaları ekibiniz inceleyeceği için "test" yerine gerçekçi örnek veriler kullanın. Ajana, her şablonun HTML çıktısını bir dosyaya yazan bir betik hazırlatın.
Brew, bir React Email modülünü format: "jsx" ile doğrudan da içe aktarabilir; modülü çalıştırmadan, statik olarak okur. Props değerleri varsayılan değerlerine ya da PreviewProps değerlerine çözümlenir, diğer yerel dosyalardan içe aktarılan bileşenler atlanır ya da reddedilir, await ve benzeri yapılar ise kabul edilmez. Kendi içinde bağımsız tek bir dosyanın ötesine geçtiğinizde HTML çıktısını kullanın.
Ardından her HTML çıktısını, ürün alanı başına bir groupName değeriyle import_email aracı üzerinden içe aktarın:
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.Geliştiriciler haklı olarak içe aktarmanın e-postalarını yeniden yazıp yazmadığını soruyor. Yazmıyor:
assetReport listeler.baseUrl ise yalnızca göreli görsel yollarını çözümler.Her grubun bir tuvali olur. brew.new/emails/onboarding adresini açtığınızda serinin tamamı yan yana durur; masaüstü ve mobil görünüm arasında geçiş yapabilir, her tasarıma yorum bırakabilirsiniz. Tuval bağlantıları, Brew çalışma alanınızda oturum açmış kişiler için çalışır. Herkese açık bir paylaşım bağlantısı olmadığından inceleyecek kişileri davet edin.
Sorunlar tam da burada ortaya çıkar: iki farklı logo, çalışmayan bir buton bağlantısı, üç ayrı alt bilgi. Herhangi bir şeyi düzeltmeden önce audit_email aracını çalıştırın. Bu araç bağlantıları, görselleri, yasal uyumluluğu, yükleme boyutunu, istemci desteğini, erişilebilirliği ve metni kontrol eder; tam bir denetim 5 kredi tutar. Kayıtlı bir emailId değerini ya da ham HTML’i kabul ettiği için içe aktarmadığınız e-postaları da denetleyebilirsiniz. Gönderim öncesi kalite kontrol listemiz her kontrolü ve eşiği açıklıyor.
Artık elinizde bir envanter, tuvalde duran tüm e-postalar ve bir sorun listesi var; kodunuz ise her şeyi eskisi gibi göndermeye devam ediyor.
Bu aşamada bazı e-postaları kodunuz yerine Brew gönderir. Her e-postanın taşınması gerekmez; belirli bir e-posta türünü ise her an yalnızca tek bir sistem gönderir.
| Bugün kodunuzda | Brew içinde |
|---|---|
resend.emails.send({ react: <WelcomeEmail /> }) |
Bir tetikleyici olayı ve tek bir “E-posta gönder” adımı içeren yayımlanmış bir otomasyon |
| Bileşene aktarılan props değerleri | {{ firstName | there }} ya da {{ trigger.planName }} gibi birleştirme etiketleri olarak kullanılan tetikleyici payload alanları |
from adresinin alan adı |
Brew içinde doğrulanmış bir gönderim alan adı |
| Kullanıcılar tablonuz | REST API ya da bir entegrasyon üzerinden oluşturulan kişiler |
| Bir seriyi gönderen bir cron işi | Bekle, Filtre ve E-posta gönder adımlarından oluşan bir otomasyon |
Ajan, DNS kayıtları için create_domain aracını, kayıtlar yayıldıktan sonra da verify_domain aracını çağırır. MCP ve API üzerinden oluşturulan alan adları pazarlama alan adlarıdır. Şifre sıfırlama e-postaları ve makbuzlar için Brew uygulamasında gönderim amacı işlemsel olan bir alan adı kurun: Bu alan adı abonelikten çıkma alt bilgisini eklemez ve abonelikten çıkmış kişilere de teslim eder. Kayıtların ayrıntıları Gönderim alan adınızı doğrulayın sayfasında.
MCP kişileri günceller ama oluşturmaz. Kişileri sunucunuzdan POST /v1/contacts ile oluşturun; bu uç nokta tek bir kişiyi ya da en fazla 1.000 kişilik bir partiyi ekler veya günceller (upsert) ve özel alanları otomatik olarak oluşturur. Dilerseniz uygulamaya bir CSV dosyası da yükleyebilirsiniz. Bir tetikleyiciyi tetiklemek de payload içindeki kişiyi oluşturur ya da günceller. Yalnızca sizden haber almayı kabul etmiş kişileri içe aktarın. Brew için nelerin gerektiğini Kişi ekleme sayfası açıklıyor.
Gözden kaçması kolay bir ayrıntı: İçe aktarılan hoş geldin e-postasında kelimesi kelimesine “Hi Ana” yazıyor. Her örnek değeri {{ firstName | there }} gibi bir birleştirme etiketiyle değiştirin; dikey çizgiden sonraki metin varsayılan değerdir. Bunun için Brew editörünü kullanın ya da ajana yalnızca bu değişikliklerle sınırlı bir edit_email çağrısı yaptırın. Bu, kredi harcayan bir yapay zekâ düzenlemesidir; önizlemeyi kontrol edin. Söz dizimi Birleştirme etiketleri sayfasında.
Ajan, save_trigger aracıyla bir tetikleyici oluşturur. Payload şeması alıcının email alanını içermelidir. Tetikleyiciye tipli bir sözleşme tanımlayın (infer_payload_contract örnek bir payload verisinden taslağını çıkarır, set_trigger_contract kaydeder), ardından sözleşmeyi get_trigger_contract ile ts ya da zod biçiminde alın; böylece sunucunuz ve Brew, payload yapısı konusunda aynı şeyi bilir.
Ardından save_automation aracı tetikleyiciyi ve e-postayı, alan adını ve konu satırını içeren bir “E-posta gönder” adımını kurar. Otomasyon, siz yayımlayana kadar taslak olarak kalır. dryRun grafı doğrular, test_automation adresinize gerçek bir kopya gönderir, check_trigger ise üretim ortamı herhangi bir şeyi tetiklemeden önce yayımlanmış bir otomasyonun tetikleyiciyi dinlediğini doğrular.
Uygulama kodunuzdaki tek değişiklik budur. Önce, Resend ile:
await resend.emails.send({
from: 'Acme <hello@acme.com>',
to: user.email,
subject: 'Welcome to Acme',
react: <WelcomeEmail firstName={user.firstName} planName={plan.name} />,
})Sonra, Brew ile:
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, sunucu isteği reddettiğinde bile hata fırlatmaz; bu yüzden res.ok değerini kontrol edin ve yeniden denemeyi ya da uyarıyı iş çalıştırıcınıza bırakın. Uç nokta, olayı kabul ettiğinde 202, tetikleyiciyi dinleyen yayımlanmış bir otomasyon yoksa 422 döndürür.
Idempotency-Key değerini kullanıcı ya da sipariş kimliği gibi sabit bir kimlikten oluşturun. Tekrarlanan bir anahtar, e-postayı ikinci kez göndermek yerine ilk çalıştırmayı döndürür; aynı anahtarı farklı bir istek gövdesiyle yeniden kullanırsanız 409 IDEMPOTENCY_CONFLICT yanıtı alırsınız. Brew bir tetiklemenin anahtarını, tetikleyicinin alındı kaydı durduğu sürece saklar; bu süre, birçok API’nin kullandığı 24 saat değil, 90 gündür. Anahtarları kalıcı kabul edin ve her eylem için ayrı bir anahtar kullanın. Zaman damgasından üretilen bir anahtar her yeniden denemede değişir; haftalar sonra farklı bir eylem için yeniden kullanılan bir anahtar ise gönderim yerine önceki çalıştırmanın tekrarı olarak işlenebilir.
Üretim ortamındaki kod bu uç noktayı MCP ile değil, bir API anahtarıyla çağırır. OAuth üzerinden MCP canlı gönderimler, tetiklemeler ve yayımlama için bir kişinin onayını ister: Bu bir sohbet için doğru, bir istek işleyici (request handler) için yanlıştır. Bu iş bölümünü MCP ve REST API rehberi anlatıyor.
EMAILS.md dosyasını güncelleyin.Loops’tan geçiş rehberi de aynı yöntemi izliyor.
Supabase’in onay ve sihirli bağlantı e-postaları Supabase’ten gelmeye devam eder. Brew içindeki Supabase entegrasyonu, Supabase Auth e-postalarının yerini almak yerine otomasyonları başlatmak için kullanıcı olaylarını dinler. Gönderim anında karmaşık verilerden oluşturulan kalem kalem bir fatura da kodda daha basit kalabilir; bu yüzden önce birleştirme etiketlerinizin neye ihtiyaç duyduğunu kontrol edin. Bu e-postalar da görünür kalsın diye içe aktarılmış kopyalarını tuvalde tutun.
Setin tamamını denetleyin. Bir grubun tamamında audit_email aracını çalıştırın, sorunları düzeltin ve büyük gönderimlerden önce denetimi yeniden çalıştırın.
Gerçek istemcileri kontrol edin. test_email_rendering, belirli e-posta istemcilerinden ve cihazlardan karanlık mod dâhil ekran görüntüleri döndürür; her çalıştırma 10 kredi tutar. create_inbox_placement_test ise test gelen kutularına gerçek bir kopya gönderir ve e-postanın nereye düştüğünü raporlar; bu da 10 kredi tutar.
Seti tutarlı hâle getirin. Tutarsızlıkları editörde düzeltin ya da yeni bir alt bilgi gibi tek bir değişikliği ajana edit_email ile bir grubun tamamına uygulatın.
Sonuçları okuyun. get_email_analytics gönderimleri ve etkileşimi raporlar. list_insights ise Brew tarafından hesabınızda tespit edilen bulguları, her birinin dayandığı metriklerle birlikte döndürür.
Versiyonları bilinçli olarak test edin. Tuvalde versiyonlar oluşturun ve kişileri, örneğin tıklayıp tıklamadıkları gibi davranışlara göre bir Dallanma adımıyla yönlendirin. Brew, rastgele bölmede kazananı sizin yerinize seçmez; bu yüzden versiyonları kendiniz karşılaştırın.
Yeni e-postaları görünür tutun. AGENTS.md ya da benzeri bir dosyaya şu kuralı ekleyin: Yeni ürün e-postaları Brew içinde oluşturulur, bir tetikleyiciyle tetiklenir ve aynı pull request içinde EMAILS.md dosyasına eklenir.
Evet. import_email aracı HTML çıktısını, MJML’i, kaydedilmiş bir .eml mesajını ya da bir React Email modülünü kabul eder. En güvenilir seçenek HTML çıktısıdır, çünkü modül statik olarak okunur: Props değerleri varsayılan ya da önizleme değerlerine dönüşür, diğer yerel dosyalardan içe aktarılan bileşenler ise dışarıda kalır.
Hayır. Resend entegrasyonu, Resend’den içe aktarma ya da Resend’e dışa aktarma yoktur. Kodunuzun ürettiği HTML’i içe aktarırsınız; geçiş yaparsanız da kodunuz Resend’i çağırmak yerine bir Brew tetikleyicisini tetikler.
Hayır. MCP’yi kurulum, içe aktarma, denetim ve test için bir kodlama ajanı üzerinden kullanın. Üretim ortamındaki kod REST API’yi bir API anahtarıyla çağırmalıdır; çünkü OAuth bağlantılarında MCP, canlı gönderimler ve tetiklemeler için bir kişinin onayını ister.
İçe aktarma, e-postayı düzenlenebilir bir Brew tasarımına dönüştürür ve gönderim için orijinal kaynak HTML’i korur. Betikleri, iframe öğelerini, formları ve olay işleyicilerini kaldırır; mevcut izleme piksellerini etkisiz hâle getirir ve herkese açık görselleri yeniden barındırır. Her birini Brew içinden göndermeden önce tuvalde, masaüstü ve mobil görünümde inceleyin.
