# อีเมลในโค้ด: มองให้เห็น ย้ายระบบ และปรับปรุงให้ดีขึ้น

URL หลัก: https://brew.new/th/blog/emails-in-code-visibility-migration-mcp
ผู้เขียน: Thomas Park
เผยแพร่: 2026-10-12
อัปเดต: 2026-10-15

อีเมลในโค้ดคืออีเมลของผลิตภัณฑ์ที่กำหนดไว้ใน codebase และปล่อยออกไปเหมือนฟีเจอร์อื่น ๆ ลองถามทีมที่ใช้ Resend และ React Email ว่าผลิตภัณฑ์ส่งอีเมลอะไรบ้าง แล้วคุณจะเจอความเงียบไปครู่หนึ่ง อีเมลต้อนรับเป็นคอมโพเนนต์ในโฟลเดอร์ `emails/` อีเมลรีเซ็ตรหัสผ่านอยู่ในแดชบอร์ดของผู้ให้บริการระบบยืนยันตัวตน อีเมลแจ้งช่วงทดลองใช้ใกล้สิ้นสุดเป็นสตริงใน cron job ใบเสร็จส่งโดย Stripe และไม่มีใครจำได้ว่าอะไรเป็นตัวส่งอีเมล “เราคิดถึงคุณ”

อีเมลแต่ละฉบับปล่อยออกไปได้ง่าย จึงไม่มีใครดูแลภาพรวมทั้งหมด เราจะแก้ปัญหานี้ตามลำดับ คือทำให้มองเห็นก่อน แล้วจึงย้ายระบบ จากนั้นจึงปรับปรุง เอเจนต์เขียนโค้ดที่คุณใช้อยู่แล้วทำงานส่วนใหญ่นี้ได้ เมื่อเชื่อมต่อกับ Brew ผ่าน MCP

## ประเด็นสำคัญ

- เริ่มจากการทำบัญชีรายการอีเมล (inventory) ไม่ใช่เครื่องมือใหม่ โดยครอบคลุมอีเมลทุกฉบับ พร้อมทริกเกอร์ ไฟล์ และตัวแปรของแต่ละฉบับ
- เอเจนต์เขียนโค้ดหาจุดที่เรียกส่งอีเมล แสดงผลแต่ละเทมเพลต และนำเข้าด้วยเครื่องมือ MCP `import_email` ได้ การนำเข้าเป็นแบบเชิงกำหนด (deterministic) ไม่ใช้ AI และไม่มีค่าใช้จ่าย
- อีเมลที่นำเข้าจะไปอยู่บนแคนวาส 1 แคนวาสต่อกลุ่ม ทีมจึงตรวจทานอีเมลเทียบกันได้ทั้งบนเดสก์ท็อปและมือถือ
- เมื่อย้ายระบบ การส่งแบบ Resend จะกลายเป็นทริกเกอร์คู่กับระบบอัตโนมัติที่เผยแพร่แล้ว ซึ่งเรียกให้ทำงานด้วยการเรียก REST เพียงครั้งเดียว โค้ดที่ใช้งานจริงใช้ REST ไม่ใช่ MCP
- ย้ายทีละประเภทอีเมลโดยวางไว้หลังแฟล็ก และย้ายอีเมลธุรกรรมเป็นลำดับสุดท้าย

## ทำไมอีเมลที่กำหนดไว้ในโค้ดจึงมองไม่เห็น

React Email และ Resend ทำให้งานอีเมลดีขึ้นมากสำหรับนักพัฒนา ทั้งคอมโพเนนต์แบบมีไทป์และการตรวจทานผ่าน pull request แต่ราคาที่ต้องจ่ายจะปรากฏทีหลัง

**อีเมลกระจัดกระจาย:** มีทั้งคอมโพเนนต์, HTML แบบอินไลน์ในงานเบื้องหลัง, เทมเพลตในแดชบอร์ดของบริการภายนอก และอีเมลที่บริการอื่นส่งแทนคุณ ไม่มีไฟล์ไหนรวบรวมอีเมลไว้ครบทั้งหมด

**ตัวอย่างไม่ใช่ของจริง:** เซิร์ฟเวอร์พรีวิวของ React Email แสดงเทมเพลตทีละตัวด้วย props ตัวอย่าง ไม่ใช่สิ่งที่ลูกค้าได้รับจริง และไม่แสดงอะไรเลยสำหรับเทมเพลตอื่น

**มีแต่วิศวกรที่ดูได้:** ทีมผลิตภัณฑ์ ทีมออกแบบ และฝ่ายสนับสนุนต้องขอให้วิศวกรรันโปรเจกต์ให้ดู ส่วนใหญ่จึงไม่มีใครขอ

**ไม่มีใครตรวจทานหลังเปิดใช้งาน:** อีเมลที่ใช้มา 2 ปียังมีโลโก้เก่าและแพ็กเกจที่คุณเลิกขายไปแล้ว ไม่มีใครสังเกตเห็น เพราะไม่มีใครเห็นอีเมลทั้งหมดพร้อมกัน

## ขั้นตอนที่ 1: การมองเห็นภาพรวม

เป้าหมายคือมุมมองเดียวที่ทุกคนเห็นอีเมลทุกฉบับร่วมกัน ขั้นตอนนี้ไม่แตะต้องระบบที่ใช้งานจริงเลย

![3 ระยะของการย้ายอีเมลออกจากโค้ด: การมองเห็นภาพรวมด้วย import_email และแคนวาสแยกตามกลุ่ม, การย้ายระบบด้วยโดเมน ผู้ติดต่อ ทริกเกอร์ และระบบอัตโนมัติ, การปรับปรุงประสิทธิภาพด้วยการตรวจคุณภาพ การทดสอบการแสดงผล และการวิเคราะห์](/images/blog/emails-in-code-three-phases.png)

*แต่ละระยะมีประโยชน์ในตัวเอง และคุณจะหยุดหลังระยะใดก็ได้*

### เชื่อมต่อเอเจนต์เขียนโค้ดของคุณกับ Brew

เซิร์ฟเวอร์ MCP ของ Brew อยู่ที่ `https://brew.new/api/mcp` และใช้ OAuth โดยคุณเข้าสู่ระบบด้วย Brew และเลือกแบรนด์ที่เอเจนต์ทำงานได้ ใน Claude Code:

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

การเพิ่มเซิร์ฟเวอร์เป็นเพียงการบันทึกการกำหนดค่าในเครื่องสำหรับโปรเจกต์นี้ ใส่ `--scope user` หากต้องการใช้ในทุกโปรเจกต์ ทั้งนี้ ก่อนใช้เครื่องมือของ Brew ให้รัน `claude mcp login brew` หรือเปิด `/mcp` แล้วยืนยันตัวตนกับ Brew

[เอกสารการตั้งค่าไคลเอนต์](https://docs.brew.new/api-reference/mcp/connect-your-client)มีวิธีตั้งค่าสำหรับ Cursor และ Codex ด้วย ไคลเอนต์ที่ไม่รองรับ OAuth ใช้คีย์ API ระดับแบรนด์ได้ จากนั้นให้เอเจนต์เรียก `get_brew_capabilities` เพื่ออ่านรายการเครื่องมือที่ใช้งานได้ในปัจจุบันแทนการเดา

### สร้างบัญชีรายการอีเมล

ขอให้เอเจนต์ทำรายการให้:

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

เก็บส่วน “Unknown” ไว้ อีเมลยืนยันจากระบบยืนยันตัวตนและใบเสร็จของ Stripe ไม่ได้ถูกส่งจากโค้ดของคุณ แต่ก็ควรอยู่ในรายการด้วย จากนั้น commit ไฟล์ `EMAILS.md` ต่อให้หยุดแค่ตรงนี้ คุณก็ยังได้รายการที่เมื่อวานยังไม่มี

### แสดงผลแต่ละเทมเพลตด้วยข้อมูลที่สมจริง

อินพุตที่ดีที่สุดสำหรับการนำเข้าคือ HTML ที่โค้ดของคุณสร้างอยู่แล้ว [ยูทิลิตี render](https://react.email/docs/utilities/render) ของ React Email ให้สตริงนั้นมา:

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

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

โปรเจกต์รุ่นเก่านำเข้า `render` จาก `@react-email/render` ให้ใช้ fixture ที่สมจริง ไม่ใช่ `"test"` เพราะทีมของคุณจะตรวจทานอีเมลเหล่านี้ และให้เอเจนต์เขียนสคริปต์แสดงผลทุกเทมเพลตออกมาเป็นไฟล์

Brew ยังนำเข้าโมดูล React Email ได้โดยตรงด้วย `format: "jsx"` โดยอ่านโค้ดแบบสแตติกโดยไม่รันโค้ดนั้น ค่า props จะมาจากค่าเริ่มต้นหรือ `PreviewProps` ส่วนคอมโพเนนต์ที่นำเข้าจากไฟล์อื่นในโปรเจกต์จะถูกตัดทิ้งหรือถูกปฏิเสธ และ `await` หรือไวยากรณ์ทำนองเดียวกันจะไม่ได้รับอนุญาต หากเกินกว่าไฟล์เดียวที่สมบูรณ์ในตัว ให้ใช้ HTML ที่แสดงผลแล้ว

### นำเข้าทุกอย่างไว้ในที่เดียว

จากนั้นนำเข้าไฟล์ที่แสดงผลแล้วแต่ละไฟล์ด้วย `import_email` โดยแยก `groupName` ตามส่วนของผลิตภัณฑ์:

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

นักพัฒนามักถามว่าการนำเข้าจะเขียนอีเมลของตนใหม่หรือไม่ ซึ่งเป็นคำถามที่สมเหตุสมผล คำตอบคือไม่:

- เป็นคอมไพเลอร์แบบเชิงกำหนด (deterministic) ไม่ใช่โมเดล AI และไม่ใช้เครดิต
- ผลลัพธ์คือดีไซน์ใน Brew ที่แก้ไขได้ ขณะที่การส่งจริงยังใช้ HTML ต้นฉบับสำหรับแถวที่นำเข้ามา
- ระบบจะโฮสต์รูปภาพสาธารณะใหม่ และ `assetReport` จะแสดงรายการรูปที่ดึงมาไม่ได้
- ระบบจะลบสคริปต์, iframe, ฟอร์ม และตัวจัดการเหตุการณ์ (event handler) ออก และทำให้พิกเซลติดตามการเปิดที่มีอยู่เดิมใช้งานไม่ได้
- ซอร์สแต่ละรายการมีขนาดได้สูงสุด 5 MB และไม่มีช่องรับ URL เพราะเครื่องมือนี้รับมาร์กอัปโดยตรง ส่วน `baseUrl` ใช้แค่แปลงพาธรูปภาพแบบสัมพัทธ์

### ตรวจทานอีเมลร่วมกันทั้งทีม

แต่ละกลุ่มจะได้แคนวาสของตัวเอง เปิด `brew.new/emails/onboarding` แล้วคุณจะเห็นลำดับอีเมลทั้งชุดวางเรียงกัน พร้อมสวิตช์สลับมุมมองเดสก์ท็อปกับมือถือ และความคิดเห็นในแต่ละดีไซน์ ลิงก์แคนวาสใช้ได้กับคนที่เข้าสู่ระบบเวิร์กสเปซ Brew ของคุณ และไม่มีลิงก์แชร์แบบสาธารณะ จึงต้องเชิญผู้ตรวจทานเข้ามา

ตรงนี้เองที่ปัญหาจะโผล่ขึ้นมา เช่น โลโก้ 2 แบบ ลิงก์ปุ่มที่เสีย หรือส่วนท้าย 3 แบบ ให้เรียกใช้ `audit_email` ก่อนแก้ไขอะไร เครื่องมือนี้ตรวจลิงก์ รูปภาพ การปฏิบัติตามข้อกำหนด ขนาดเมื่อโหลด การรองรับของแอปอีเมล การเข้าถึงได้ และข้อความ ใช้ 5 เครดิตต่อการตรวจคุณภาพแบบสมบูรณ์ 1 ครั้ง และรับได้ทั้ง `emailId` ที่บันทึกไว้หรือ HTML ดิบ คุณจึงตรวจคุณภาพอีเมลที่ยังไม่ได้นำเข้าได้ด้วย [เช็กลิสต์ตรวจคุณภาพก่อนส่ง](/th/blog/pre-send-email-qa-checklist)ของเราอธิบายแต่ละจุดตรวจและเกณฑ์ไว้

ตอนนี้คุณมีบัญชีรายการอีเมล อีเมลทุกฉบับอยู่บนแคนวาส และมีรายการปัญหาแล้ว ขณะที่โค้ดของคุณยังส่งทุกอย่างเหมือนเดิม

## ขั้นตอนที่ 2: การย้ายระบบ

ถึงตอนนี้ Brew จะส่งอีเมลบางฉบับแทนโค้ดของคุณ ไม่จำเป็นต้องย้ายอีเมลทุกฉบับ และอีเมลแต่ละประเภทควรถูกส่งจากระบบเดียวในแต่ละช่วงเวลา

### จับคู่แนวคิด

| ในโค้ดของคุณตอนนี้ | ใน Brew |
| --- | --- |
| `resend.emails.send({ react: <WelcomeEmail /> })` | เหตุการณ์ทริกเกอร์ คู่กับระบบอัตโนมัติที่เผยแพร่แล้วซึ่งมีขั้นตอนส่งอีเมล 1 ขั้น |
| props ที่ส่งให้คอมโพเนนต์ | ฟิลด์ในเพย์โหลดของทริกเกอร์ ซึ่งใช้เป็นแท็กตัวแปร เช่น `{{ firstName \| there }}` หรือ `{{ trigger.planName }}` |
| โดเมนใน `from` | โดเมนผู้ส่งที่ยืนยันแล้วใน Brew |
| ตารางผู้ใช้ของคุณ | ผู้ติดต่อ ซึ่งสร้างผ่าน REST API หรือการเชื่อมต่อ |
| cron job ที่ส่งลำดับอีเมล | ระบบอัตโนมัติที่มีขั้นตอนรอ ตัวกรอง และขั้นตอนส่งอีเมล |

### 1. ตั้งค่าโดเมนผู้ส่ง

เอเจนต์เรียก `create_domain` เพื่อรับระเบียน DNS แล้วเรียก `verify_domain` เมื่อระเบียนมีผลแล้ว โดเมนที่สร้างผ่าน MCP และ API จะเป็นโดเมนการตลาด สำหรับอีเมลรีเซ็ตรหัสผ่านและใบเสร็จ ให้ตั้งค่าโดเมนที่ตั้งวัตถุประสงค์เป็นธุรกรรมในแอป Brew โดเมนแบบนี้จะไม่ใส่ส่วนท้ายสำหรับยกเลิกการรับข่าวสาร และส่งถึงผู้ติดต่อที่ยกเลิกการรับข่าวสารแล้วด้วย [การยืนยันโดเมนผู้ส่ง](https://docs.brew.new/get-started/verify-your-sending-domain)อธิบายระเบียนต่าง ๆ ไว้

### 2. นำผู้ติดต่อเข้ามา

MCP อัปเดตผู้ติดต่อได้แต่สร้างใหม่ไม่ได้ ให้สร้างผู้ติดต่อจากแบ็กเอนด์ด้วย `POST /v1/contacts` ซึ่งเพิ่มหรืออัปเดต (upsert) ผู้ติดต่อได้ทีละ 1 รายหรือเป็นชุดสูงสุด 1,000 ราย และสร้างฟิลด์ที่กำหนดเองให้อัตโนมัติ หรืออัปโหลดไฟล์ CSV ในแอป การเรียกทริกเกอร์ก็สร้างหรืออัปเดตผู้ติดต่อที่อยู่ในเพย์โหลดด้วย นำเข้าเฉพาะคนที่ยินยอมรับข่าวสารจากคุณเท่านั้น [การเพิ่มผู้ติดต่อ](https://docs.brew.new/audience/add-contacts)อธิบายว่า Brew ต้องการข้อมูลแบบใด

### 3. แทนค่าตัวอย่างด้วยแท็กตัวแปร

จุดที่พลาดได้ง่าย: อีเมลต้อนรับที่นำเข้ามาจะมีคำว่า “Hi Ana” อยู่ตรงตัว ให้แทนค่าจาก fixture แต่ละค่าด้วยแท็กตัวแปร เช่น `{{ firstName | there }}` โดยข้อความหลังขีดตั้งคือค่าสำรอง ใช้ตัวแก้ไขของ Brew หรือให้เอเจนต์เรียกใช้ `edit_email` โดยจำกัดให้แก้แค่การแทนค่าเหล่านั้น การแก้ไขนี้เป็นการแก้ไขด้วย AI ที่ใช้เครดิต จึงควรตรวจตัวอย่างอีกครั้ง [แท็กตัวแปร](https://docs.brew.new/create-emails/merge-tags)แสดงไวยากรณ์ทั้งหมด

### 4. สร้างทริกเกอร์และระบบอัตโนมัติ

เอเจนต์สร้างทริกเกอร์ด้วย `save_trigger` โดยสคีมาเพย์โหลดต้องมี `email` ของผู้รับ กำหนดสคีมาเพย์โหลดแบบมีไทป์ให้ทริกเกอร์ (`infer_payload_contract` ร่างสคีมาจากเพย์โหลดตัวอย่าง และ `set_trigger_contract` บันทึกสคีมานั้น) แล้วดึงสคีมาด้วย `get_trigger_contract` ในรูปแบบ `ts` หรือ `zod` เพื่อให้แบ็กเอนด์ของคุณกับ Brew ใช้รูปแบบเพย์โหลดตรงกัน

จากนั้น `save_automation` จะสร้างทริกเกอร์พร้อมขั้นตอนส่งอีเมลที่ระบุอีเมล โดเมน และหัวเรื่อง ระบบอัตโนมัติจะยังเป็นฉบับร่างจนกว่าคุณจะเผยแพร่ ส่วน `dryRun` ใช้ตรวจสอบความถูกต้องของกราฟระบบอัตโนมัติ, `test_automation` ส่งสำเนาจริงไปยังที่อยู่อีเมลของคุณ และ `check_trigger` ยืนยันว่ามีระบบอัตโนมัติที่เผยแพร่แล้วรอรับทริกเกอร์อยู่ ก่อนที่ระบบที่ใช้งานจริงจะเรียกทริกเกอร์ใด ๆ

### 5. สลับจุดที่เรียกส่งอีเมล

นี่เป็นการเปลี่ยนแปลงเดียวในโค้ดแอปพลิเคชันของคุณ ก่อนหน้านี้ เมื่อใช้ 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} />,
})
```

หลังเปลี่ยน เมื่อใช้ 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` จะ resolve แม้คำขอถูกปฏิเสธ จึงต้องตรวจ `res.ok` และให้ตัวรันงาน (job runner) ลองใหม่หรือแจ้งเตือน เอนด์พอยต์จะตอบ `202` เมื่อรับเหตุการณ์ และตอบ `422` หากไม่มีระบบอัตโนมัติที่เผยแพร่แล้วรอรับทริกเกอร์นั้น

สร้าง `Idempotency-Key` จาก ID ที่คงที่ เช่น ID ผู้ใช้หรือ ID คำสั่งซื้อ คีย์ที่ซ้ำจะได้รอบการทำงานเดิมกลับมาแทนการส่งซ้ำ และการใช้คีย์เดิมกับเนื้อหาคำขอที่ต่างไปจะได้ `409 IDEMPOTENCY_CONFLICT` ทั้งนี้ Brew เก็บคีย์ของการเรียกทริกเกอร์แต่ละครั้งไว้นานเท่ากับบันทึกการรับทริกเกอร์ ซึ่งคือ 90 วัน ไม่ใช่ 24 ชั่วโมงอย่างที่ API จำนวนมากใช้ ให้ถือว่าคีย์เป็นของถาวร ใช้ 1 คีย์ต่อ 1 การกระทำ คีย์ที่สร้างจาก timestamp จะเปลี่ยนทุกครั้งที่ลองใหม่ และคีย์ที่นำกลับมาใช้กับการกระทำอื่นในอีกหลายสัปดาห์ต่อมาอาจกลายเป็นการเรียกซ้ำของครั้งก่อนแทนที่จะส่งอีเมลจริง

โค้ดที่ใช้งานจริงควรเรียกเอนด์พอยต์นี้ด้วยคีย์ API ไม่ใช่ผ่าน MCP เพราะเมื่อเชื่อมต่อผ่าน OAuth แล้ว MCP จะขอให้คนยืนยันก่อนการส่งจริง การเรียกทริกเกอร์ และการเผยแพร่ ซึ่งเหมาะกับการแชท แต่ไม่เหมาะกับ request handler [คู่มือ MCP กับ REST](/th/blog/mcp-vs-rest-api-for-email-marketing-which-workflow-should-you-use) อธิบายการแบ่งงานนี้

### 6. ย้ายทีละอีเมล

1. วางการเรียกแบบใหม่ไว้หลังฟีเจอร์แฟล็กคู่กับการเรียกแบบเดิม เพื่อให้การสลับกลับทำได้ด้วยการเปลี่ยนการกำหนดค่า
2. เริ่มจากอีเมลที่มีความเสี่ยงต่ำ เช่น อีเมลกระตุ้นตามวงจรชีวิตลูกค้า แล้วติดตามการนำส่งและการคลิกสักสองสามวัน
3. ย้ายลำดับอีเมลเป็นลำดับถัดไป เมื่อทริกเกอร์ของลำดับเหล่านั้นทำงานด้วยเพย์โหลดที่ถูกต้องแล้ว
4. ย้ายอีเมลธุรกรรมเป็นลำดับสุดท้าย เพราะผู้ใช้จะสังเกตเห็นอีเมลรีเซ็ตรหัสผ่านและ Magic Link ที่ใช้งานไม่ได้ก่อนอย่างอื่น
5. ลบเส้นทางเดิมทิ้งหลังผ่านไป 1 สัปดาห์โดยไม่มีปัญหา และอัปเดต `EMAILS.md`

[คู่มือการย้ายจาก Loops](https://docs.brew.new/migrations/loops) ก็ใช้รูปแบบเดียวกัน

### อีเมลที่ควรอยู่ในโค้ดต่อไป

อีเมลยืนยันและอีเมล Magic Link ของ Supabase ยังคงส่งจาก Supabase ต่อไป การเชื่อมต่อ Supabase ของ Brew รอรับเหตุการณ์ของผู้ใช้เพื่อเริ่มระบบอัตโนมัติ ไม่ได้มาแทนที่อีเมลของ Supabase Auth ส่วนใบแจ้งหนี้แบบแจกแจงรายการที่สร้างจากข้อมูลซับซ้อนตอนส่งก็อาจทำในโค้ดได้ง่ายกว่า จึงควรตรวจก่อนว่าแท็กตัวแปรของคุณต้องใช้อะไรบ้าง และเก็บสำเนาที่นำเข้าไว้บนแคนวาส เพื่อให้อีเมลเหล่านี้ยังมองเห็นได้

## ขั้นตอนที่ 3: การปรับปรุงประสิทธิภาพ

**ตรวจคุณภาพอีเมลทั้งชุด:** เรียกใช้ `audit_email` กับทั้งกลุ่ม แก้ไข แล้วเรียกใช้อีกครั้งก่อนการส่งขนาดใหญ่

**ตรวจในแอปอีเมลจริง:** `test_email_rendering` ส่งภาพหน้าจอจากแอปอีเมลและอุปกรณ์ที่ระบุกลับมา รวมถึงโหมดมืด โดยใช้ 10 เครดิตต่อการรัน 1 ครั้ง ส่วน `create_inbox_placement_test` ส่งสำเนาจริงไปยังอินบ็อกซ์ทดสอบและรายงานว่าอีเมลไปตกที่ใด โดยใช้ 10 เครดิตเช่นกัน

**ทำให้อีเมลทั้งชุดสอดคล้องกัน:** แก้จุดที่ไม่สอดคล้องกันในตัวแก้ไข หรือให้เอเจนต์ใช้ `edit_email` ปรับการเปลี่ยนแปลงเดียวกัน เช่น ส่วนท้ายแบบใหม่ กับทั้งกลุ่ม

**อ่านผลลัพธ์:** `get_email_analytics` รายงานการส่งและการมีส่วนร่วม ส่วน `list_insights` แสดงสิ่งที่ Brew ตรวจพบในบัญชีของคุณ พร้อมตัวชี้วัดเบื้องหลังของแต่ละรายการ

**ทดสอบแต่ละแบบอย่างตั้งใจ:** สร้างอีเมลหลายแบบบนแคนวาส แล้วส่งผู้ติดต่อไปตามเส้นทางด้วยขั้นตอนแยกเส้นทางตามพฤติกรรม เช่น เคยคลิกหรือไม่ Brew ไม่ได้เลือกผู้ชนะจากการแยกแบบสุ่มให้คุณ คุณจึงต้องเปรียบเทียบแต่ละแบบเอง

**ทำให้อีเมลใหม่ยังมองเห็นได้:** เพิ่มบรรทัดหนึ่งใน `AGENTS.md` หรือไฟล์ทำนองเดียวกันว่า อีเมลผลิตภัณฑ์ฉบับใหม่ให้สร้างใน Brew เรียกส่งด้วยทริกเกอร์ และเพิ่มลงใน `EMAILS.md` ใน pull request เดียวกัน

## คำถามที่พบบ่อย

### Brew นำเข้าเทมเพลต React Email ได้ไหม?

ได้ โดย `import_email` รับ HTML ที่แสดงผลแล้ว, MJML, ข้อความ `.eml` ที่บันทึกไว้ หรือโมดูล React Email ทั้งนี้ HTML ที่แสดงผลแล้วเชื่อถือได้มากที่สุด เพราะโมดูลจะถูกอ่านแบบสแตติก ค่า props จะกลายเป็นค่าเริ่มต้นหรือค่าตัวอย่าง และคอมโพเนนต์ที่นำเข้าจากไฟล์อื่นในโปรเจกต์จะถูกตัดออก

### Brew เชื่อมต่อกับบัญชี Resend ของฉันได้ไหม?

ไม่ได้ เพราะไม่มีการเชื่อมต่อ การนำเข้า หรือการส่งออกกับ Resend คุณนำเข้า HTML ที่โค้ดของคุณแสดงผล และหากย้ายระบบ โค้ดของคุณจะเรียกทริกเกอร์ของ Brew แทนการเรียก Resend

### แบ็กเอนด์ของฉันควรเรียก Brew ผ่าน MCP ไหม?

ไม่ควร ให้ใช้ MCP จากเอเจนต์เขียนโค้ดสำหรับการตั้งค่า การนำเข้า การตรวจคุณภาพ และการทดสอบ ส่วนโค้ดที่ใช้งานจริงควรเรียก REST API ด้วยคีย์ API เพราะในการเชื่อมต่อผ่าน OAuth นั้น MCP จะขอให้คนยืนยันก่อนการส่งจริงและการเรียกทริกเกอร์

### การนำเข้าอีเมลทำให้หน้าตาอีเมลเปลี่ยนไปไหม?

การนำเข้าจะแปลงอีเมลเป็นดีไซน์ใน Brew ที่แก้ไขได้ และเก็บ HTML ต้นฉบับไว้ใช้ส่งจริง โดยจะตัดสคริปต์, iframe, ฟอร์ม และตัวจัดการเหตุการณ์ออก ทำให้พิกเซลติดตามที่มีอยู่เดิมใช้งานไม่ได้ และโฮสต์รูปภาพสาธารณะใหม่ ตรวจทานแต่ละฉบับบนแคนวาสทั้งในมุมมองเดสก์ท็อปและมือถือก่อนส่งจาก Brew
