راهنما · API ایمیل Resend

تیم محصول چگونه باید API ایمیل Resend را به‌طور ایمن پیاده‌سازی کند؟

API ایمیل Resend را پشت یک worker سرور مورد اعتماد پیاده‌سازی کنید، نه در کد مرورگر یا موبایل. دامنه دقیق ارسال را تأیید کنید، در صورت امکان یک کلید API فقط برای ارسال و محدود به همان دامنه بسازید، یک job خروجی تأییدشده را ذخیره کنید و یک `Idempotency-Key` پایدار به `POST /emails` بفرستید. شناسه ایمیل بازگشتی را ذخیره کنید، امضای وب‌هوک‌ها را پیش از parse کردن تأیید کنید، رویدادها را به‌صورت idempotent پردازش کنید و گیرندگان پرخطر را در فهرست توقف ارسال قرار دهید. پذیرش توسط API، ارسال توسط ارائه‌دهنده، تحویل به سرور گیرنده و رسیدن به صندوق ورودی را وضعیت‌هایی جداگانه نگه دارید.

پیش از درخواست به ارائه‌دهنده، عملیات محصول را تعریف کنید

با یک عملیات محدود در اپلیکیشن شروع کنید، مانند تأیید حساب، رسید، هشدار امنیتی یا اعلانی که گیرنده درخواست کرده است. endpoint عمومی محصول باید پیش از اینکه هیچ payload مربوط به Resend ساخته شود، فراخواننده، tenant، کلاس پیام، هویت فرستنده، گیرندگان و قالب را مجاز کند. اجازه ندهید مرورگر با در اختیار داشتن یک اعتبارنامه قابل‌استفاده مجدد، مقادیر دلبخواهی `from`، `to`، HTML یا گزینه‌های ارائه‌دهنده را ارسال کند. یک سابقه خروجی داخلی ماندگار بسازید که شامل کلید رویداد اپلیکیشن، tenant، نسخه قالب، فرستنده تأییدشده، مجموعه گیرندگان و وضعیت فعلی باشد. یک worker می‌تواند این سابقه را به درخواست ارائه‌دهنده تبدیل کند. این مرز کلیدهای API و محتوای غیرقابل‌اعتماد پیام را از کلاینت‌ها دور نگه می‌دارد، جلوگیری از تکرار را قابل‌آزمون می‌کند و به محصول اجازه می‌دهد بدون بازنویسی همه گردش‌کارهای کسب‌وکار ارائه‌دهنده را تغییر دهد. پیام‌های تراکنشی و پیام‌های وابسته به رضایت را در مدل داخلی جدا کنید تا تنظیمات ترجیحی، فهرست توقف ارسال و تصمیم‌های مربوط به رخدادها صریح بمانند.

دقیقاً همان دامنه‌ای را که در نشانی From استفاده می‌شود تأیید کنید

دامنه‌ای را که کنترل می‌کنید در Resend اضافه کنید و رکوردهای DNS نمایش‌داده‌شده برای آن دامنه را منتشر کنید. دامنه یا زیردامنه سازمانی واقعی را که در نشانی From قابل‌مشاهده استفاده می‌شود تأیید کنید، نه اینکه فرض کنید یک هویت والد نامرتبط آن را پوشش می‌دهد. پیش از تغییر DNS، سیاست SPF و DMARC موجود را بازبینی کنید و هرگز برای یک hostname رکورد SPF دوم نسازید. وقتی ملاحظات جداسازی، مالکیت یا مهاجرت آن را توجیه می‌کند، از یک زیردامنه ارسال اختصاصی استفاده کنید. پس از اینکه داشبورد تأیید را اعلام کرد، یک پیام آزمایشی دریافت‌شده را بررسی کنید تا نشانی From قابل‌مشاهده، هویت امضای DKIM، return path، نتایج احراز هویت و رفتار پاسخ را تأیید کنید. تأیید ارائه‌دهنده ثابت می‌کند که یک هویت پیکربندی‌شده بررسی راه‌اندازی ارائه‌دهنده را گذرانده است. رضایت گیرنده، پذیرش توسط سرور گیرنده، رسیدن به صندوق ورودی یا اعتبار خوب را ثابت نمی‌کند. مالکیت DNS و تاریخچه تغییرات را بیرون از داشبورد ارائه‌دهنده نگه دارید تا چرخش و بازگشت ممکن بماند.

برای هر بار کاری یک کلید API با حداقل دسترسی بسازید

Resend کلیدهای API را با سطوح دسترسی و محدودیت اختیاری دامنه مستند کرده است. یک worker ارسال باید از کلیدی استفاده کند که فقط دسترسی ارسال دارد و در صورت امکان معماری، به همان یک دامنه‌ای محدود است که آن بار کاری مالکش است. مدیریت، دامنه، وب‌هوک و اداره حساب را تحت اختیارهای جداگانه نگه دارید. برای development، staging و production کلیدهای جداگانه بسازید تا یک محیط غیرعملیاتی نتواند با هویت محیط عملیاتی ارسال کند یا محدودیت‌های آن را مصرف کند. هر راز را مستقیماً در یک انبار مدیریت‌شده اسرار ذخیره کنید، آن را فقط در اختیار فرایند سروری که به آن نیاز دارد بگذارید و آن را به‌صورت Bearer authorization روی HTTPS ارسال کنید. کلید را در کنترل نسخه، artifactهای build، لاگ‌ها، قالب‌ها، analytics، تیکت‌ها یا promptها کپی نکنید. چرخش کلید باید تمرین شود: یک جایگزین با دامنه دسترسی معادل بسازید، worker را به‌روز کنید، ترافیک کنترل‌شده و همبستگی رویدادها را بررسی کنید و سپس کلید قدیمی را باطل کنید. برای خطاهای غیرمنتظره احراز هویت و مجوزدهی هشدار تنظیم کنید، چون می‌توانند نشانه انقضا، ابطال، تغییر ناخواسته دامنه دسترسی یا افشای راز باشند.

یک job ماندگار و یک تلاش ارسال idempotent بسازید

پیش از فراخوانی Resend، job خروجی داخلی را رزرو کنید. مقدار idempotency را از یک واقعیت پایدار محصول مانند tenant، نوع عملیات و شناسه تغییرناپذیر رویداد اپلیکیشن استخراج کنید، نه از یک تلاش مجدد تصادفی. این مقدار را در هدر `Idempotency-Key` بفرستید. Resend در حال حاضر مستند کرده است که این کلیدها از درخواست‌های ایمیل تکراری جلوگیری می‌کنند، پس از 24 ساعت منقضی می‌شوند و حداکثر 256 کاراکتر دارند. این بازه ارائه‌دهنده مفید است، اما تضمین کاملی برای جلوگیری از تکرار در سطح محصول نیست. برای گردش‌کارهای کسب‌وکاری طولانی‌تر، یک قید یکتایی روی کلید رویداد داخلی نگه دارید، workerهایی را که ممکن است همان job را بردارند serialize کنید و شناسه ایمیل ارائه‌دهنده را که درخواست موفق برمی‌گرداند ذخیره کنید. اگر timeout شبکه پذیرش را مبهم کند، job را در وضعیت نامعلوم نگه دارید و پیش از ارسال دوباره، آن را با لاگ‌ها یا رویدادهای ارائه‌دهنده تطبیق دهید. استفاده مجدد از یک کلید پایدار برای همان عملیات منطقی، ایمن‌تر از ساختن کلید تازه برای هر تلاش مجدد در لایه انتقال است.

درخواست ایمیل را آگاهانه بسازید و اعتبارسنجی کنید

endpoint ارسال ایمیل Resend نشانی From، گیرندگان، موضوع و محتوای پیام را می‌پذیرد و گزینه‌های مستندی مانند text، HTML، محتوای رندرشده با React، قالب‌ها، Cc، Bcc، reply-to، هدرها، پیوست‌ها، تگ‌ها و تحویل زمان‌بندی‌شده دارد. فقط زیرمجموعه‌ای را که محصول نیاز دارد در دسترس قرار دهید. نحو نشانی و مالکیت tenant را اعتبارسنجی کنید، تعداد گیرندگان و پیوست‌ها را پایین‌تر از محدودیت‌های ارائه‌دهنده نگه دارید، تزریق newline در هدرها را رد کنید و محتوای مرتبط با MIME را از طریق کتابخانه‌های نگهداری‌شده یا فیلدهای مورد اعتماد ارائه‌دهنده بسازید. اعتبارنامه‌ها، داده‌های شخصی حساس یا ورودی نامحدود مشتری را در تگ‌ها یا هدرها قرار ندهید. به‌جای لاگ کردن کل محتوا، نسخه قالب و متغیرهای پاک‌سازی‌شده را ذخیره کنید. یک adapter داخلی باید نتیجه‌ای محدود مانند شناسه پذیرفته‌شده ارائه‌دهنده یا خطای دسته‌بندی‌شده برگرداند، نه اینکه جزئیات پاسخ ارائه‌دهنده را به کد کسب‌وکار نشت دهد. این کار امکان می‌دهد نام فیلدهای مختص ارائه‌دهنده، نسخه‌های SDK یا محدودیت‌های درخواست را بدون تغییر قرارداد رویداد محصول به‌روز کنید.

پیش از تلاش مجدد، پاسخ‌های API و محدودیت‌های مصرف را دسته‌بندی کنید

پاسخ HTTP را فقط یک مشاهده در گردش‌کار بدانید. پاسخ موفق ارسال یک شناسه ایمیل برمی‌گرداند که باید همراه با job داخلی ذخیره شود، اما پذیرش توسط مقصد یا رسیدن به صندوق ورودی را ثابت نمی‌کند. خطاهای اعتبارسنجی، احراز هویت، دامنه، مجوز و payload را اصلاح کنید، نه اینکه کورکورانه دوباره امتحان کنید. Resend محدودیت‌های درخواست API را مستند کرده و هدرهای rate limit و سهمیه را برمی‌گرداند، از جمله فیلدهایی که ظرفیت باقی‌مانده، زمان reset و تأخیر تلاش مجدد را توصیف می‌کنند؛ پاسخ 429 باید به اندازه بازه مستند به‌علاوه jitter صبر کند. خطاهای انتقال و خطاهای سرور واجد شرایط را با exponential backoff، تعداد تلاش محدود و همان کلید idempotency منطقی تا زمانی که بازه مستند آن معتبر است دوباره امتحان کنید. خطاهای مبهم به تطبیق نیاز دارند، چون ممکن است ارائه‌دهنده ایمیل را پذیرفته باشد حتی اگر کلاینت پاسخی دریافت نکرده باشد. وقتی خطاهای تکراری بر اساس دامنه، قالب، کلید یا tenant خوشه می‌شوند هشدار دهید، اما اعتبارنامه‌ها، محتوای کامل و داده‌های غیرضروری گیرنده را از لاگ‌های عملیاتی دور نگه دارید.

پیش از پردازش رویدادها، درخواست‌های وب‌هوک را احراز هویت کنید

یک endpoint اختصاصی HTTPS برای وب‌هوک پیکربندی کنید و بدنه خام دقیق درخواست را نگه دارید. Resend امضای وب‌هوک را از طریق هدرها و رازهای امضای سازگار با Svix مستند کرده است. شناسه وب‌هوک، مهر زمانی و امضا را روی payload تغییرنیافته، پیش از parse کردن JSON یا serialize کردن دوباره، تأیید کنید و از جریان رسمی تأیید یا یک کتابخانه سازگار نگهداری‌شده استفاده کنید. درخواست‌های نامعتبر یا کهنه را رد کنید، اندازه درخواست را محدود کنید و راز امضا را جدا از کلید ارسال نگه دارید. پس از احراز هویت، رویداد را پیش از تأیید دریافت (acknowledge) به‌طور ماندگار ذخیره یا در صف قرار دهید تا crash شدن فرایند شواهد تحویل را بی‌صدا از بین نبرد. سیستم‌های تحویل ممکن است وب‌هوک‌ها را دوباره ارسال یا تکرار کنند؛ پس، از شناسه رویداد به‌عنوان کلید حذف تکرار استفاده کنید و تغییر وضعیت‌ها را یک‌طرفه نگه دارید. رویداد دیرتر یا تکراری نباید صرفاً چون آخر رسیده، یک نتیجه نهایی آگاهی‌بخش‌تر را بازنویسی کند. خطاهای تأیید و تأخیر رویدادها را به‌عنوان سیگنال‌های عملیاتی ثبت کنید، بدون اینکه محتوای خام پیام را فراتر از دوره نگهداری لازم ذخیره کنید.

رویدادهای ارائه‌دهنده را بدون اغراق درباره تحویل مدل کنید

Resend انواع نام‌گذاری‌شده رویداد ایمیل از جمله sent، delivered، delivery delayed، bounced، complained، failed، opened و clicked را منتشر می‌کند. این نام‌های ارائه‌دهنده را به یک مدل وضعیت داخلی نگاشت کنید که نوع رویداد اصلی، شناسه ایمیل ارائه‌دهنده، شناسه رویداد، زمان، دامنه گیرنده و داده‌های عیب‌یابی موجود را در بر دارد. رویداد sent پیشرفت در ارائه‌دهنده را توصیف می‌کند. رویداد delivered تحویل را طبق معنای مستند رویدادهای Resend گزارش می‌دهد، اما موفقیت SMTP در یک سیستم گیرنده همچنان پوشه نهایی گیرنده را نشان نمی‌دهد. باز شدن و کلیک مشاهدات تعامل‌اند، نه اثبات تحویل، و فناوری‌های حریم خصوصی می‌توانند بر آن‌ها اثر بگذارند. برگشت‌ها، گزارش‌های اسپم و خطاهای دائمی باید پیش از تصمیم ارسال بعدی، وضعیت ایمنی گیرنده را به‌روز کنند. تاریخچه رویدادهای ارائه‌دهنده را فقط-افزودنی (append-only) نگه دارید و وضعیت نمایشی برای کاربر را با قوانین صریح استخراج کنید. این کار شواهد را برای پشتیبانی حفظ می‌کند و از تلاش‌های مجدد ناایمن پس از انتقال مسئولیت یا دریافت سیگنال منفی از گیرنده جلوگیری می‌کند.

مسیرهای خطا و بازیابی را با گیرندگان کنترل‌شده آزمایش کنید

از یک کلید غیرعملیاتی، یک زیردامنه تأییدشده کنترل‌شده و صندوق‌های ایمیلی که متعلق به تیم است استفاده کنید. محتوای متنی و HTML، رفتار reply-to، محدودیت پیوست‌ها، کلیدهای idempotency پایدار و شناسه‌های ذخیره‌شده ارائه‌دهنده را آزمایش کنید. همان job منطقی را دو بار ارسال کنید و مطمئن شوید کنترل‌های اپلیکیشن و ارائه‌دهنده تکرار ناخواسته ایجاد نمی‌کنند. payload نامعتبر، دامنه اشتباه، کلید باطل‌شده، مجوز ناکافی، rate limit، timeout انتقال، برگشت، گزارش اسپم، تأخیر تحویل، وب‌هوک تکراری، بدنه امضای تغییریافته، مهر زمانی کهنه وب‌هوک و چرخش راز امضا را امتحان کنید. تأیید کنید که دریافت رویداد پیش از acknowledge ماندگار است و ایمنی گیرنده جلوی job بعدی را می‌گیرد. چرخش DNS و حذف ارائه‌دهنده را بدون پاک کردن رکوردهای نامرتبط آزمایش کنید. داشبوردها باید خطاهای ارسال، تأخیر، خطاهای تأیید وب‌هوک، تأخیر رویدادها، برگشت‌ها، گزارش‌های اسپم و صف‌های تطبیق را پوشش دهند. هنگام راه‌اندازی، مستندات فعلی Resend و تنظیمات حساب را بازبینی کنید، چون سهمیه‌ها، محدودیت‌ها، فیلدهای رویداد و مجوزهای موجود می‌توانند مستقل از کد مستقرشده اپلیکیشن تغییر کنند.

پیش از مهاجرت، قابلیت‌های API منتشرشده را مقایسه کنید

SendHQ یک قرارداد OpenAPI 3.1 برای API ایمیل در سطح فضای کاری خود منتشر می‌کند که شامل ارسال با دامنه تأییدشده، ایمیل ورودی، قالب‌های میزبانی‌شده، رویدادهای تحویل و موارد توقف ارسال است. پیش از مهاجرت یک یکپارچه‌سازی، بدنه‌های درخواست، احراز هویت، idempotency، شناسه‌های بازگردانده‌شده، شکل‌های خطا، وب‌هوک‌ها، قواعد دامنه و رفتار توقف ارسال را مقایسه کنید، سپس آن‌ها را با آزمون‌های سطح فیلد اعتبارسنجی کنید. سازگاری را از نام‌های endpoint مشابه فرض نکنید.

پرسش‌های متداول

کدام endpoint از طریق Resend ایمیل ارسال می‌کند؟

Resend مسیر `POST https://api.resend.com/emails` را با Bearer authorization مستند کرده است. آن را فقط از کد سرور مورد اعتماد و پس از مجاز کردن عملیات محصول، دامنه فرستنده، گیرندگان و محتوا فراخوانی کنید.

دامنه دسترسی کلید API در Resend چگونه باید تعیین شود؟

از کلیدی با دسترسی ارسال استفاده کنید و وقتی کنترل‌های مستند با معماری جور است، آن را به دامنه بار کاری محدود کنید. برای محیط عملیاتی، محیط غیرعملیاتی و مدیریت، اعتبارنامه‌های جداگانه‌ای را که در مدیر اسرار نگهداری می‌شوند به کار ببرید.

آیا پاسخ موفق API در Resend تحویل را ثابت می‌کند؟

خیر. این پاسخ پذیرش توسط ارائه‌دهنده را ثبت می‌کند و یک شناسه ایمیل برمی‌گرداند. رویدادهای احرازهویت‌شده بعدی می‌توانند پیشرفت در ارائه‌دهنده و تحویل به سیستم گیرنده را گزارش کنند، در حالی که رسیدن به صندوق ورودی دسته‌بندی جداگانه‌ای در سمت گیرنده است.

idempotency در Resend چگونه از ایمیل‌های تکراری جلوگیری می‌کند؟

برای همان درخواست منطقی یک `Idempotency-Key` پایدار بفرستید. Resend در حال حاضر کلیدها را 24 ساعت با حداکثر 256 کاراکتر نگه می‌دارد؛ پس یک قید یکتایی داخلی با عمر طولانی‌تر هم داشته باشید.

امضای وب‌هوک‌های Resend را چگونه باید تأیید کرد؟

بدنه خام دقیق درخواست را نگه دارید و پیش از parse کردن، هدرهای مستند و سازگار با Svix یعنی شناسه وب‌هوک، مهر زمانی و امضا را تأیید کنید. ورودی نامعتبر یا کهنه را رد کنید و سپس رویدادهای احرازهویت‌شده را پیش از acknowledge به‌طور ماندگار در صف قرار دهید.

آیا SendHQ می‌تواند جای Resend را بگیرد؟

پیش از سازگار دانستن SendHQ و Resend، قراردادهای API منتشرشده را مقایسه و آزمون‌های یکپارچه‌سازی سطح فیلد اجرا کنید.

منابع