Uma integração de API de e-mail confiável tem a ver, sobretudo, com o que acontece quando algo dá errado. O caminho feliz é uma única requisição HTTP. Os casos difíceis são um timeout em que você não sabe se a mensagem foi aceita, um worker que cai no meio de um lote e um loop de retentativas que transforma uma breve indisponibilidade em uma enxurrada. Este guia nos dá um conjunto de padrões que garantem que cada e-mail seja enviado exatamente uma vez, ou, no pior caso, de forma previsível uma vez, qualquer que seja o endpoint do provedor que você chame.
Descrevemos os padrões de forma genérica para que funcionem com qualquer API HTTP de e-mail, incluindo o MigoSMTP. Quando um recurso específico importar, como um cabeçalho de idempotência, um endpoint de lote ou um limite de taxa, consulte a sua conta do MigoSMTP ou a documentação da API para obter os detalhes exatos, em vez de presumir. Se você ainda está escolhendo entre protocolos, leia primeiro SMTP ou API: como escolher.
Por que os envios de e-mail falham de maneiras que outras chamadas de API não falham
A maioria das chamadas de API pode ser repetida sem prejuízo. E-mail não. Uma segunda chamada para criar um usuário normalmente falha com um conflito, mas uma segunda chamada para enviar um recibo envia, alegremente, um segundo recibo. O cliente vê duas mensagens, o suporte recebe uma reclamação, e uma redefinição de senha enviada duas vezes pode invalidar o primeiro código que a pessoa está lendo.
O problema central é o resultado desconhecido. Seu cliente envia a requisição, o servidor a aceita e a resposta se perde por uma queda de rede ou um timeout. Do seu lado, isso é idêntico a uma requisição que nunca chegou. Se você tentar novamente, pode duplicar. Se não tentar, pode perder a mensagem. Todos os padrões a seguir existem para resolver essa ambiguidade.
| Falha | O que você sabe | Risco se tratada de forma ingênua |
|---|---|---|
| Conexão recusada ou falha de DNS | A requisição nunca chegou à API | Seguro tentar novamente; o único risco é uma tempestade de retentativas |
| Timeout de leitura após o envio da requisição | Nada sobre a aceitação | Tentar novamente sem chave de deduplicação pode causar envio duplo |
| 429 Too Many Requests | A API rejeitou a chamada por motivos de ritmo | Uma nova tentativa imediata piora a pressão |
| 5xx da API ou de um gateway | Em geral não foi aceita, mas sem garantia | Em alguns casos, a mesma ambiguidade de um timeout |
| Erro de validação 400 ou 422 | A própria requisição está errada | Tentar novamente para sempre desperdiça capacidade e esconde um bug |
| Queda do worker após a chamada à API | Aceita, mas você nunca registrou isso | O job é reentregue e o e-mail é enviado de novo |
Chaves de idempotência e prevenção de envios duplicados
Uma operação idempotente produz o mesmo resultado, não importa quantas vezes você a execute. Muitas APIs HTTP permitem passar uma chave de idempotência, geralmente em um cabeçalho, de modo que uma requisição repetida com a mesma chave devolve o resultado original em vez de criar um novo recurso. O IETF tem um rascunho ativo para um campo de cabeçalho Idempotency-Key padronizado, o que mostra o quanto a ideia é difundida. Se o MigoSMTP oferece esse cabeçalho, e por quanto tempo uma chave é lembrada, deve ser confirmado na documentação da API do MigoSMTP. Não presumimos isso aqui.
A boa notícia é que você não precisa esperar pelo suporte do servidor. Você pode construir a mesma garantia do seu lado com uma tabela de deduplicação. A ideia central é que a sua aplicação defina a identidade de um e-mail antes de falar com a rede.
Escolha uma chave de deduplicação determinística
Uma boa chave é derivada do evento de negócio, não gerada no momento do envio. Use algo como order-1042-shipped ou user-77-password-reset-2026-10-15T09:14. Um UUID aleatório criado dentro do worker não ajuda, porque um job reentregue criaria um novo. Inclua o tipo da mensagem para que um recibo e um aviso de envio do mesmo pedido não colidam, e inclua um intervalo de tempo ou um contador somente quando envios repetidos forem legítimos, por exemplo, em um resumo diário.
Garanta a regra com uma restrição de unicidade
Verificações na aplicação, como consultar e depois inserir, estão sujeitas a condições de corrida. Coloque um índice único na chave e deixe o banco de dados resolver os empates. O primeiro a gravar vence e cria o registro de envio. Qualquer tentativa posterior recebe um erro de restrição ou encontra a linha existente e lê o seu estado.
CREATE TABLE email_sends (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
dedupe_key VARCHAR(190) NOT NULL,
to_address VARCHAR(320) NOT NULL,
template VARCHAR(80) NOT NULL,
payload_json JSON NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
attempts INT NOT NULL DEFAULT 0,
next_try_at DATETIME NULL,
message_id VARCHAR(255) NULL,
last_error TEXT NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
UNIQUE KEY uq_dedupe (dedupe_key)
);
Os status que usamos são pending, sending, accepted, failed e unknown. Accepted significa que a API retornou sucesso e você armazenou o ID da mensagem. Unknown significa que uma chamada foi feita e o resultado não é certo, o que abordamos na seção sobre retentativas. Se a API oferecer suporte a uma chave de idempotência, passe a mesma chave de deduplicação nela também, para que as duas camadas concordem. Trate o suporte no servidor como uma segunda rede de segurança, não como substituto.
O padrão outbox: envie somente o que foi confirmado
O bug clássico é assim: seu código salva um pedido, depois chama a API de e-mail e então retorna. Se a chamada à API falhar, o pedido existe sem e-mail. Se você chamar a API primeiro e o commit no banco falhar, o cliente recebe a confirmação de um pedido que não existe. Dois sistemas não podem ser atualizados em uma única transação, então mudamos o problema.
Com o padrão outbox, a requisição de e-mail é apenas mais uma linha gravada na mesma transação da alteração de negócio. Ou ambas são confirmadas, ou nenhuma. Um processo separado então entrega as linhas do outbox à API. A entrega se torna um job de segundo plano com possibilidade de nova tentativa, e o banco de dados passa a ser a única fonte de verdade sobre o que precisa ser enviado.
- Transação: insira o pedido e a linha de email_sends juntos, com status pending.
- Commit: somente após o commit algo se torna visível para o processo de envio.
- Reivindicação: um worker seleciona as linhas pendentes que já estão no prazo e as marca como sending, usando bloqueio de linha para que dois workers nunca peguem a mesma linha.
- Chamada à API: envie a requisição e depois registre o resultado e o ID da mensagem na linha.
- Reconciliação: um job periódico procura linhas presas em sending ou unknown e as resolve.
Você pode alimentar o worker fazendo polling na tabela a cada poucos segundos ou publicando em uma fila após o commit. O polling é mais simples e tem menos peças móveis. Uma fila ajuda quando o volume é alto, mas mantenha a tabela como registro de verdade, porque filas podem reentregar ou perder mensagens, e a tabela permite perguntar o que aconteceu com este e-mail.
Filas na sua aplicação: workers, concorrência e ordenação
Não chame a API de e-mail dentro da requisição web, a menos que tenha um motivo forte. Uma resposta lenta de qualquer terceiro vira um checkout lento, e um pico de cadastros vira um pico de conexões abertas. Retorne ao usuário assim que a linha do outbox for confirmada e deixe que os workers em segundo plano façam a entrega.
- Limite a concorrência. Um número fixo de workers, cada um com um pequeno pool de conexões HTTP, dá a você um teto previsível de requisições por segundo. Paralelismo ilimitado é como uma aplicação atinge, sem querer, o limite de uma API.
- Separe as filas por urgência. Redefinições de senha e códigos de uso único nunca devem esperar atrás de uma newsletter. Use filas ou prioridades distintas, como discutido em separação dos fluxos transacional e de marketing.
- Torne os jobs idempotentes. Presuma que todo job pode ser entregue duas vezes. O primeiro passo de um job é carregar a linha e sair se o status já for accepted.
- Não dependa da ordenação. Retentativas e workers paralelos embaralham as mensagens. Se a ordem importa, por exemplo, verificação antes de boas-vindas, modele isso como uma dependência nos seus dados, não como ordem da fila.
- Faça e-mails vencidos expirarem. Um código de login entregue depois de vinte minutos é pior do que nenhum. Dê às linhas sensíveis ao tempo um prazo de validade e marque-as como expiradas em vez de enviá-las.
Mantenha os payloads pequenos. Armazene o nome do template e as variáveis, ou o conteúdo final já renderizado, mas não grandes anexos dentro das mensagens da fila. Referencie arquivos armazenados por ID, de acordo com os limites explicados em nosso guia de limites de tamanho e MIME.
Timeouts e classificação de retentativas
Toda chamada HTTP precisa de timeouts explícitos. Um cliente sem timeout esperará muito mais do que qualquer pessoa se importa e ocupará um slot do worker durante todo esse tempo. Defina um timeout de conexão curto, frequentemente de um ou dois segundos, e um timeout total longo o suficiente para uma resposta normal, mas curto o bastante para falhar rápido. Escolha os valores a partir da sua própria latência medida e da orientação na documentação da API do MigoSMTP, não de um número em um post de blog.
Quando uma chamada termina, coloque o resultado em um de três grupos. Essa classificação é o coração da integração.
| Resultado | Exemplos | Ação |
|---|---|---|
| Aceito | 2xx com um ID de mensagem | Armazene o ID, marque como accepted e pare |
| Definitivamente rejeitado, não tente novamente | 400, 401, 403, 404, 422, outros 4xx que descrevem a sua requisição | Marque como failed, registre o corpo do erro e alerte se se repetir; corrija código, credenciais ou dados |
| Tentar mais tarde, mesma chave de deduplicação | 429, 500, 502, 503, 504, erros de conexão, erros de DNS | Faça backoff e tente novamente; respeite o Retry-After |
| Resultado desconhecido | Timeout de leitura, conexão reiniciada após o envio | Tente novamente somente com a mesma chave de deduplicação, ou reconcilie primeiro |
A semântica HTTP desses códigos, incluindo o cabeçalho Retry-After, é definida na RFC 9110, e a RFC 6585 define o 429. Observe a diferença em relação ao SMTP. No SMTP, as respostas 4xx são temporárias e as 5xx são permanentes, o que abordamos em nosso guia de códigos de bounce SMTP. Em uma API HTTP, os papéis são diferentes: 5xx significa que o serviço teve um problema e 4xx significa que a sua requisição teve um. Não misture os dois modelos. Um HTTP 400 nunca é uma falha temporária de e-mail.
Backoff com jitter
Os atrasos entre tentativas devem crescer exponencialmente e incluir aleatoriedade, para que mil workers que falharam juntos não voltem todos juntos. Uma abordagem comum é um atraso base dobrado a cada tentativa, limitado a um máximo, com uma fração aleatória aplicada. Se a resposta incluir Retry-After, use-o como mínimo. Defina um número máximo de tentativas ou uma idade máxima, após o qual a linha passa para failed e dispara um alerta. Nosso guia sobre limites de taxa, retentativas e backoff aprofunda a estratégia.
import random, time
RETRY_STATUS = {429, 500, 502, 503, 504}
def next_delay(attempt, retry_after=None, base=2.0, cap=300.0):
delay = min(cap, base * (2 ** attempt))
delay = random.uniform(delay / 2, delay)
if retry_after is not None:
delay = max(delay, float(retry_after))
return delay
def deliver(row, client):
try:
resp = client.post("/send", json=row.payload,
headers={"X-Dedupe-Key": row.dedupe_key},
timeout=(2, 15))
except (ConnectionError, TimeoutError):
return ("retry", next_delay(row.attempts))
if 200 <= resp.status_code < 300:
return ("accepted", resp.json().get("id"))
if resp.status_code in RETRY_STATUS:
ra = resp.headers.get("Retry-After")
return ("retry", next_delay(row.attempts, ra))
return ("failed", resp.text[:500])
O nome do cabeçalho neste exemplo é inventado para fins de ilustração. Use o que a documentação da API do MigoSMTP especificar, ou conte apenas com a sua própria tabela se esse cabeçalho não existir.
Tratamento de respostas e armazenamento de IDs de mensagem
Uma resposta de sucesso não é o fim da história, é o começo do rastreamento. Armazene o ID da mensagem retornado na resposta no seu registro de envio imediatamente, no mesmo passo que marca a linha como accepted. Assim, os eventos de webhook de entrega, bounce e reclamação podem ser associados a ele. A confiabilidade dessa segunda metade é tratada em como lidar com webhooks de e-mail de forma confiável.
- Guarde o corpo bruto da resposta da API por um curto período. Ele é valioso na depuração.
- Registre carimbos de data e hora de criação, primeira tentativa, aceitação e último evento. As lacunas entre eles mostram onde ocorrem os atrasos.
- Entenda o que "aceito" significa. Uma resposta 2xx de uma API de e-mail normalmente significa que o serviço colocou a mensagem na fila para entrega, não que o servidor do destinatário a aceitou. A entrega final é informada depois, por eventos.
- Não use mensagens de erro como lógica. Use códigos de status e quaisquer códigos de erro documentados, e trate o texto livre como informação para humanos.
- Indexe a coluna do ID da mensagem para que o suporte possa ir de um ID em um log até o registro de um cliente em uma única consulta.
Oculte segredos e dados pessoais nos logs. Registre a chave de deduplicação, o ID do envio, o status e o ID da mensagem, mas não chaves de API nem corpos completos de mensagens. As chaves devem ser armazenadas e rotacionadas conforme descrito em segurança de chaves de API.
Lotes e envios em massa
Enviar para muitos destinatários é uma carga de trabalho diferente de enviar um recibo. Agora você gerencia vazão, memória e equidade em relação ao restante do tráfego. Algumas APIs de e-mail oferecem um endpoint de lote que aceita muitas mensagens em uma só requisição, e outras esperam uma mensagem por requisição com muitas chamadas concorrentes. Consulte a sua conta do MigoSMTP ou a documentação da API para saber o que está disponível e quais são os limites de destinatários por requisição antes de projetar em torno de qualquer um dos modelos.
- Divida o público em blocos. Leia os destinatários em páginas do banco de dados, não como uma lista gigante na memória. Crie linhas de envio por destinatário e deixe os workers processá-las.
- Personalize por destinatário. Evite colocar muitos destinatários em To ou Cc. Cada pessoa deve receber a sua própria mensagem, com o seu próprio link de cancelamento de inscrição e seus próprios dados de rastreamento.
- Controle o ritmo do envio. Distribua grandes campanhas em uma janela de tempo em vez de liberar tudo de uma vez. O controle de ritmo também protege a sua reputação, principalmente em domínios novos, como descrito no guia de aquecimento.
- Torne a campanha retomável. Como cada destinatário tem uma linha com uma chave de deduplicação única, como campaign-318-user-9001, você pode interromper e reiniciar um envio a qualquer momento sem envio duplicado.
- Trate falhas parciais. Se uma chamada em lote puder ter sucesso para algumas mensagens e falhar para outras, armazene resultados por mensagem. Nunca marque um lote inteiro como aceito ou falho com base em um único código de status, a menos que a documentação diga que é assim que funciona.
Não ignore o básico das listas: O envio em massa por API não muda as regras de consentimento, supressão e cancelamento de inscrição. Filtre os endereços suprimidos antes de criar as linhas de envio, usando a abordagem do nosso guia de listas de supressão.
Exemplo prático: uma indisponibilidade, dois projetos
Eis um exemplo inventado, com números redondos. Uma loja online envia uma confirmação de pedido para cada pedido. Em uma tarde movimentada, ela cria 6.000 pedidos em uma hora, e a API de e-mail tem um período de 4 minutos de respostas lentas e erros 503 intermitentes.
| Etapa | Projeto ingênuo | Outbox com chave de deduplicação |
|---|---|---|
| Pedido criado | A requisição chama a API diretamente | A requisição grava o pedido e a linha de envio e retorna imediatamente |
| API lenta por 4 minutos | O checkout espera por um timeout longo, alguns clientes veem erros e clicam em Pagar de novo | Checkout não afetado; as linhas aguardam em pending |
| Timeout em 150 chamadas | O código tenta de novo imediatamente; muitas dessas mensagens já tinham sido aceitas | Linhas marcadas como unknown; novas tentativas mais tarde com a mesma chave de deduplicação |
| Resultado | 150 pedidos com cerca de 2 confirmações cada, além de pedidos duplicados por cliques duplos | Cerca de 150 mensagens atrasadas em alguns minutos; zero duplicatas |
| Impacto no suporte | Dezenas de tickets perguntando qual e-mail está correto | Nenhum; o alerta de idade da fila disparou e foi encerrado |
Com 6.000 pedidos na hora, a média é de 100 por minuto, então uma lentidão de 4 minutos deixa um acúmulo de cerca de 400 linhas. Se os workers conseguirem enviar 300 por minuto quando a API se recuperar, o acúmulo é eliminado em cerca de 2 minutos (400 linhas divididas pelos 200 por minuto de capacidade ociosa além dos 100 por minuto de novas chegadas). Vale fazer essa conta para o seu próprio sistema: a capacidade ociosa dos seus workers decide a rapidez da recuperação, e o limite de concorrência decide se a recuperação permanece dentro dos limites da sua conta.
Atenção aos limites de taxa
Os limites de taxa aparecem em formas como requisições por segundo, mensagens por dia, conexões concorrentes e destinatários por requisição. Quais se aplicam à sua conta, e seus valores exatos, estão na sua conta do MigoSMTP ou na documentação da API. Não os adivinhe. Construa o seu cliente de modo que esses números sejam configuração, e não constantes no código.
- Use um token bucket ou um atraso fixo entre requisições em cada worker, com um teto global somando todos os workers.
- Em um 429, pare de enviar daquele worker pelo período do Retry-After, ou por um atraso de backoff se nenhum for informado. Não repita simplesmente a mesma chamada.
- Fique atento ao sucesso lento. Uma tendência de alta na latência costuma surgir antes dos erros e é um sinal para reduzir a concorrência.
- Use um circuit breaker. Após uma sequência de falhas, pause as chamadas por uma janela curta e depois teste com uma requisição antes de retomar à velocidade plena.
- Tenha em mente os limites do lado receptor. A aceitação pelo provedor é apenas o primeiro salto. Os provedores de caixa de entrada aplicam seus próprios limites, abordados em nosso guia de requisitos para remetentes em massa.
Degradação controlada quando a API está fora do ar
Todo serviço externo ficará indisponível em algum momento. Decida com antecedência o que o seu produto faz, para que a resposta não seja improvisada durante um incidente.
| Tipo de e-mail | Comportamento sugerido durante uma indisponibilidade |
|---|---|
| Redefinição de senha, código de uso único | Enfileire com um prazo de validade curto; mostre na tela que a mensagem pode atrasar e ofereça reenvio após um intervalo de espera |
| Confirmação de pedido ou pagamento | Enfileire e entregue com atraso; mostre também a confirmação na página do pedido |
| Notificações de conta | Enfileire e entregue com atraso; considere combinar várias em uma |
| Newsletters e campanhas | Pause a campanha e retome depois; nunca tenha pressa em recuperar o atraso |
| Alertas internos | Use como alternativa outro canal, como chat, ou um segundo provedor |
Configure alertas sobre a profundidade da fila e a idade da linha pendente mais antiga, não apenas sobre contagens de erros. Uma fila crescente sem erros ainda significa clientes esperando. Defina um limite para a fila, de modo que memória e armazenamento não possam crescer sem controle, e decida o que será descartado primeiro se o limite for atingido. Se você projetar um segundo provedor como alternativa, lembre-se do trabalho envolvido em aquecer e autenticar um segundo caminho, conforme descrito em nosso guia de migração.
Testando a integração
Testes que verificam apenas uma resposta 200 não vão protegê-lo. O comportamento importante é o que acontece na falha, então facilite a produção de falhas. Execute o seu cliente contra um servidor simulado (mock) ou sandbox que possa ser instruído a responder lentamente, devolver 429 com Retry-After, devolver 503, derrubar a conexão depois de ler a requisição ou devolver um corpo malformado. Use um mail catcher para verificações de conteúdo, seguindo nosso guia de ambiente de staging.
- Teste de job duplicado: enfileire o mesmo job duas vezes e verifique que apenas uma requisição chega à API simulada.
- Teste de queda: derrube um worker após a chamada à API e antes da atualização do banco de dados, e verifique que o reconciliador resolve a linha sem um segundo envio.
- Teste de timeout: faça o mock aceitar a requisição e depois travar, e verifique que a linha termina como accepted exatamente uma vez.
- Teste de mensagem venenosa: envie um payload que retorne 422 e confirme que ele passa para failed após uma única tentativa, com o erro armazenado.
- Teste de carga: execute uma rajada realista contra o staging para confirmar que os limites de concorrência e o backoff se comportam como projetado.
Checklist de pré-lançamento
- Todo e-mail tem uma chave de deduplicação determinística e um índice único a faz valer.
- As linhas de envio são gravadas na mesma transação do evento de negócio (outbox).
- O suporte a um cabeçalho de idempotência foi confirmado na documentação da API do MigoSMTP, e a nossa própria tabela é usada de qualquer forma.
- Workers, e não requisições web, chamam a API, com concorrência limitada.
- Timeouts de conexão e total estão definidos em cada chamada.
- As respostas são classificadas: accepted, retry, failed, unknown. Outras respostas 4xx nunca são repetidas às cegas.
- O backoff tem jitter, um teto, um número máximo de tentativas e respeita o Retry-After.
- Os IDs de mensagem são armazenados nas linhas de envio e indexados.
- Os envios em massa são divididos em blocos, têm ritmo controlado e são retomáveis, com filtragem de supressão antes da criação das linhas.
- Os limites de taxa são configuração, obtidos da sua conta ou da documentação da API.
- Existem alertas para a idade da linha pendente mais antiga, a contagem de falhas e a taxa de 429.
- Os testes de falha para duplicatas, quedas, timeouts e 429 passam no staging.
Quer uma segunda opinião sobre o seu projeto de envio? Conte-nos como a sua aplicação envia e-mails hoje e onde retentativas ou duplicatas preocupam você, e nós o ajudaremos a planejar uma integração segura.
Leituras complementares e fontes
- RFC 9110: HTTP Semantics (códigos de status, Retry-After, métodos idempotentes)
- RFC 6585: Additional HTTP Status Codes (429 Too Many Requests)
- RFC 5321: Simple Mail Transfer Protocol
- Rascunho do IETF: The Idempotency-Key HTTP Header Field
- Amazon Builders Library: Timeouts, retries and backoff with jitter
Perguntas frequentes
O que é uma chave de idempotência em uma API de e-mail?
É um valor único que você anexa a uma requisição para que o servidor reconheça uma repetição da mesma requisição e evite executar o trabalho duas vezes. No caso de e-mail, isso significa que uma nova tentativa após um timeout não gera uma segunda cópia da mensagem. Se o MigoSMTP oferece um cabeçalho de idempotência, e como ele funciona, deve ser confirmado na documentação da API do MigoSMTP. De qualquer forma, você pode obter a mesma proteção com a sua própria tabela de deduplicação.
Se a API oferece idempotência, ainda preciso da minha própria tabela de deduplicação?
Sim, recomendamos. A idempotência no servidor geralmente cobre apenas uma janela limitada e somente as requisições que chegam à API. A sua própria tabela também impede jobs duplicados, disparos duplicados de webhooks e cliques duplos a montante, e ainda oferece uma trilha de auditoria do que você pretendia enviar.
É seguro tentar novamente após um timeout?
Somente se você tiver uma estratégia de deduplicação. Um timeout significa que você não sabe se a API aceitou a mensagem. Sem uma chave de idempotência ou uma consulta pela sua própria referência, uma nova tentativa pode enviar o e-mail duas vezes. Com uma delas, a nova tentativa é segura.
Quais códigos de status HTTP devo tentar novamente?
Tente novamente em falhas de rede, timeouts, 429 Too Many Requests e erros de servidor 5xx, usando backoff exponencial com jitter e respeitando qualquer cabeçalho Retry-After. Não tente novamente outros erros 4xx, como 400, 401, 403 ou 422, pois a mesma requisição falhará da mesma forma até que você mude algo.
O que é o padrão outbox?
Você grava a requisição de e-mail em uma tabela na mesma transação de banco de dados da alteração de negócio, e um processo separado lê as linhas não enviadas e chama a API. Isso elimina a brecha em que o commit no banco funciona, mas a chamada de e-mail falha, ou o contrário.
Devo enviar e-mails a partir da requisição web ou de uma fila?
De uma fila, para quase tudo. Uma fila protege a latência percebida pelo usuário, permite tentar novamente com segurança e permite controlar a taxa de envio. A exceção é uma ferramenta interna muito simples, em que um envio com falha pode ser mostrado diretamente a quem o acionou.
Como devo enviar uma grande campanha por uma API?
Divida os destinatários em lotes, limite a concorrência, respeite os limites documentados e o Retry-After, e distribua o envio ao longo do tempo. Consulte a sua conta do MigoSMTP ou a documentação da API para saber os limites exatos e se existe um endpoint de lote. Para domínios ou IPs novos, siga também um plano de aquecimento.
Por que armazenar o ID da mensagem retornado pela API?
Ele é a chave de ligação entre o seu registro de envio e eventos posteriores, como webhooks de entrega, bounce e reclamação. Sem ele, perguntas do suporte como "este cliente recebeu o recibo?" viram adivinhação.
Como testo uma integração de e-mail sem enviar e-mails reais?
Execute o cliente da API contra um servidor simulado (mock) ou sandbox capaz de devolver respostas lentas, 429 e 5xx sob demanda, e use um mail catcher para verificar o conteúdo. Faça as verificações na sua tabela de envios, não apenas nas chamadas HTTP. Nosso guia de ambiente de staging descreve configurações seguras.