رفتن به محتوای اصلی
سندک

آموزش

ارسال ایمیل در PHP

ارسال با cURL (API) یا PHPMailer (SMTP) در پروژه‌ی PHP بدون فریم‌ورک.

آخرین ویرایش: ۲۱ آبان ۱۴۰۵

اگر فریم‌ورک ندارید یا با Laravel کار نمی‌کنید، این دو راه را دارید. پیش از شروع، دامنه‌تان را تأیید و یک کلید بسازید. کلید را در متغیر محیطی بگذارید (getenv('SENDAK_KEY')) و در مخزن کد نگذارید.

با API (cURL)

sendak.php
<?php
function sendak_send(string $idempotencyKey, array $to, string $subject, string $text, array $tags = []): array
{
    $payload = json_encode([
        'from' => 'hello@shop.ir',
        'to' => $to,
        'subject' => $subject,
        'text' => $text,
        'tags' => $tags,
    ], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);

    for ($attempt = 0; $attempt < 4; $attempt++) {
        $ch = curl_init('https://api.sendak.ir/v1/emails');
        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer '.getenv('SENDAK_KEY'),
                'Content-Type: application/json',
                'Idempotency-Key: '.$idempotencyKey,
            ],
        ]);

        $body = curl_exec($ch);
        $status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        curl_close($ch);

        if ($body !== false && $status >= 200 && $status < 300) {
            return json_decode($body, true, 512, JSON_THROW_ON_ERROR)['data'];
        }

        // Only a network failure, 429 and 5xx are worth another try; the key makes it safe.
        if ($body !== false && $status !== 429 && $status < 500) {
            throw new RuntimeException("Sendak refused the message: {$body}");
        }

        sleep(2 ** $attempt);
    }

    throw new RuntimeException('Sendak did not accept the message after 4 tries');
}

$result = sendak_send('receipt-1201', ['ali@gmail.com'], 'رسید سفارش ۱۲۰۱', 'سفارش شما ثبت شد.');
echo $result[0]['id'], ' ', $result[0]['status']; // ... queued

$idempotencyKey را برای هر ایمیل منطقی ثابت بگیرید؛ نه برای هر تلاش. توضیح بیشتر. کدهای خطا: خطاها و سقف‌ها.

با SMTP (PHPMailer)

shell
composer require phpmailer/phpmailer
smtp.php
<?php
require __DIR__.'/vendor/autoload.php';

use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer(true);

try {
    $mail->isSMTP();
    $mail->Host = 'smtp.sendak.ir';
    $mail->Port = 587;
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->SMTPAuth = true;
    $mail->Username = getenv('SENDAK_USER');
    $mail->Password = getenv('SENDAK_KEY');
    $mail->Timeout = 20;
    $mail->CharSet = 'UTF-8';

    $mail->setFrom('hello@shop.ir', 'فروشگاه');
    $mail->addAddress('ali@gmail.com');
    $mail->Subject = 'اولین ایمیل';
    $mail->Body = 'سلام از سندک';

    $mail->send();
} catch (Exception $e) {
    error_log('Sendak SMTP: '.$mail->ErrorInfo);
}
  • ENCRYPTION_STARTTLS روی پورت ۵۸۷. ENCRYPTION_SMTPS (پورت ۴۶۵) پشتیبانی نمی‌شود.
  • CharSet = 'UTF-8' را فراموش نکنید، وگرنه فارسی خراب می‌شود.

نکته: SMTP کلید یکتایی درخواست ندارد. برای ایمیل‌هایی که ارسال تکراری‌شان ضرر دارد (کد تأیید، بازیابی رمز)، API را بردارید.

بررسی وب‌هوک

webhook.php
<?php
$raw = file_get_contents('php://input'); // the raw body
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_SENDAK_SIGNATURE'] ?? ''), $parts);
$t = (int) ($parts['t'] ?? 0);
$expected = hash_hmac('sha256', $t.'.'.$raw, getenv('SENDAK_WEBHOOK_SECRET'));

if ($t === 0 || abs(time() - $t) > 300 || ! hash_equals($expected, (string) ($parts['v1'] ?? ''))) {
    http_response_code(401);
    exit;
}

$event = json_decode($raw, true);
// Put the event on your own queue and answer fast.
http_response_code(200);

جزئیات رویدادها: وب‌هوک.

کلید ندارید؟

با پلن رایگان، ۱٬۰۰۰ ایمیل در ماه می‌فرستید.