MailLandDocs
وب‌هوک‌ها

منطق تلاش مجدد

درک نحوه تلاش مجدد Mail.Land برای تحویل‌های ناموفق webhook

وقتی تحویل webhook شکست می‌خورد، MailLand به‌طور خودکار با تأخیرهای افزایشی مجدداً تلاش می‌کند. این صفحه برنامه زمانی تلاش مجدد، وضعیت‌های تحویل، مدیریت خطا و نحوه نظارت و تلاش مجدد دستی تحویل‌ها را پوشش می‌دهد.

برنامه زمانی تلاش مجدد

این بخش همهٔ رویدادهایی را پوشش می‌دهد که dispatcher دائمی تحویل می‌دهد: message.*، suppression.*، account.* و inbound.received. نکته‌های مخصوص رویدادهای ورودی در بخش تحویل‌های ورودی در ادامه آمده است.

MailLand یک تحویل ناموفق را در مجموع تا ۶ بار، با تأخیری فزاینده پیش از هر تلاش مجدد، دوباره امتحان می‌کند:

تلاشتأخیر پیش از این تلاشزمان کل سپری‌شده
۱: (تلاش اولیه)۰
۲بلافاصله~۰
۳۱ دقیقه~۱ دقیقه
۴۵ دقیقه~۶ دقیقه
۵۱۵ دقیقه~۲۱ دقیقه
۶۱ ساعت~۱ ساعت و ۲۱ دقیقه

اگر تلاش ششم هم شکست بخورد، تحویل به‌عنوان شکست‌خورده دائمی علامت‌گذاری می‌شود؛ نه انتظار بیشتری در کار است و نه تلاش هفتمی.

تلاش‌مجددپذیر در مقابل غیرتلاش‌مجددپذیر

پاسخ‌های تلاش‌مجددپذیر

این کدهای وضعیت تلاش مجدد خودکار را آغاز می‌کنند:

  • 408 Request Timeout
  • 429 Too Many Requests
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout
  • خطاهای شبکه (تایم‌اوت، خطاهای سوکت، خرابی DNS)

پاسخ‌های غیرتلاش‌مجددپذیر

این کدهای وضعیت به‌عنوان شکست‌های دائمی در نظر گرفته می‌شوند، بدون تلاش مجدد:

  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not 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}/deliveries
List delivery history
curl -X GET "https://api.mail.land/v1/webhooks/wh_abc123/deliveries?limit=20" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

پارامترهای کوئری

پارامترنوعپیش‌فرضتوضیحات
cursorstring-نشانگر مبهم از nextCursor صفحهٔ قبل. برای صفحهٔ اول حذف کنید.
limitint20تعداد آیتم در هر صفحه
statusstring-فیلتر: success یا failed
eventTypestring-فیلتر بر اساس نوع رویداد (مثلاً message.delivered)
fromdatetime-تاریخ شروع
todatetime-تاریخ پایان
Delivery history response
{
  "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}/retry
Retry a delivery
curl -X POST https://api.mail.land/v1/webhooks/wh_abc123/deliveries/p8r2kx7m3nq1abc/retry \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

در صورت موفقیت 202 Accepted برمی‌گردد. تلاش مجدد در صف قرار می‌گیرد و از داده‌های رویداد اصلی استفاده می‌کند.

وضعیتکدتوضیحات
202-تلاش مجدد با موفقیت در صف قرار گرفت
202-تحویل از پیش برای تلاش مجدد در صف قرار دارد؛ بدون اثر، نه یک خطا
400ALREADY_SUCCEEDEDنمی‌توان تحویل موفق را دوباره امتحان کرد
400INVALID_REQUESTتحویل مربوط به پیش از پیگیری پایدار تلاش مجدد است، یا هم‌اکنون در حال انجام است
404WEBHOOK_NOT_FOUNDwebhook وجود ندارد
404DELIVERY_NOT_FOUNDشناسه تحویل وجود ندارد

توقف خودکار در صورت شکست

وقتی یک webhook به‌اندازهٔ کافی تلاش تحویل ناموفق متوالی جمع کند، MailLand آن را به‌طور خودکار متوقف می‌کند. این آستانه، pauseThreshold خود webhook است اگر روی مقداری بزرگ‌تر از ۰ تنظیم شده باشد، در غیر این صورت مقدار پیش‌فرض یعنی ۱۰ تلاش تحویل ناموفق متوالی:

  1. isActive webhook روی false تنظیم می‌شود و pausedAt / pausedReason پر می‌شوند؛ pausedReason می‌گوید چند شکست رخ داده و آخرین شکست چه بوده است
  2. یک اعلان درون‌برنامه‌ای ایجاد می‌شود
  3. تا زمانی که webhook از سر گرفته نشود، هیچ رویداد دیگری تحویل نمی‌شود

شمارنده، شمارندهٔ تلاش‌ها است، نه رویدادها: یک رویداد که کل نردبان تلاش مجدد خودش را مصرف کند، چند شکست حساب می‌شود.

پیش از رسیدن به آستانه، هیچ اعلان هشدار زودهنگامی وجود ندارد؛ به‌جای منتظر ماندن برای اطلاع‌رسانی، فیلد consecutiveFailures را پیش‌دستانه بررسی کنید (به بهترین روش‌ها در ادامه نگاه کنید).

از سرگیری یک Webhook متوقف‌شده

POST https://api.mail.land/v1/webhooks/{id}/resume
Resume a paused webhook
curl -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 آن را رعایت می‌کند.

مراحل بعدی

در این صفحه