# Migrasi dari MailerSend

Halaman ini memetakan payload pengiriman, daftar supresi, dan webhook MailerSend ke Bird. Ikuti [panduan migrasi utama](/docs/guides/email/migrate) secara berurutan, dan gunakan pemetaan ini untuk langkah 1, 3, dan 4.

MailerSend menyimpan lima daftar supresi dan salah satunya bersifat sementara. Baca [Ekspor supresi](#ekspor-supresi) sebelum langkah 3: mengimpor daftar tersebut mengubah penahanan 72 jam menjadi pemblokiran permanen.

## Berikan ini ke agen Anda

Tempelkan ini ke Claude Code, Cursor, atau Codex. Agen akan mengerjakan halaman ini terhadap repositori Anda, menggunakan permukaan Bird mana pun yang sudah tersedia: server MCP jika sudah terhubung, atau CLI jika sudah terinstal dan login.

```text
I am moving an email integration from MailerSend to Bird. Route through it with me.
1. Check what you already have before setting anything up. If Bird's MCP server is connected, use its tools. If the Bird CLI is installed and signed in, use that. Either one is enough, and every step below is an action you take with whichever you have. Only if neither is present, follow https://bird.com/docs/ai/set-up-your-agent.md to set one up and sign me in. Every Bird docs page serves Markdown at its own URL with `.md` appended, so fetch that rather than the HTML.
2. Read https://bird.com/docs/guides/email/migrate/mailersend.md for the payload, suppression and webhook mapping, and https://bird.com/docs/guides/email/migrate.md for the order the steps go in.
3. Find and list my MailerSend usage in this repository before you change anything: calls to /v1/email and any SDK wrappers around them, whether I send with template_id and personalization or with html, the webhook handler and the URL it is registered at, and every domain I send from. Tell me the list before you edit anything.
4. Register each of those sending domains with Bird and give me the DNS records to publish, following https://bird.com/docs/guides/email/sending-domains.md. Leave every DNS record MailerSend uses exactly as it is: Bird's records are published alongside them and both providers authenticate side by side until I switch traffic. Publishing DNS affects mail for the whole domain, so show me the records and let me publish them.
5. Export my suppressions and import them into Bird before any production traffic goes through Bird, so my first sends do not reach addresses that already bounced or complained. MailerSend keeps five lists under /v1/suppressions: hard bounces, spam complaints, unsubscribes and the blocklist are the four to carry over. Do NOT import the On Hold list: it is a temporary 72-hour hold that MailerSend clears by itself, and importing it would suppress those addresses permanently. The Bird import takes one address per request and is idempotent, so a partial re-run is safe. https://bird.com/docs/guides/email/suppressions.md has the reason taxonomy.
6. Port the send call and the webhook handler using the mapping tables on the provider page. Both providers sign with HMAC-SHA256, so this is a re-implementation rather than new code: MailerSend sends one Signature header, Bird follows the Standard Webhooks scheme with webhook-id, webhook-timestamp and webhook-signature, and the signed string is constructed differently. Keep the constant-time comparison. https://bird.com/docs/guides/webhooks.md and https://bird.com/docs/guides/email/events.md.
7. Run my whole integration against Bird's mail sandbox before any production traffic, following https://bird.com/docs/guides/email/testing-sandbox.md. Sandbox sends run the real pipeline without reaching an inbox or touching my sending reputation.
8. Stop and ask me wherever a step needs a decision. Do not point production traffic at Bird until I have seen the sandbox results and replied with the words cut over to Bird. Retiring the MailerSend path is a separate step that comes later: ask me again and wait for me to reply with the words retire the MailerSend path. A reply that agrees without naming what it is authorising is not authorisation. Finish by telling me what is left that only a person can do.
```

## Petakan panggilan pengiriman

`POST /v1/email` milik MailerSend dan [`POST /v1/email/messages`](/docs/api/reference/create-email-message) kami memiliki struktur serupa. Perbedaan yang perlu diubah dalam kode adalah batas tag dan cara data per-penerima dibawa.

| Fungsi                    | MailerSend                                                 | Bird                                                   |
| ------------------------- | ---------------------------------------------------------- | ------------------------------------------------------ |
| Pengirim                  | `from` (`{email, name}`)                                   | `from`                                                 |
| Penerima                  | `to` (maks 50), `cc` / `bcc` (maks 10 masing-masing)       | `to` / `cc` / `bcc` (array)                            |
| Subjek                    | `subject` (maks 998 karakter)                              | `subject`                                              |
| Isi                       | `html` / `text`                                            | `html` / `text` (minimal satu)                         |
| Reply-to                  | `reply_to` (`{email, name}`)                               | `reply_to` (array)                                     |
| Header kustom             | `headers` (`{name, value}`, paket lebih tinggi)            | `headers` (objek string → string)                      |
| Label yang dapat difilter | `tags` (array of strings, maks 5)                          | pasangan `tags`: `{name, value}`                       |
| Template tersimpan        | `template_id` + `personalization`                          | `template` + `template.parameters` (lihat di bawah)    |
| Lampiran                  | `attachments` (`content`, `filename`, `disposition`, `id`) | `attachments`                                          |
| Penjadwalan               | `send_at` (hingga 72 jam ke depan)                         | `scheduled_at`                                         |
| Prioritas bulk            | `precedence_bulk`                                          | (tidak ada padanan, lihat di bawah)                    |
| Kategori                  | (tidak ada)                                                | `category`: `marketing` (default) atau `transactional` |
| Threading                 | `in_reply_to`                                              | `headers`                                              |

Batas field dan nilai default kami (jumlah penerima, batas tag dan metadata) ada di [Mengirim email](/docs/guides/email/sending-email).

Catatan porting:

- **Alamat berupa objek di sana dan string di sini.** `{"email": "a@x.com", "name": "A"}` menjadi `"A <a@x.com>"` atau cukup `"a@x.com"`, untuk `from`, `to`, `cc`, `bcc` maupun `reply_to`.
- **`tags` adalah string biasa dengan batas lima. Tag kami berupa pasangan.** Tag seperti `"welcome"` menjadi `{"name": "category", "value": "welcome"}`. Pilih `name` yang stabil agar dasbor Anda memfilter seperti statistik tag MailerSend sebelumnya.
- **`personalization` adalah data template per-penerima.** Ini berupa array yang dikunci berdasarkan email penerima. `template.parameters` kami berlaku untuk seluruh pengiriman, jadi pesan yang kontennya benar-benar berbeda per penerima harus menjadi satu pengiriman per penerima atau masing-masing satu entri [batch](/docs/guides/email/sending-bulk). Jika array `personalization` Anda berisi nilai yang sama untuk setiap penerima, array tersebut dapat disederhanakan menjadi satu objek `template.parameters`.
- **Konteks round-trip tidak memiliki padanan di MailerSend untuk disalin.** Jika sebelumnya Anda merekonstruksi konteks dari `tags`, gunakan [`metadata`](/docs/guides/email/sending-email) sebagai gantinya: kami mengembalikannya di setiap event webhook bersama `email_id`/`recipient_id`, dan tidak dibatasi lima entri.
- **`precedence_bulk` tidak memiliki padanan, dan `category` bukan padanannya.** `precedence_bulk` menyetel header `Precedence: bulk`, yang meminta autoresponder dan agen out-of-office untuk tidak membalas. `category` kami menentukan catatan supresi dan preferensi berhenti berlangganan mana yang boleh memblokir pesan, dan hanya itu. Menyetel `category` sebagai gantinya mengubah perilaku supresi dan tidak melakukan apa pun terhadap autoresponder. Jika Anda membutuhkan header tersebut, perlu diketahui bahwa `headers` menolak nama alamat dan platform tetapi bukan header ini.
- **Header kustom dan `list_unsubscribe` dibatasi berdasarkan paket di MailerSend.** Jika paket Anda tidak menyertakannya, fitur tersebut tersedia di sini; lihat [mengirim email](/docs/guides/email/sending-email) dan [kategori](/docs/guides/email/categories) untuk cara kami menangani list-unsubscribe pada email pemasaran.

## Ekspor supresi

MailerSend menyimpan lima daftar di bawah `/v1/suppressions`, satu endpoint per daftar. Empat bersifat permanen dan perlu dipindahkan; yang kelima tidak boleh.

Ekspor dan jalankan melalui [loop impor](/docs/guides/email/migrate#3-import-suppressions):

- **Hard bounce**, misalnya `GET https://api.mailersend.com/v1/suppressions/hard-bounces`
- **Keluhan spam**
- **Berhenti berlangganan**
- **Blocklist**, alamat dan pola yang Anda tambahkan secara manual

**Jangan impor daftar On Hold.** Deskripsi MailerSend sendiri menyatakan bahwa daftar ini menampung alamat yang "have soft bounced 5 times within 30 days", yang "these emails will be blocked for 72 hours", dan kemudian "automatically removed from the list". Ini adalah periode pendinginan yang dibersihkan sendiri oleh penyedia, jadi mengimpornya mengubah penahanan sementara menjadi supresi permanen dan secara diam-diam menghentikan pengiriman ke alamat yang akan segera dirilis. Padanan perilaku tersebut di sistem kami adalah [deferral](/docs/guides/email/events), yang kami tangani dari hasil pengiriman langsung, bukan dari daftar yang diimpor.

Jenis daftar MailerSend dipetakan ke alasan `hard_bounce`, `complaint`, dan `manual` milik kami; [Supresi](/docs/guides/email/suppressions) memiliki taksonomi lengkapnya.

## Terjemahkan event webhook

| Hasil                 | MailerSend                                     | Bird                                             |
| --------------------- | ---------------------------------------------- | ------------------------------------------------ |
| Diterima/diproses     | `activity.sent`                                | `email.accepted` → `email.processed`             |
| Terkirim              | `activity.delivered`                           | `email.delivered`                                |
| Kegagalan sementara   | `activity.soft_bounced` / `activity.deferred`  | `email.deferred`                                 |
| Bounce permanen       | `activity.hard_bounced`                        | `email.bounced` / `email.out_of_band_bounce`     |
| Keluhan spam          | `activity.spam_complaint`                      | `email.complained`                               |
| Dibuka                | `activity.opened` / `activity.opened_unique`   | `email.opened`                                   |
| Diklik                | `activity.clicked` / `activity.clicked_unique` | `email.clicked`                                  |
| Berhenti berlangganan | `activity.unsubscribed`                        | `email.unsubscribed` / `email.list_unsubscribed` |
| Ditahan sementara     | `recipient.on_hold_added` / `..._removed`      | (tidak ada padanan; lihat di atas)               |

Dua perbedaan menentukan seberapa banyak handler Anda perlu diubah.

**Kedua sisi menandatangani dengan HMAC-SHA256, jadi ini adalah implementasi ulang, bukan kode baru.** MailerSend mengirim satu header `Signature` yang berisi hash payload yang dihitung dengan signing secret webhook tersebut. Kami mengikuti skema [Standard Webhooks](https://www.standardwebhooks.com), yang menggunakan `webhook-id`, `webhook-timestamp` dan `webhook-signature` serta menandatangani string yang dibangun dari id, timestamp, dan body, sehingga timestamp juga memberikan perlindungan replay. Pertahankan perbandingan constant-time yang sudah Anda miliki dan ganti konstruksinya; resepnya ada di [Webhook dan event](/docs/guides/webhooks).

**MailerSend membedakan open dan click dari varian uniknya. Kami tidak.** `activity.opened` dan `activity.opened_unique` keduanya diterima sebagai `email.opened`, jadi handler yang sebelumnya hanya menghitung varian unik perlu melakukan deduplikasi pada `recipient_id` sendiri. Event pengiriman kami berskala per penerima, jadi satu pengiriman ke tiga penerima menghasilkan tiga hasil pengiriman, bukan satu.

## Peralihan

Kerjakan [domain dan DNS](/docs/guides/email/migrate#2-re-point-domains-and-dns) serta [uji coba sandbox](/docs/guides/email/migrate#5-verify-in-the-sandbox-before-cutover) di panduan utama. Keduanya tidak bergantung pada penyedia.

## Langkah selanjutnya

- [Domain pengirim](/docs/guides/email/sending-domains): pendaftaran, siklus verifikasi, dan catatan DNS yang Anda publikasikan
- [Webhook dan event](/docs/guides/webhooks): pengaturan endpoint dan verifikasi Standard Webhooks
- [Sandbox pengujian](/docs/guides/email/testing-sandbox): uji coba integrasi baru sebelum peralihan
- [Supresi](/docs/guides/email/suppressions): konfirmasi daftar yang diimpor dan cara kami mengelolanya selanjutnya

## Related resources

- [Getting started with email](/learn/email/getting-started-with-email) (video)
- [Email](/products/email) (product)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=email)
