Skip to content

Send email with PHP

Send transactional email from PHP through PostStack.

PHP ships with cURL in the core, so you can talk to PostStack without Composer if you want a minimal dependency tree. Frameworks that already have a mailer — Symfony Mailer, WordPress, Laravel — are easier to point at the SMTP relay; there is a separate Laravel guide for Mailables, queues and notifications.

Quickstart#

Before you start

You need an API key (sk_live_…, or sk_test_… to try it without delivering anything) and a sending domain you have verified in PostStack. See Authentication and Domains.

  1. Install the SDK

    Nothing to install: the examples use PHP’s cURL extension, which most PHP builds include. Check that it is loaded:

    bash
    php -m | grep -i curl   # prints "curl" when the extension is available
  2. Initialize the client

    php
    $apiKey = getenv('POSTSTACK_API_KEY');
    $baseUrl = 'https://api.poststack.dev';
  3. Send an email

    php
    <?php
    $apiKey = getenv('POSTSTACK_API_KEY');
    
    $payload = json_encode([
        'from' => 'hello@yourdomain.com',
        'to' => ['user@example.com'],
        'subject' => 'Hello from PHP!',
        'html' => '<h1>Welcome!</h1>',
    ]);
    
    $ch = curl_init('https://api.poststack.dev/emails');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $payload,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
        ],
    ]);
    
    $response = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    
    echo $status, ' ', $response;   // 202 {"id":"em_..."}
  4. Handle errors

    php
    <?php
    
    class PoststackException extends RuntimeException {
        public int $statusCode;
        public ?string $requestId;
        public function __construct(int $statusCode, string $message, ?string $requestId = null) {
            parent::__construct($message);
            $this->statusCode = $statusCode;
            $this->requestId = $requestId;
        }
    }
    
    function send_email(array $payload, int $attempts = 3): array {
        $apiKey = getenv('POSTSTACK_API_KEY');
        // One key for every attempt: a retry after a lost response replays the
        // original send instead of delivering a second copy.
        $idempotencyKey = bin2hex(random_bytes(16));
    
        for ($i = 0; $i < $attempts; $i++) {
            $ch = curl_init('https://api.poststack.dev/emails');
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_POST => true,
                CURLOPT_TIMEOUT => 10,
                CURLOPT_POSTFIELDS => json_encode($payload),
                CURLOPT_HTTPHEADER => [
                    'Authorization: Bearer ' . $apiKey,
                    'Content-Type: application/json',
                    'Idempotency-Key: ' . $idempotencyKey,
                ],
            ]);
            $response = curl_exec($ch);
            $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
            if ($response === false) {          // network error or timeout
                sleep(2 ** $i);
                continue;
            }
    
            if ($status >= 200 && $status < 300) {
                return json_decode($response, true);
            }
            if ($status === 429 || $status >= 500) {
                sleep(2 ** $i);
                continue;
            }
            throw new PoststackException($status, (string) $response);
        }
        throw new RuntimeException('send_email retries exhausted');
    }

Good to know

  • Uses built-in PHP cURL — no Composer packages required
  • Using Laravel? The Laravel guide covers the SMTP mailer, Mailables, queues and notifications

Framework integrations#

Laravel

Set MAIL_MAILER=smtp, MAIL_HOST=smtp.poststack.dev, MAIL_PORT=587, MAIL_USERNAME=poststack and MAIL_PASSWORD to your API key in .env. Every Mailable, notification and queued mail then goes through PostStack. The Laravel guide has the full setup.

Symfony Mailer

Set MAILER_DSN=smtp://poststack:${POSTSTACK_API_KEY}@smtp.poststack.dev:587 in .env — the smtp:// scheme upgrades to STARTTLS on 587; use smtps://…@smtp.poststack.dev:465 for implicit TLS. Inject MailerInterface into your services and call $mailer->send($email).

WordPress

Install WP Mail SMTP, FluentSMTP, or any SMTP plugin. Point it at smtp.poststack.dev with username poststack and your API key as the password: port 587 with encryption TLS (STARTTLS), or port 465 with SSL. All transactional WordPress emails (admin alerts, password resets, WooCommerce order emails) start delivering through PostStack.

Common pitfalls#

Disabling SSL verification

CURLOPT_SSL_VERIFYPEER => false opens you to MITM attacks. Always leave SSL verification enabled — the PostStack TLS cert is from a public CA.

Misconfiguring MAIL_FROM_ADDRESS

Your From address must be on a verified domain. Laravel’s default hello@example.com is rejected. Update MAIL_FROM_ADDRESS in .env to your verified domain.

Holding cURL handles open per-request

For low-volume PHP apps the per-request handle is fine. For high-volume CLI workers, reuse a single cURL handle with curl_init once and curl_setopt per request to amortise the TLS handshake.

FAQ#

Do I need Composer or a package?

No. PHP’s built-in cURL is enough. For Laravel, you can also configure SMTP without adding a package.

Can I use this with WordPress?

Yes — use WP Mail SMTP or FluentSMTP. Point it at smtp.poststack.dev with username poststack and the API key as the password: port 587 with TLS (STARTTLS) or port 465 with SSL. Every WordPress email (admin, WooCommerce, Contact Form 7) then flows through PostStack.

How do I send email with Laravel?

Point Laravel’s SMTP mailer at smtp.poststack.dev in .env and keep using Mailables and Mail::to(...)->send(...). The Laravel guide covers queued mail, notifications, attachments and the HTTP API.

Reference#

The docs this guide builds on:

  • SDKs — every official client, its retries and idempotency keys
  • SMTP relay — hosts, ports, TLS modes and the X-PostStack-* headers
  • Emails API — every send field, attachments, scheduling and batch sends
  • Templates — stored templates with variables
  • Webhooks — event types, payloads and signature verification
  • Suppressions — what happens to an address after a hard bounce or complaint

Ready to send from PHP?

Create a free account and an API key — no card needed.

Get started free

Next steps

Was this page helpful?