Iniciar sesión Crear cuenta
Para empezar

Primeros pasos

De cero al primer correo entregado: verifica un dominio, crea una clave y haz un POST /emails.

#1. Verifica un dominio

Postal solo envía desde dominios que has demostrado controlar. En el panel, en Dominios, añade el dominio (por ejemplo, lojaexemplo.com.br) y crea en tu proveedor de DNS los registros que se muestran: un TXT de DKIM y un MX y un TXT para el Return-Path. La verificación suele tardar pocos minutos. Detalles en Dominios y DNS.

#2. Crea una clave de API

En Claves de API, crea una clave solo de envío y copia el token (aparece una sola vez). Guárdalo en una variable de entorno:

Terminal
export POSTAL_API_KEY="ps_sua_chave"

#3. Envía el primer correo electrónico

Cambia el remitente por una dirección de tu dominio verificado y el destinatario por tu correo:

POST /emails

cURL

curl -X POST https://api.postal.so/emails \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Loja Exemplo <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Seu pedido #10482 saiu para entrega",
    "html": "<p>O pedido <b>#10482</b> está a caminho.</p>"
  }'

Node.js

const response = await fetch('https://api.postal.so/emails', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    from: 'Loja Exemplo <[email protected]>',
    to: ['[email protected]'],
    subject: 'Seu pedido #10482 saiu para entrega',
    html: '<p>O pedido <b>#10482</b> está a caminho.</p>',
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/emails",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "from": "Loja Exemplo <[email protected]>",
        "to": ["[email protected]"],
        "subject": "Seu pedido #10482 saiu para entrega",
        "html": "<p>O pedido <b>#10482</b> está a caminho.</p>",
    },
    timeout=10,
)

data = response.json()

PHP

<?php

$ch = curl_init('https://api.postal.so/emails');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('POSTAL_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'from' => 'Loja Exemplo <[email protected]>',
        'to' => ['[email protected]'],
        'subject' => 'Seu pedido #10482 saiu para entrega',
        'html' => '<p>O pedido <b>#10482</b> está a caminho.</p>',
    ]),
]);

$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

echo $status === 200 ? $data['id'] : $data['message'];

Laravel

// config/services.php
'postal' => [
    'key' => env('POSTAL_API_KEY'),
],

// Em qualquer lugar da aplicação
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.postal.key'))
    ->withHeaders(['Idempotency-Key' => 'order-10482-shipped'])
    ->post('https://api.postal.so/emails', [
        'from' => 'Loja Exemplo <[email protected]>',
        'to' => ['[email protected]'],
        'subject' => 'Seu pedido #10482 saiu para entrega',
        'html' => view('emails.order-shipped', ['order' => $order])->render(),
    ])
    ->throw();

$emailId = $response->json('id');

La respuesta trae el ID del correo. Si algo está mal, recibes un error con el motivo, como 422 validation_error o 403 para un dominio no verificado.

200Respuesta
{
  "id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b"
}

Laravel con el Mail del framework

¿Prefieres seguir usando Mail::to() y Mailables? Configura el mailer SMTP con tu clave y no cambia nada más en el código.

#4. Sigue la entrega

Consulta el correo para ver el estado y los eventos (sent, delivered, opened…):

GET /emails/{id}

cURL

curl https://api.postal.so/emails/019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/emails/019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/emails/019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('emails/019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);

En producción, en lugar de consultar, registra un webhook y recibe cada evento en cuanto ocurre. Para consultar el estado por la API, la clave necesita acceso total.

#Próximos pasos