Postmark से माइग्रेशन
यह पेज Postmark के send पेलोड, suppression डंप और webhooks को Bird पर मैप करता है। मुख्य माइग्रेशन गाइड को क्रम से फ़ॉलो करें, और इन मैपिंग्स का उपयोग स्टेप 1, 3 और 4 के लिए करें।
Postmark का डॉक्यूमेंटेशन बताता है कि यह "does not currently support HMAC webhook signature verification" (सितंबर 2026 में पढ़ा गया), इसलिए स्टेप 4 में सत्यापन जोड़ा जाता है जो आपके handler में आज नहीं है। कटओवर की योजना बनाने से पहले Webhook इवेंट ट्रांसलेट करें पढ़ें।
यह अपने agent को दें
इसे Claude Code, Cursor, या Codex में पेस्ट करें। Agent इस पेज को आपकी अपनी repository के विरुद्ध प्रोसेस करता है, जो भी Bird सरफ़ेस उसके पास पहले से है उसका उपयोग करके: MCP सर्वर अगर कनेक्टेड है, CLI अगर इंस्टॉल और साइन इन है।
कोड उदाहरण
I am moving an email integration from Postmark 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/postmark.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 Postmark usage in this repository before you change anything: calls to /email and /email/withTemplate and any SDK wrappers around them, every MessageStream name I send on, 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 Postmark 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. Postmark keeps suppressions per message stream, so dump GET /message-streams/{stream_id}/suppressions/dump once for every stream I send on rather than only the default outbound stream. 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. Postmark's docs say it does not currently support HMAC webhook signature verification, so my handler probably has no signature check and adding one is new code rather than a swap. If my registered Postmark webhook URL carries HTTP Basic credentials, take them out and tell me to rotate that pair rather than reusing it on the Bird endpoint: a URL-embedded credential should be treated as exposed. 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 Postmark path is a separate step that comes later: ask me again and wait for me to reply with the words retire the Postmark 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.Send कॉल को मैप करें
Postmark सेंडिंग को दो endpoints में बाँटता है: POST /email composed मैसेज के लिए और POST /email/withTemplate stored टेम्प्लेट के लिए। हमारा POST /v1/email/messages दोनों के लिए एक endpoint है, जिसमें टेम्प्लेट एक फ़ील्ड में रेफ़रेंस होता है।
| यह क्या करता है | Postmark | Bird |
|---|---|---|
| Auth | X-Postmark-Server-Token हेडर | Authorization: Bearer |
| प्रेषक | From | from |
| प्राप्तकर्ता | To / Cc / Bcc (comma-separated, अधिकतम 50) | to / cc / bcc (arrays) |
| विषय | Subject | subject |
| बॉडी | HtmlBody / TextBody | html / text (कम से कम एक) |
| Reply-to | ReplyTo (comma-separated) | reply_to (array) |
| कस्टम हेडर | Headers (Name/Value objects) | headers (string → string object) |
| फ़िल्टर करने योग्य लेबल | Tag (प्रति मैसेज एक) | tags: {name, value} pairs |
| राउंड-ट्रिप कॉन्टेक्स्ट | Metadata | metadata: arbitrary JSON |
| स्टोर्ड टेम्प्लेट | TemplateId / TemplateAlias + TemplateModel | template + template.parameters |
| ओपन ट्रैकिंग | TrackOpens | track_opens (default true) |
| क्लिक ट्रैकिंग | TrackLinks (None/HtmlAndText/HtmlOnly/TextOnly) | track_clicks (boolean, नीचे देखें) |
| अटैचमेंट | Attachments (Name, Content, ContentType) | attachments |
| ट्रैफ़िक विभाजन | MessageStream | (कोई समकक्ष नहीं, नीचे देखें) |
| श्रेणी | (कोई नहीं) | category: marketing (default) या transactional |
| शेड्यूलिंग | (कोई नहीं) | scheduled_at |
हमारी फ़ील्ड सीमाएँ और defaults (प्राप्तकर्ता संख्या, tag और metadata सीमाएँ) ईमेल भेजना में हैं।
पोर्टिंग नोट्स:
- Postmark में प्राप्तकर्ता strings हैं और यहाँ arrays। "a@x.com, b@x.com" बन जाता है ["a@x.com", "b@x.com"]। अगर आपका कोड उस string को एक list जॉइन करके बनाता है, तो list नहीं बल्कि join हटाएँ।
- Tag प्रति मैसेज एक string है। हमारे tags pairs हैं, और कई हो सकते हैं। "welcome" जैसा tag बन जाता है {"name": "category", "value": "welcome"}। एक स्थिर name चुनें ताकि आपके डैशबोर्ड वैसे ही फ़िल्टर करें जैसे आपके Postmark tag stats करते थे।
- Metadata सीधे पोर्ट होता है, और हम इसे वापस echo करते हैं। हम आपका metadata (और tags) हर webhook इवेंट पर email_id/recipient_id के साथ लौटाते हैं, ताकि आपके handlers को बिना lookup के आपका कॉन्टेक्स्ट मिल जाए।
- क्लिक ट्रैकिंग वहाँ enum है और यहाँ boolean। TrackLinks: "None" है track_clicks: false; तीनों enabled values सब track_clicks: true बन जाते हैं, क्योंकि हम HTML और text parts को अलग-अलग ट्रैक नहीं करते।
- टेम्प्लेट उसी कॉल में आ जाते हैं। कोई अलग template endpoint नहीं है: TemplateId या TemplateAlias बन जाता है template (ID या slug से) और TemplateModel बन जाता है template.parameters, POST /v1/email/messages पर। देखें टेम्प्लेट के साथ भेजना।
- Message stream का कोई समकक्ष नहीं है, और category वह नहीं है। Stream एक कंटेनर है जिसमें अपनी suppression list, अपने stats और अपने webhooks होते हैं। हमारी category एक per-message flag है जिसका एक प्रभाव है: यह तय करती है कि कौन से suppression रिकॉर्ड और unsubscribe प्राथमिकताएँ उस मैसेज को ब्लॉक कर सकती हैं। category: transactional सेट करना क्योंकि मैसेज transactional stream से आया था, अधिकतर बार सही रहता है, लेकिन यह इस बात का कथन है कि आप क्यों भेज रहे हैं, stream का पोर्ट नहीं। यहाँ कुछ भी per-stream stats या per-stream suppression scoping को पुन: निर्मित नहीं करता; रिपोर्टिंग विभाजन के लिए tags का उपयोग करें।
Suppressions एक्सपोर्ट करें
Postmark suppressions प्रति message stream रखता है, इसलिए पुल करने के लिए कोई एकल account-wide list नहीं है। जिस भी stream पर आप भेजते हैं, उसे डंप करें और परिणाम को import loop से गुज़ारें:
- GET /message-streams/{stream_id}/suppressions/dump
पहले अपनी streams एन्यूमरेट करें और जिस पर भी अभी भेज रहे हैं उसे डंप करें। डिफ़ॉल्ट outbound stream को पूरी list मानना transactional suppressions तो ले आता है लेकिन broadcast वाली छूट जाती हैं, और यह आपको तब पता चलता है जब उन लोगों को मेल जाता है जिन्होंने ऑप्ट आउट किया था। SuppressionReason values हैं HardBounce, SpamComplaint, और ManualSuppression, जो हमारे hard_bounce, complaint, और manual reasons पर मैप होती हैं। Suppressions में पूरी taxonomy है।
Webhook इवेंट ट्रांसलेट करें
Postmark प्रति इवेंट एक webhook type भेजता है और उसे पेलोड में RecordType फ़ील्ड से पहचानता है।
| परिणाम | Postmark | Bird |
|---|---|---|
| स्वीकृत/प्रोसेस्ड | (API रिस्पॉन्स) | email.accepted → email.processed |
| डिलीवर हुआ | Delivery | email.delivered |
| अस्थायी विफलता | Bounce एक transient Type के साथ | email.deferred |
| स्थायी बाउंस | Bounce Type: HardBounce के साथ | email.bounced / email.out_of_band_bounce |
| स्पैम शिकायत | SpamComplaint | email.complained |
| ब्लॉक्ड/सप्रेस्ड | (कोई नहीं) | email.rejected |
| ओपन | Open | email.opened |
| क्लिक | Click | email.clicked |
| अनसब्सक्राइब | SubscriptionChange | email.unsubscribed / email.list_unsubscribed |
दो अंतर तय करते हैं कि आपके handler में कितना बदलाव होगा।
सत्यापन स्वैप नहीं बल्कि नया कोड है। Postmark का डॉक्यूमेंटेशन बताता है कि यह "does not currently support HMAC webhook signature verification" (सितंबर 2026 में पढ़ा गया), और रजिस्टर्ड URL (https://<username>:<password>@example.com/webhook) में एम्बेड किए गए HTTP Basic credentials तथा आपके फ़ायरवॉल में इसकी IP ranges की अनुशंसा करता है। हम हर डिलीवरी को Standard Webhooks HMAC स्कीम के अनुसार साइन करते हैं, इसलिए आपके handler को एक सत्यापन स्टेप मिलता है जो पहले नहीं था। रेसिपी Webhooks and events में है। यह स्टेप सबसे पहले करें: unsigned requests स्वीकार करने वाला handler वह एक चीज़ है जो माइग्रेशन में नहीं आनी चाहिए।
क्रेडेंशियल्स को दोबारा उपयोग करने के बजाय रोटेट करें। एक username और password जो webhook URL के अंदर रहा है, उसे exposed माना जाना चाहिए, क्योंकि URLs access logs, config exports और vendor console तक पहुँचते हैं। उन्हें endpoint से हटाएँ और अगर किसी और चीज़ को अभी भी उनकी ज़रूरत है तो नई pair जारी करें; पुरानी pair को Bird endpoint पर न ले जाएँ, जो signature से authenticate करता है।
Postmark हार्ड और सॉफ़्ट बाउंस को एक Bounce रिकॉर्ड में Type फ़ील्ड के साथ रिपोर्ट करता है। हम उन्हें अलग-अलग इवेंट के रूप में रिपोर्ट करते हैं। जो handler बाउंस पेलोड के अंदर Type पर ब्रांच करता है, वह यहाँ इवेंट नाम पर ब्रांच करता है: अस्थायी विफलताएँ email.deferred के रूप में आती हैं और स्थायी email.bounced के रूप में। Postmark जो हर बाउंस type पहचानता है वह उसके Bounce API रेफ़रेंस पर है; पोर्ट के लिए महत्वपूर्ण यह है कि हर एक उस विभाजन के किस तरफ़ आता है।
हमारे delivery इवेंट प्राप्तकर्ता-स्कोप्ड हैं (recipient_id के साथ email_id), इसलिए तीन प्राप्तकर्ताओं को भेजने पर एक नहीं बल्कि तीन delivery outcomes आते हैं।
कटओवर करें
मुख्य गाइड में domains और DNS और sandbox smoke test पर काम करें। दोनों provider-independent हैं।
अगले कदम
- सेंडिंग domains: रजिस्ट्रेशन, सत्यापन lifecycle, और आप जो DNS रिकॉर्ड पब्लिश कर रहे हैं
- Webhooks and events: endpoint सेटअप और Standard Webhooks सत्यापन
- Testing sandbox: कटओवर से पहले नए इंटीग्रेशन का smoke-test करें
- Suppressions: अपनी आयातित list की पुष्टि करें और यहाँ से हम इसे कैसे बनाए रखते हैं
संबंधित संसाधन
इस विषय के लिए डॉक्यूमेंटेशन, गाइड और उदाहरणों के साथ आगे बढ़ें। संसाधन अंग्रेज़ी में हैं।
गाइड देखेंGetting started with emailक्षमता जानेंEmailलर्निंग पाथ फ़ॉलो करेंBuild your first integrationइम्प्लीमेंटेशन गाइडSend your first email
अभ्यास करें और इम्प्लीमेंटेशन ब्रीफ़ पाएँ