MailLandDocs
ارسال ایمیل

REST API

ارسال ایمیل با استفاده از REST API سرویس Mail.Land به همراه مرجع کامل درخواست و پاسخ

ایمیل‌های تراکنشی را از طریق POST /v1/transactional/send ارسال کنید. این روش اصلی ارسال ایمیل از طریق MailLand است.

احراز هویت

کلید API خود را در هدر X-API-Key قرار دهید:

X-API-Key: ml_pet_Ab3Kx9mN2pQ7rT4wL8yD...

اعتبارنامه باید کانال Api فعال داشته باشد و از نوع اعتبارنامه محصول Sending باشد.

ارسال یک ایمیل

POST https://api.mail.land/v1/transactional/send
Send an email
curl -X POST https://api.mail.land/v1/transactional/send \
  -H "X-API-Key: ml_pet_Ab3Kx9mN2pQ7rT4wL8yD..." \
  -H "Content-Type: application/json" \
  -d '{
    "from": {"email": "[email protected]"},
    "to": [{"email": "[email protected]"}],
    "subject": "Hello from MailLand",
    "htmlContent": "<p>Your email content here</p>"
  }'

بدنه درخواست

نمونه کامل درخواست
{
  "from": {
    "email": "[email protected]",
    "name": "Your App"
  },
  "to": [
    {
      "email": "[email protected]",
      "name": "Jane Doe",
      "variables": {
        "firstName": "Jane",
        "orderNumber": "ORD-12345"
      }
    }
  ],
  "subject": "Your order #{{orderNumber}} has shipped",
  "htmlContent": "<h1>Hi {{firstName}},</h1><p>Your order #{{orderNumber}} is on its way.</p>",
  "textContent": "Hi {{firstName}}, Your order #{{orderNumber}} is on its way.",
  "replyTo": "[email protected]",
  "tags": ["order-shipped", "transactional"],
  "customHeaders": {
    "X-Entity-Ref-ID": "order-12345"
  },
  "tracking": {
    "opens": true,
    "clicks": true
  },
  "priority": "High",
  "idempotencyKey": "order-12345-shipped-v1"
}

مرجع فیلدها

فیلدنوعالزامیتوضیحات
fromobjectبلهآدرس فرستنده
from.emailstringبلهایمیل فرستنده (باید روی دامنه تایید شده باشد)
from.namestringخیرنام نمایشی
toarrayبلهلیست گیرندگان
to[].emailstringبلهآدرس ایمیل گیرنده
to[].namestringخیرنام نمایشی گیرنده
to[].variablesobjectخیرمتغیرهای قالب اختصاصی هر گیرنده
subjectstringمشروطالزامی است مگر اینکه از قالب استفاده شود
templateIdstringخیراستفاده از قالب ذخیره شده به جای محتوای درون‌خطی
htmlContentstringمشروطبدنه HTML (اگر templateId نباشد، htmlContent یا textContent الزامی است)
textContentstringخیرمتن ساده جایگزین
variablesobjectخیرمتغیرهای سراسری قالب. چه templateId تنظیم شده باشد چه نشده اعمال می‌شوند؛ در صورت هم‌پوشانی کلید، مقدار to[].variables خودِ گیرنده برنده می‌شود
replyTostringخیرآدرس ایمیل پاسخ‌دهی
tagsarrayخیربرچسب‌ها برای فیلترکردن در آنالیتیکس و وب‌هوک‌ها
customHeadersobjectخیرهدرهای سفارشی ایمیل (جفت‌های کلید-مقدار)
trackingobjectخیرتنظیمات ردیابی را بازنویسی کنید
tracking.opensbooleanخیردرخواست ردیابی باز شدن برای همین پیام (پیش‌فرض: در هر دو جریان خاموش). فقط تا وقتی به کار می‌رود که دامنهٔ فرستنده انتخابی نکرده باشد؛ انتخاب خود دامنه برای هر جریان، در صفحهٔ دامنه‌ها، مقدم است. false همیشه آن را خاموش می‌کند
tracking.clicksbooleanخیرردیابی کلیک را فعال کنید (پیش‌فرض: برای جریان تراکنشی false مگر اینکه حساب شما آن را فعال کند، برای بازاریابی true)
ipPoolIdstringخیربرای استخرهای IP اختصاصی رزرو شده و هنوز در دسترس نیست؛ ارسال آن خطای 400 IP_POOL_NOT_FOUND برمی‌گرداند. آن را حذف کنید.
scheduledAtdatetimeخیرزمان‌بندی برای تحویل آینده (UTC)، حداکثر تا ۷ روز بعد
idempotencyKeystringخیرجلوگیری از ارسال تکراری برای یک کلید یکسان. ترجیحاً از هدر X-Idempotency-Key استفاده کنید
attachmentsarrayخیرپیوست‌های فایل (حداکثر ۱۰ عدد و حداکثر ۱۰ مگابایت مجموع اندازهٔ رمزگشایی‌شده)
priorityenumخیرLow، Normal (پیش‌فرض)، High یا Critical

پیوست‌ها

هر پیوست به سه فیلد نیاز دارد:

Attachment format
{
  "attachments": [
    {
      "fileName": "invoice.pdf",
      "contentType": "application/pdf",
      "content": "JVBERi0xLjQKJ...",
      "inline": false
    },
    {
      "fileName": "logo.png",
      "contentType": "image/png",
      "content": "iVBORw0KGgoAAAA...",
      "contentId": "company-logo",
      "inline": true
    }
  ]
}
فیلدنوعالزامیتوضیحات
fileNamestringبلهنام فایل با پسوند
contentTypestringبلهنوع MIME (مثلاً application/pdf)
contentstringبلهمحتوای فایل با Base64 استاندارد رمزگذاری‌شده: دارای padding و بدون فاصله یا شکست خط
contentIdstringخیرشناسه محتوا برای پیوست‌های درون‌خطی (در HTML با cid:company-logo ارجاع دهید)
inlinebooleanخیرآیا این یک تصویر درون‌خطی است (پیش‌فرض: false)

حداکثر ۱۰ پیوست در هر ایمیل و حداکثر ۱۰ مگابایت مجموع اندازهٔ رمزگشایی‌شده (پس از Base64). نبودِ contentType، Base64 غیراستاندارد، یا عبور از تعداد یا حجم مجاز، خطای 400 VALIDATION_FAILED برمی‌گرداند. مسیر POST /v1/transactional/send-batch فیلد attachments ندارد.

پاسخ

وضعیت: 202 Accepted

Success response
{
  "success": true,
  "jobId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "messageIds": ["t_a1b2c3d4e5f6..."],
  "acceptedRecipients": ["[email protected]"],
  "rejectedRecipients": [],
  "queuedAt": "2026-02-17T10:30:00Z",
  "isSandboxed": false
}
فیلدنوعتوضیحات
successbooleanآیا درخواست پذیرفته شد
jobIdstringشناسه یکتای کار برای ردیابی
messageIdsarrayشناسه‌های پیام برای هر گیرنده (پیشوند t_ برای تراکنشی، m_ برای بازاریابی)
acceptedRecipientsarrayآدرس‌های ایمیل پذیرفته‌شده برای تحویل
rejectedRecipientsarrayگیرندگانی که رد شدند
queuedAtdatetimeزمانی که ایمیل در صف قرار گرفت
isSandboxedbooleanاگر درخواست با اعتبارنامهٔ sandbox ارسال شده باشد true است (حالت Sandbox را ببینید)
sandboxReasonstringcredential_sandbox_mode (ثبت شده، تحویل نشده) یا all_recipients_not_in_sandbox_allowlist (هیچ گیرنده‌ای در فهرست مجاز نبود)؛ در غیر این صورت وجود ندارد

گیرندگان رد شده

گیرندگان می‌توانند به چند دلیل رد شوند:

Response with rejected recipients
{
  "success": true,
  "jobId": "...",
  "acceptedRecipients": ["[email protected]"],
  "rejectedRecipients": [
    {
      "email": "[email protected]",
      "reason": "Suppressed"
    },
    {
      "email": "[email protected]",
      "reason": "domain_typo",
      "suggestion": "[email protected]"
    }
  ]
}

دلایل رایج رد:

  • Suppressed: آدرس در لیست سرکوب است (بانس یا شکایت‌های قبلی)
  • disposable_domain: ارائه‌دهنده ایمیل یکبارمصرف شناسایی شد
  • domain_typo: احتمالاً اشتباه تایپی در دامنه (شامل فیلد suggestion)

بررسی پیش از پرواز

توانایی ارسال خود را قبل از درخواست واقعی تأیید کنید:

GET https://api.mail.land/v1/transactional/send/check?recipientCount=1
Pre-flight check
curl https://api.mail.land/v1/transactional/send/check?recipientCount=1 \
  -H "X-API-Key: ml_pet_Ab3Kx9mN2pQ7rT4wL8yD..."
Pre-flight response
{
  "canSend": true,
  "rateLimitStatus": {
    "currentSecond": 2,
    "limitPerSecond": 50,
    "currentHour": 450,
    "limitPerHour": 5000,
    "currentDay": 8200,
    "limitPerDay": 50000
  },
  "monthlyUsed": 125000,
  "monthlyLimit": 500000
}

اگر canSend برابر false باشد، فیلد reason دلیل آن را توضیح می‌دهد (محدودیت نرخ، سهمیه، وضعیت حساب و غیره).

ایدمپوتنسی (Idempotency)

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

کلید را به‌صورت هدر بفرستید (توصیه‌شده):

X-Idempotency-Key: order-12345-shipped-v1

یا از فیلد idempotencyKey در بدنه استفاده کنید. هر دو پذیرفته می‌شوند و ارسال هم‌زمانِ هر دو تنها در صورت یکسان بودن مقادیر مجاز است.

قواعد

  • دامنه. X-Idempotency-Key تنها روی POST /v1/transactional/send و POST /v1/transactional/send-batch پذیرفته می‌شود و هیچ نقطهٔ پایانی دیگری آن را نمی‌خواند.
  • قالب. ۱ تا ۲۵۵ نویسه: حروف، ارقام، _ و -. کلیدها دقیقاً مقایسه می‌شوند؛ بدون حذف فاصله و بدون یکسان‌سازی بزرگی و کوچکی حروف.
  • بازه. هر کلید تا ۲۴ ساعت قابل بازپخش است. پس از آن همان کلید یک درخواست تازه به شمار می‌رود.
  • بازپخش. تلاش دوباره در این بازه، پاسخ اصلی را عیناً برمی‌گرداند، همان شناسه‌ها و همان وضعیت، و چیزی ارسال نمی‌کند.
  • یکتایی. کلیدها به ازای هر حساب یکتا هستند. استفادهٔ دوباره از یک کلید برای نقطهٔ پایانی دیگر با 409 رد می‌شود؛ برای هر عملیات کلید جداگانه به کار ببرید.

شناسه همبستگی

درخواست‌ها را در سیستم‌ها با افزودن یک شناسه همبستگی ردیابی کنید:

X-Correlation-ID: my-app-order-12345

یا

X-Request-ID: my-app-order-12345

شناسهٔ همبستگی در لاگ‌ها و جریان فعالیت ظاهر می‌شود.

هدرهای محدودیت نرخ

پاسخ‌های موفق شامل اطلاعات محدودیت نرخ به‌ازای هر IP هستند:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295

هنگامی که موتور سیاست ارسال محدودیت نرخ را اعمال می‌کند (429)، هدر Retry-After ثانیه‌های انتظار را نشان می‌دهد:

Retry-After: 30

یک درخواست تراکنشی می‌تواند تا ۵ گیرنده داشته باشد و هر گیرنده در محدودیت‌های نرخ شما شمرده می‌شود. اگر این تعداد از سهمیهٔ در ثانیهٔ شما بیشتر باشد (برای مثال ۱ در ثانیه در پلنی با ۶۰ در دقیقه)، درخواست وقتی پذیرفته می‌شود که در همان ثانیه درخواست دیگری پذیرفته نشده باشد؛ در غیر این صورت پاسخ 429 با Retry-After: 1 می‌گیرد و با تلاش دوباره در ثانیهٔ بعد، در حد محدودیت دقیقه‌ای شما، موفق می‌شود. به محدودیت‌های نرخ مراجعه کنید.

یک 429 در سطح IP همچنین شامل X-RateLimit-Reset به‌صورت زمان UTC با قالب ISO-8601 است.

پاسخ‌های خطا

تمام خطاها یک بدنهٔ JSON برمی‌گردانند:

Error response format
{
  "code": "ERROR_CODE",
  "message": "Human-readable description",
  "timestamp": "2026-02-17T10:30:00Z",
  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

کدهای خطا

وضعیتکدتوضیحات
400INVALID_REQUESTبدنهٔ درخواست نادرست، یا scheduledAt بیش از ۷ روز جلوتر («امکان زمان‌بندی ایمیل بیش از ۷ روز جلوتر وجود ندارد»)
400VALIDATION_FAILEDبدون htmlContent، textContent یا templateId؛ یا یک پیوست اعتبارسنجی را نمی‌گذراند (به محدودیت‌های پیوست‌ها در بالا مراجعه کنید). پاسخ شامل آرایهٔ errors[] با فیلد و قانون ناموفق است. (قبلاً: MISSING_CONTENT: از ۲۰۲۶-۰۴ منسوخ شده.)
413CONTENT_TOO_LARGE"The message is too large to send: it would exceed the platform's message-size limit. Reduce the HTML, text, attachments or recipients.": حجم پیام از حد مجاز پلتفرم فراتر می‌رود. POST /v1/transactional/send و send-batch آن را با 413 برمی‌گردانند؛ چیزی در صف قرار نمی‌گیرد. پیام را کوچک‌تر کنید. در درون‌ریزی CSV کد 400 است
400transactional_recipient_limit_exceededبیش از ۵ گیرنده روی یک اعتبارنامهٔ تراکنشی (۱۰۰۰ در بازاریابی)
400TEMPLATE_NOT_FOUNDtemplateId به هیچ قالب فعالی از این حساب اشاره ندارد (برای قالب حذف‌شده نیز برگردانده می‌شود)
400IP_POOL_NOT_FOUNDipPoolId به هیچ استخری که به این حساب اختصاص یافته باشد اشاره ندارد (اکنون همیشه، چون هنوز استخری قابل اختصاص نیست: به مرجع فیلدها در بالا مراجعه کنید)
422TEMPLATE_VARIABLE_MISSINGمحتوا یک {{placeholder}} بدون مقدار دارد؛ details.missingVariables نام‌ها را فهرست می‌کند. چیزی در صف قرار نمی‌گیرد
400IDEMPOTENCY_KEY_INVALIDکلید خالی، نامعتبر یا بیش از ۲۵۵ نویسه است، یا هدر بیش از یک‌بار ارسال شده است
400IDEMPOTENCY_KEY_CONFLICTهدر و فیلد idempotencyKey هر دو ارسال شده‌اند و مقادیرشان متفاوت است
400SEND_FAILEDتمام گیرندگان سرکوب شده‌اند (پیام: «All recipients are suppressed»)
409IDEMPOTENCY_KEY_REUSEDاین کلید هم‌اکنون برای نقطهٔ پایانی دیگری در این حساب استفاده می‌شود
401UNAUTHORIZEDX-API-Key وجود ندارد، نامعتبر است، منقضی شده یا لغو شده است
403ACCOUNT_SUSPENDEDحساب تعلیق شده است
403ACCOUNT_DISABLEDحساب غیرفعال شده است
403ACCOUNT_NOT_ACTIVEحساب فعال نیست
403NO_ACTIVE_SUBSCRIPTIONحساب اشتراک فعالی ندارد
403SUBSCRIPTION_EXPIREDاشتراک حساب منقضی شده است
403IP_NOT_ALLOWEDIP درخواست در فهرست مجاز اعتبارنامه نیست
403SENDING_BLOCKEDارسال برای این حساب مسدود شده است
403ACTION_REQUIREDپیش از ارسال، اقدامی روی حساب لازم است
403TENANT_APPROVAL_REQUIREDحساب پیش از ارسال در انتظار بررسی است. تلاش مجدد کمکی نمی‌کند؛ با پشتیبانی تماس بگیرید
422DOMAIN_NOT_VERIFIEDدامنهٔ فرستنده تأیید نشده است
422DOMAIN_NOT_ALLOWED_FOR_CREDENTIALدامنه در محدودهٔ اعتبارنامه نیست
422DOMAIN_NOT_FOUNDدامنهٔ فرستنده یافت نشد
429RATE_LIMIT_EXCEEDEDاز محدودیت نرخ تجاوز شده
429QUOTA_EXCEEDEDسهمیهٔ ماهانه تمام شده
429WARMUP_LIMIT_EXCEEDEDسقف روزانهٔ دورهٔ راه‌اندازی ارسال حساب شما پر شده است؛ در ۰۰:۰۰ UTC بازنشانی می‌شود
429DAILY_LIMIT_EXCEEDEDبه محدودیت روزانهٔ ارسال رسیده
429WARMUP_POOL_BUDGET_EXCEEDED"Sending is temporarily paused for today. It resumes automatically at 00:00 UTC; no action is needed." / "Sending is briefly delayed. Please retry in a few minutes."
429WARMUP_POOL_EMPTY"Sending is temporarily paused. It resumes automatically; no action is needed."
429PLATFORM_DAILY_CAPACITY_REACHED"Platform sending capacity for today is fully booked. This is a temporary platform-wide limit, not your account quota, and it resets at midnight UTC."
429PLATFORM_CAPACITY_PROTECTION"New sending is briefly paused to protect platform capacity. Mail already accepted is not affected. This is transient and clears on its own; retry shortly."
429PROBATION_CAP_REACHED"New accounts can send to N recipients per rolling 24 hours until our team has reviewed the account. Capacity returns as earlier sends age out of the 24-hour window; contact support to request a review."
429PAYMENT_DAILY_LIMIT_EXCEEDEDمحدودیت روزانه برای حساب دارای پرداخت معوق اعمال شده
429MARKETING_PAUSEDارسال بازاریابی برای این حساب موقتاً متوقف شده
429SENDING_BLOCKEDسطح تأیید حساب اجازهٔ این ارسال را نمی‌دهد (ردِّ مربوط به sandbox/سطح تأیید؛ مسدودسازی قطعی ارسال به‌جای آن 403 برمی‌گرداند، به بالا مراجعه کنید)
503SERVICE_UNAVAILABLEسرویس ایمیل موقتاً در دسترس نیست

محدودیت گیرندگان تراکنشی

اعتبارنامه‌های تراکنشی حداکثر ۵ گیرنده در هر درخواست ارسال را اجرا می‌کنند. این امر از سوءاستفاده از جریان‌های تراکنشی برای ارسال انبوه جلوگیری می‌کند. اگر به گیرندگان بیشتری نیاز دارید، از اعتبارنامه بازاریابی با ارسال دسته‌ای استفاده کنید.

استفاده از قالب‌ها

به جای HTML درون‌خطی، به یک قالب ذخیره‌شده ارجاع دهید:

Send with a template
{
  "from": { "email": "[email protected]" },
  "to": [
    {
      "email": "[email protected]",
      "variables": {
        "firstName": "Jane",
        "resetLink": "https://app.example.com/reset?token=abc123"
      }
    }
  ],
  "templateId": "t8x2m4q9zk7wpr",
  "variables": {
    "companyName": "Acme Inc"
  }
}

subject از قالب می‌آید. در صورت هم‌پوشانی کلید، مقدار to[].variables خودِ گیرنده، variables سراسری را بازنویسی می‌کند، همان قاعدهٔ محتوای درون‌خطی. برای ایجاد و مدیریت قالب‌ها به قالب‌ها مراجعه کنید.

مراحل بعدی

در این صفحه