SMTP
Envía con Postal desde cualquier sistema que hable SMTP, usando una clave de API como contraseña.
#Configuración
Para sistemas que no se comunican con APIs (WordPress, ERPs, plataformas de tienda, impresoras), usa el servidor SMTP de Postal. Los envíos pasan por las mismas reglas de la API: dominio verificado, cuotas, lista de supresión, y aparecen en Correos y Registros. El SMTP forma parte del plan (smtp_access): sin él, el mensaje se rechaza con 550 5.7.1.
| Campo | Valor |
|---|---|
| Servidor | smtp.postal.so |
| Puerto | 465 (TLS directo, recomendado) o 587 (STARTTLS). Si la red bloquea esos, usa 2465 (TLS) o 2587 (STARTTLS). |
| Usuario | postal |
| Contraseña | Una clave de API (ps_…). Basta una clave solo de envío; crea una exclusiva para el SMTP. |
| Autenticación | AUTH PLAIN o AUTH LOGIN, siempre después del TLS. |
Los destinatarios de los correos enviados por SMTP (To y Cc) se guardan en la Audiencia como contactos sin confirmar, que no reciben marketing hasta que los confirmes: mira Audiencia automática de los correos transaccionales.
#Ejemplos
Node.js
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: 'smtp.postal.so',
port: 465,
secure: true, // TLS direto; para a porta 587 use secure: false
auth: {
user: 'postal',
pass: process.env.POSTAL_API_KEY,
},
});
const info = await transporter.sendMail({
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>',
});
console.log(info.response); // 250 2.0.0 OK queued as 019a1b2c-...
Python
import os
import smtplib
from email.message import EmailMessage
message = EmailMessage()
message["From"] = "Loja Exemplo <[email protected]>"
message["To"] = "[email protected]"
message["Subject"] = "Seu pedido #10482 saiu para entrega"
message.set_content("O pedido #10482 está a caminho.")
message.add_alternative("<p>O pedido <b>#10482</b> está a caminho.</p>", subtype="html")
with smtplib.SMTP_SSL("smtp.postal.so", 465) as server:
server.login("postal", os.environ["POSTAL_API_KEY"])
server.send_message(message)
PHP
use PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.postal.so';
$mail->Port = 465;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // 587: ENCRYPTION_STARTTLS
$mail->SMTPAuth = true;
$mail->Username = 'postal';
$mail->Password = getenv('POSTAL_API_KEY');
$mail->CharSet = 'UTF-8';
$mail->setFrom('[email protected]', 'Loja Exemplo');
$mail->addAddress('[email protected]');
$mail->Subject = 'Seu pedido #10482 saiu para entrega';
$mail->isHTML(true);
$mail->Body = '<p>O pedido <b>#10482</b> está a caminho.</p>';
$mail->send();
Laravel
# .env
MAIL_MAILER=smtp
MAIL_SCHEME=smtps
MAIL_HOST=smtp.postal.so
MAIL_PORT=465
MAIL_USERNAME=postal
MAIL_PASSWORD=ps_sua_chave
[email protected]
MAIL_FROM_NAME="Loja Exemplo"
cURL
curl --ssl-reqd --url "smtps://smtp.postal.so:465" \
--user "postal:$POSTAL_API_KEY" \
--mail-from "[email protected]" \
--mail-rcpt "[email protected]" \
--upload-file message.eml
#Laravel
Con el .env anterior, Mail::to($customer)->send(new OrderShipped($order)) pasa a salir por Postal, sin cambiar el código. En el puerto 587, usa MAIL_SCHEME=smtp y Laravel activa el STARTTLS solo.
#Códigos de un solo uso (OTP-Token)
Postal entrega el mensaje tal como llegó, así que el encabezado OTP-Token ("123456"; origin="https://app.exemplo.com.br") llega al destinatario tal como lo escribió tu sistema. El cuidado está en la biblioteca de SMTP, que no debe codificar el valor (RFC 2047) ni cambiar las comillas. En Nodemailer, por ejemplo, usa { prepared: true, value }; en PHPMailer, los valores de más de 47 caracteres piden una subclase; en Laravel, el headers() del Mailable basta. El formato, los ejemplos de cada biblioteca y cómo leer el código al recibir están en Encabezado OTP-Token.
#Cómo se tratan los mensajes
- El remitente viene del encabezado
Fromdel mensaje, que debe ser de un dominio verificado (y del dominio de la clave, si está restringida). - Los destinatarios son los del sobre (
RCPT TO). Quien no aparece enToni enCcse trata comoBcc. - El mensaje se envía tal como llegó, con adjuntos e imágenes incrustadas. Queda disponible en
GET /emails/{id}/raw. - Los encabezados personalizados (
X-…,List-Unsubscribe,OTP-Token,Reply-To…) siguen tal como los escribió tu sistema. Los únicos cambios son la eliminación delBcc(quien está solo en él recibe por el sobre y no aparece para los demás) y elOTP-Tokenque llega en palabras codificadas de la RFC 2047 (Nodemailer, PHPMailer), que Postal decodifica y despliega para entregar el valor original (consulta la guía del OTP-Token). - El SMTP no tiene
tags, programación ni plantillas: para eso usa la API. Las cuotas, la lista de supresión, los eventos y los webhooks son los mismos. - Las direcciones de prueba (
[email protected]…) también funcionan: el correo se simula, no usa la cuota y genera los eventos y webhooks reales. No mezcles direcciones de prueba con destinatarios reales en el mismo mensaje (550 5.6.0). - Al aceptar, el servidor responde
250 2.0.0 OK queued as <id>: el ID es el del correo en la API. - Cada mensaje aparece en los registros con el método
SMTP(filtra consource=smtp). - Límites: 40 MB por mensaje y 50 destinatarios. Las sesiones inactivas se cierran después de 5 minutos.
#Respuestas de error
| Código | Significado |
|---|---|
535 5.7.8 | Usuario o contraseña incorrectos. El usuario es postal y la contraseña, la clave de API. Tras 3 fallos la conexión se cierra; muchos fallos desde la misma IP bloquean nuevos intentos durante 10 minutos. |
530 5.7.0 | Faltó autenticarse, o se intentó autenticar antes del STARTTLS en el puerto 587. |
550 5.7.1 | Envío rechazado: dominio no verificado o pausado por el plan, clave restringida a otro dominio, envíos pausados (sending_paused) o un recurso que el plan no incluye (SMTP, direcciones de prueba, adjuntos). El mensaje trae el motivo. |
550 5.6.0 | Mensaje no válido (sin From válido, dirección mal formada o direcciones de prueba mezcladas con destinatarios reales, por ejemplo). |
452 4.5.3 | Cuota diaria o mensual alcanzada, o más de 50 destinatarios. Es temporal: el cliente puede intentarlo más tarde. |
552 5.3.4 | Mensaje de más de 40 MB. |
451 4.3.0 | Fallo temporal. Inténtalo de nuevo. |