منطق تلاش مجدد
درک نحوه تلاش مجدد Mail.Land برای تحویلهای ناموفق webhook
وقتی تحویل webhook شکست میخورد، MailLand بهطور خودکار با تأخیرهای افزایشی مجدداً تلاش میکند. این صفحه برنامه زمانی تلاش مجدد، وضعیتهای تحویل، مدیریت خطا و نحوه نظارت و تلاش مجدد دستی تحویلها را پوشش میدهد.
برنامه زمانی تلاش مجدد
این بخش همهٔ رویدادهایی را پوشش میدهد که dispatcher دائمی تحویل میدهد: message.*، suppression.*،
account.* و inbound.received. نکتههای مخصوص رویدادهای ورودی در بخش تحویلهای ورودی
در ادامه آمده است.
MailLand یک تحویل ناموفق را در مجموع تا ۶ بار، با تأخیری فزاینده پیش از هر تلاش مجدد، دوباره امتحان میکند:
| تلاش | تأخیر پیش از این تلاش | زمان کل سپریشده |
|---|---|---|
| ۱ | : (تلاش اولیه) | ۰ |
| ۲ | بلافاصله | ~۰ |
| ۳ | ۱ دقیقه | ~۱ دقیقه |
| ۴ | ۵ دقیقه | ~۶ دقیقه |
| ۵ | ۱۵ دقیقه | ~۲۱ دقیقه |
| ۶ | ۱ ساعت | ~۱ ساعت و ۲۱ دقیقه |
اگر تلاش ششم هم شکست بخورد، تحویل بهعنوان شکستخورده دائمی علامتگذاری میشود؛ نه انتظار بیشتری در کار است و نه تلاش هفتمی.
تلاشمجددپذیر در مقابل غیرتلاشمجددپذیر
پاسخهای تلاشمجددپذیر
این کدهای وضعیت تلاش مجدد خودکار را آغاز میکنند:
408Request Timeout429Too Many Requests500Internal Server Error502Bad Gateway503Service Unavailable504Gateway Timeout- خطاهای شبکه (تایماوت، خطاهای سوکت، خرابی DNS)
پاسخهای غیرتلاشمجددپذیر
این کدهای وضعیت بهعنوان شکستهای دائمی در نظر گرفته میشوند، بدون تلاش مجدد:
400Bad Request401Unauthorized403Forbidden404Not Found- تمام خطاهای
4xxدیگر (به جز ۴۰۸ و ۴۲۹) - پاسخ ریدایرکتی که اعتبارسنجی را پشت سر نگذارد (به بخش ریدایرکتها نگاه کنید) یا از سقف تعداد پرش عبور کند
اگر endpoint شما در یک پاسخ تلاشمجددپذیر هدر Retry-After برگرداند، MailLand بهجای برنامه بالا
همان مقدار را بهعنوان تأخیر پیش از تلاش بعدی به کار میبرد؛ این کار برای هر وضعیت
تلاشمجددپذیری انجام میشود، نه فقط 429. هیچ سقف بالایی و هیچ نوسان تصادفی (jitter) روی آن اعمال
نمیشود: اگر خودتان این هدر را ارسال میکنید، در سمت خودتان هم همین رفتار را رعایت کنید، چون یک
مقدار خیلی بزرگ دقیقاً همانطور که فرستاده شده اعمال میشود.
ریدایرکتها
MailLand با endpoint شما مثل یک مرورگر رفتار نمیکند. ریدایرکتها بهصورت دستی دنبال میشوند، حداکثر ۳ پرش، و پیش از ارسال هر چیزی به هر پرش، دوباره اعتبارسنجی میشود:
- مقصد باید
https://باشد؛ ریدایرکت بهhttp://رد میشود، نه تنزلیافته؛ - مقصد باید به یک آدرس عمومی resolve شود؛ ریدایرکت به آدرس خصوصی، loopback یا link-local رد میشود و درخواست هرگز ارسال نمیشود؛
- عبور از ۳ پرش باعث شکست تحویل میشود.
یک ریدایرکت ردشده بهعنوان شکست تحویل بدون کد وضعیت گزارش میشود. اگر endpoint شما جابهجا شده، webhook را به آدرس جدید اشاره دهید، نه اینکه به یک ریدایرکت متکی باشید.
پیکربندی تحویل
| تنظیم | پیشفرض | توضیحات |
|---|---|---|
| تایماوت HTTP | ۱۵ ثانیه | حداکثر زمان انتظار برای هر تلاش تحویل |
| حداکثر تلاش مجدد | ۶ تلاش | تعداد کل تلاشهای تحویل شامل اولین تلاش |
| آستانه توقف خودکار | ۱۰ شکست متوالی | webhook پس از این تعداد شکست متوالی متوقف میشود؛ اگر pauseThreshold خود webhook روی مقداری بزرگتر از ۰ تنظیم شده باشد از همان استفاده میشود، در غیر این صورت از همین مقدار پیشفرض |
| حذف تکراری | تا زمانی که رکورد تحویل وجود دارد | تکرارهای همان رویداد با محدودیت (WebhookId, EventId) سرکوب میشوند، تا زمانی که سطر وجود داشته باشد؛ برای تحویلهای موفق دستکم ۳۰ روز |
تحویلهای ورودی
inbound.received با همان dispatcher دائمی تحویل داده میشود که رویدادهای دیگر را تحویل میدهد؛ با همان
برنامهٔ تلاش مجدد، همان رعایت Retry-After، همان تاریخچهٔ تحویل و همان توقف خودکاری که در بالا توضیح داده شد.
- مثل هر رویداد دیگر، تکراریها را بر اساس
event_id(برابر باX-MLND-Event-Id) حذف کنید. این شناسه برای هر پیام ورودی و هر وبهوک ثابت است؛ پس هر تلاش برای همان ایمیل همان شناسه را دارد. - بازپخش دستی یک رویداد جدید است:
event_idتازه دارد و شناسهٔ اصلی درdata.replay_ofمیآید.data.idempotency_keyتغییر نمیکند. download_urlهر پیوست در هر تلاش امضا میشود و از همان لحظه ۱۵ دقیقه معتبر است؛idپیوست در همهٔ تلاشها یکسان است. بخش وبهوکهای ورودی را ببینید.
مشاهده تاریخچه تحویل
تحویلهای گذشته برای یک webhook را مشاهده کنید:
GET https://api.mail.land/v1/webhooks/{id}/deliveriescurl -X GET "https://api.mail.land/v1/webhooks/wh_abc123/deliveries?limit=20" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."پارامترهای کوئری
| پارامتر | نوع | پیشفرض | توضیحات |
|---|---|---|---|
cursor | string | - | نشانگر مبهم از nextCursor صفحهٔ قبل. برای صفحهٔ اول حذف کنید. |
limit | int | 20 | تعداد آیتم در هر صفحه |
status | string | - | فیلتر: success یا failed |
eventType | string | - | فیلتر بر اساس نوع رویداد (مثلاً message.delivered) |
from | datetime | - | تاریخ شروع |
to | datetime | - | تاریخ پایان |
{
"items": [
{
"publicId": "p8r2kx7m9wq4rtz",
"eventType": "message.delivered",
"messageId": "t_a1b2c3d4e5f6",
"statusCode": 200,
"responseTimeMs": 145,
"success": true,
"errorMessage": null,
"createdAt": "2026-02-17T12:34:58.000Z",
"attemptNumber": 1
},
{
"publicId": "p8r2kx7m3nq1abc",
"eventType": "message.bounced",
"messageId": "t_d4e5f6a1b2c3",
"statusCode": 503,
"responseTimeMs": 15000,
"success": false,
"errorMessage": "Service Unavailable",
"createdAt": "2026-02-17T12:30:00.000Z",
"attemptNumber": 3
}
],
"nextCursor": "eyJ2IjoxLCJzIjoiY3JlYXRlZGF0OmRlc2MiLCJrIjoi...",
"hasMore": true
}تلاش مجدد برای تحویل ناموفق
بهصورت دستی یک تحویل ناموفق خاص را دوباره امتحان کنید:
POST https://api.mail.land/v1/webhooks/{id}/deliveries/{publicId}/retrycurl -X POST https://api.mail.land/v1/webhooks/wh_abc123/deliveries/p8r2kx7m3nq1abc/retry \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."در صورت موفقیت 202 Accepted برمیگردد. تلاش مجدد در صف قرار میگیرد و از دادههای رویداد اصلی استفاده میکند.
| وضعیت | کد | توضیحات |
|---|---|---|
202 | - | تلاش مجدد با موفقیت در صف قرار گرفت |
202 | - | تحویل از پیش برای تلاش مجدد در صف قرار دارد؛ بدون اثر، نه یک خطا |
400 | ALREADY_SUCCEEDED | نمیتوان تحویل موفق را دوباره امتحان کرد |
400 | INVALID_REQUEST | تحویل مربوط به پیش از پیگیری پایدار تلاش مجدد است، یا هماکنون در حال انجام است |
404 | WEBHOOK_NOT_FOUND | webhook وجود ندارد |
404 | DELIVERY_NOT_FOUND | شناسه تحویل وجود ندارد |
توقف خودکار در صورت شکست
وقتی یک webhook بهاندازهٔ کافی تلاش تحویل ناموفق متوالی جمع کند، MailLand آن را بهطور خودکار
متوقف میکند. این آستانه، pauseThreshold خود webhook است اگر روی مقداری بزرگتر از ۰ تنظیم شده
باشد، در غیر این صورت مقدار پیشفرض یعنی ۱۰ تلاش تحویل ناموفق متوالی:
isActivewebhook رویfalseتنظیم میشود وpausedAt/pausedReasonپر میشوند؛pausedReasonمیگوید چند شکست رخ داده و آخرین شکست چه بوده است- یک اعلان درونبرنامهای ایجاد میشود
- تا زمانی که webhook از سر گرفته نشود، هیچ رویداد دیگری تحویل نمیشود
شمارنده، شمارندهٔ تلاشها است، نه رویدادها: یک رویداد که کل نردبان تلاش مجدد خودش را مصرف کند، چند شکست حساب میشود.
پیش از رسیدن به آستانه، هیچ اعلان هشدار زودهنگامی وجود ندارد؛ بهجای منتظر ماندن برای اطلاعرسانی،
فیلد consecutiveFailures را پیشدستانه بررسی کنید (به بهترین روشها در ادامه نگاه کنید).
از سرگیری یک Webhook متوقفشده
POST https://api.mail.land/v1/webhooks/{id}/resumecurl -X POST https://api.mail.land/v1/webhooks/wh_abc123/resume \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."این عملیات webhook را دوباره فعال میکند؛ وضعیت توقف را پاک میکند، شمارنده شکستهای متوالی را به صفر بازنشانی میکند و آن را دوباره فعال میسازد. تحویل رویداد بعدی بهطور معمول انجام میشود.
هر تحویل موفق بهطور خودکار شمارنده شکستهای متوالی را به صفر بازنشانی میکند. یک موفقیت پس از ۹ شکست از متوقف شدن webhook جلوگیری میکند.
بهترین روشها
- سریع ۲۰۰ برگردانید: دادههای webhook را بهصورت ناهمزمان پردازش کنید. رویداد را در صف قرار دهید و بلافاصله
200برگردانید. کنترلکنندههای طولانی خطر تایماوت دارند. - از شناسه رویداد برای پردازش idempotent استفاده کنید: هدر
X-MLND-Event-Id(و فیلد متناظرevent_idدر payload) در طول تلاشهای مجدد و بازارسالها ثابت میماند: همان رویداد پایه، هر چند بار هم دوباره تحویل داده شود، همیشه با همان شناسه میرسد. شناسههای پردازششده را ذخیره کنید و از موارد قبلاً پردازششده صرفنظر کنید تا تحویل تکراری در سمت شما بیاثر باشد. - شکستهای متوالی را رصد کنید: فیلد
consecutiveFailuresرا هنگام فهرست کردن webhookها بررسی کنید. قبل از رسیدن به آستانه توقف خودکار بررسی کنید. - ۴۲۹ را بهدرستی مدیریت کنید: اگر endpoint شما بیش از حد بارگذاری شده،
429با هدرRetry-Afterبرگردانید. MailLand آن را رعایت میکند.
مراحل بعدی
- تأیید امضا: اصالت webhook را تأیید کنید
- رویدادها: مرجع کامل انواع رویداد
- مرور کلی Webhookها: webhookها را ایجاد و مدیریت کنید