Guia do desenvolvedorIntegrações
Enviar e-mail no Django
Enviar e-mail pelo Couryo no Django com send_mail e EmailMultiAlternatives, pelo backend do SDK Python ou por SMTP, e receber webhooks assinados.
O send_mail, o EmailMessage e os e-mails do próprio Django (recuperação de senha do django.contrib.auth, avisos de erro) passam a sair pelo Couryo trocando só o backend.
Opção 1: backend do SDK#
pip install "couryo[django]"No Django 6.1 ou mais novo, o backend vai em MAILERS:
import os
MAILERS = {
"default": {
"BACKEND": "couryo.django.EmailBackend",
"OPTIONS": {"api_key": os.environ["COURYO_API_KEY"]}, # ck_test_... enquanto testa
},
}
DEFAULT_FROM_EMAIL = "Exemplo <oi@exemplo.com.br>"
SERVER_EMAIL = "alertas@exemplo.com.br"No Django 6.0 ou mais antigo, use EMAIL_BACKEND (o Django 6.1 ainda aceita, com aviso de descontinuação, mas não junto com MAILERS):
import os
EMAIL_BACKEND = "couryo.django.EmailBackend"
COURYO_API_KEY = os.environ["COURYO_API_KEY"] # ck_test_... enquanto testa
DEFAULT_FROM_EMAIL = "Exemplo <oi@exemplo.com.br>"
SERVER_EMAIL = "alertas@exemplo.com.br"O código que já existe não muda:
from django.core.mail import EmailMultiAlternatives, send_mail
from django.template.loader import render_to_string
send_mail("Pedido recebido", "Obrigado pela compra!", None, ["ana@exemplo.com.br"])
contexto = {"pedido": pedido}
msg = EmailMultiAlternatives(
subject=f"Pedido {pedido.numero} enviado",
body=render_to_string("emails/pedido_enviado.txt", contexto),
to=[pedido.cliente.email],
headers={"X-Couryo-Tags": "tipo=pedido"},
)
msg.attach_alternative(render_to_string("emails/pedido_enviado.html", contexto), "text/html")
msg.send()Anexos (msg.attach(...)) e reply_to, cc e bcc seguem para a API. O cabeçalho X-Couryo-Stream: marketing manda no fluxo de marketing; sem ele, o e-mail é transacional.
Chamar a API direto#
from couryo import Couryo
couryo = Couryo() # lê COURYO_API_KEY
couryo.events.track(
{"contact": {"email": usuario.email, "attributes": {"nome": usuario.first_name}}, "name": "user.signed_up"},
idempotency_key=f"signup-{usuario.pk}",
)Em views assíncronas, use AsyncCouryo com await.
Opção 2: SMTP#
No Django 6.1 ou mais novo:
MAILERS = {
"default": {
"BACKEND": "django.core.mail.backends.smtp.EmailBackend",
"OPTIONS": {
"host": "smtp.couryo.com",
"port": 587,
"use_tls": True, # STARTTLS; para a porta 465, use "use_ssl": True no lugar
"username": "couryo",
"password": os.environ["COURYO_API_KEY"],
},
},
}
DEFAULT_FROM_EMAIL = "Exemplo <oi@exemplo.com.br>"No Django 6.0 ou mais antigo:
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.couryo.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True # STARTTLS; para a porta 465, use EMAIL_USE_SSL = True
EMAIL_HOST_USER = "couryo"
EMAIL_HOST_PASSWORD = os.environ["COURYO_API_KEY"]
DEFAULT_FROM_EMAIL = "Exemplo <oi@exemplo.com.br>"use_tls e use_ssl (EMAIL_USE_TLS e EMAIL_USE_SSL) não podem ser True ao mesmo tempo. Detalhes e códigos de resposta em SMTP.
Receber webhooks#
import os
from couryo import WebhookVerificationError, verify_webhook
from django.http import HttpResponse, HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
@csrf_exempt
@require_POST
def couryo_webhook(request):
try:
evento = verify_webhook(os.environ["COURYO_WEBHOOK_SECRET"], request.headers, request.body)
except WebhookVerificationError:
return HttpResponseBadRequest("assinatura inválida")
if evento["type"] == "bounced":
... # evento["data"]["recipient"], evento["data"]["explanation"]
return HttpResponse(status=204)request.body é o corpo cru, exatamente como a assinatura espera. A view fica fora do CSRF porque a assinatura já protege.
Recuperação de senha do Django#
A PasswordResetView usa o mailer padrão (MAILERS["default"], ou o EMAIL_BACKEND no Django 6.0 e anteriores), então já sai pelo Couryo. Confira só o DEFAULT_FROM_EMAIL (num domínio verificado) e o domínio do link: em produção, o Django monta o link com o host da requisição, então mantenha o ALLOWED_HOSTS certo. Se o e-mail de senha não chega, o guia Recuperação de senha não chega passa pelas causas uma a uma.
Problemas comuns#
| Sintoma | O que fazer |
|---|---|
InvalidRequestError com code domain_not_verified |
o DEFAULT_FROM_EMAIL precisa estar num domínio verificado no projeto |
| Nada acontece e nenhum erro | fail_silently=True esconde erros; tire para ver a mensagem do Couryo |
SMTPAuthenticationError (535) |
usuário diferente de couryo ou chave inválida, revogada ou sem escopo send |