Ritto Mail Docs

Migrar do Resend

Um comando move sua conta do Resend; duas linhas de ambiente movem seu código — o formato de wire é idêntico.

A API REST do Ritto Mail é compatível no wire com a do Resend: mesmos endpoints, mesmos formatos de requisição e resposta. Migrar é uma mudança de configuração, não uma reescrita. Os dados da conta — contatos, segmentos, tópicos, templates, webhooks, domínios, supressões — vêm com um comando.

Entregue a um agente

A migração inteira — inventário, movimentação da conta, mudanças de código, DNS, virada — está escrita como um único prompt que um agente pode seguir de ponta a ponta, incluindo as salvaguardas (Resend somente leitura, chaves nunca em arquivos, perguntar antes de aplicar).

Ou aponte o agente para ele: /pt-BR/prompts/migrate-from-resend.md.

1. Mova sua conta

Crie uma chave de API rm_ com acesso total em Chaves de API no painel em app.ritto.email e rode, na sua máquina:

npx ritto-mail migrate --from resend

Ele pede sua chave do Resend (acesso total) e sua chave do Ritto Mail, lê sua conta no Resend, mostra um plano, aguarda a confirmação, aplica e imprime um resumo.

O que ele faz:

  • O Resend é apenas lido. Toda requisição ao Resend é um GET a um endpoint documentado; nada lá é criado, alterado ou excluído. A CLI mostra ao conectar o limite de taxa que o Resend informa e se mantém abaixo dele: 8 requisições por segundo por padrão (o limite do time no Resend é 10, compartilhado com o seu envio em produção), recuando pelos cabeçalhos ratelimit-* e a cada 429. --rps muda o ritmo.
  • Suas chaves nunca saem da sua máquina. A ferramenta fala apenas com api.resend.com e com a sua API do Ritto Mail. As chaves ficam em memória durante a execução, nunca são gravadas em arquivo e são redigidas de toda linha de log. Sem telemetria, sem verificação de atualização.
  • Virada primeiro, enriquecimento depois. A passagem 1 cria propriedades, tópicos, segmentos, domínios, webhooks, templates, broadcasts e supressões e faz upsert dos contatos com suas associações a segmentos e o unsubscribed. Ela termina em minutos, e a CLI então imprime Cutover ready com os registros DNS e a linha do RESEND_BASE_URL: o envio transacional já pode mudar nesse ponto. O enriquecimento — só quando a conta usa tópicos ou propriedades de contato — lê então cada contato uma vez por faceta, primeiro as inscrições em tópicos (para os opt-outs chegarem antes das propriedades), depois as propriedades, com ritmo e tempo restante ao vivo. Segure envios por tópico e broadcasts até ele terminar. As duas passagens retomam de onde pararam após um Ctrl-C e uma nova execução, e --skip enrichment as deixa de fora.
  • Rode de novo antes da virada. Cada execução é um diff: linhas existentes são atualizadas quando diferem e deixadas como estão quando são iguais; contatos passam por upsert pelo e-mail. Rode o mesmo comando de novo logo antes de virar o tráfego e os contatos que chegaram nesse meio-tempo vêm junto. Uma nova execução lê todos os contatos de novo, então custa o tempo inteiro de enriquecimento; --only enrichment roda só as duas passagens sobre contatos que já estão no destino, e --only properties,enrichment roda só a passagem de propriedades. Contas migradas com a CLI 0.1.x não receberam valores de propriedades (o formato do fio foi lido errado); esse único comando os preenche. Um contato que surgiu no Resend desde a última execução é criado por essa passagem com o unsubscribed e os nomes, e fica registrado para o rollback como qualquer outro. O checklist de virada só é impresso quando contatos, domínios e supressões fazem parte da execução.

Antes de uma migração grande

O enriquecimento domina: dois GETs por contato contra um limite compartilhado com o envio que o seu app faz no mesmo time do Resend. A estimativa que o plano imprime segue de contatos × facetas ÷ ritmo:

ContatosFacetasA 8 req/sA 10 req/sA 50 req/s
36.685tópicos + propriedadescerca de 2 h 30 mincerca de 2 hcerca de 25 min
160.000tópicos + propriedadescerca de 11 hcerca de 9 hcerca de 1 h 50 min
160.000só tópicoscerca de 5 h 30 mincerca de 4 h 30 mincerca de 55 min

Três coisas encurtam isso:

  • Peça ao Resend um aumento temporário. A documentação do Resend diz que o limite do time "pode ser aumentado para remetentes confiáveis sob pedido" (Settings → Usage mostra o atual). Passe o ritmo concedido explicitamente — --rps 50 — a CLI aceita valores acima de 10 e avisa quando o ritmo passa do limite que detectou.
  • Rode fora do horário de pico. O limite é por time, então o enriquecimento compete com os envios da sua produção; os 429 caem nos dois lados. Uma segunda chave de API não ajuda.
  • Deixe folga. Quando a CLI detecta um limite acima de 10 e --rps não foi passado, ela usa o limite menos 2 para o seu app continuar enviando.
RecursoO que vem
ContatosE-mail, nomes, unsubscribed, propriedades, inscrições em tópicos, associações a segmentos. Descadastros são preservados; ninguém é reinscrito.
Segmentos, tópicos, propriedadesCasados por nome / nome / chave: criados quando faltam, atualizados quando diferem.
TemplatesNome, alias, assunto, html, texto. from, reply_to e variables não podem ser armazenados — listados como passos manuais.
WebhooksEndpoint e eventos. O segredo de assinatura é copiado, então o receptor que você já roda continua verificando (as entregas carregam os headers svix-*). --fresh-webhook-secrets gera segredos novos. Eventos que o Ritto Mail também emite são levados junto — os sete tipos email.* mais contact.created, contact.updated e contact.deleted; os demais (domain.*, email.suppressed) são descartados por webhook e listados.
SupressõesBounces, reclamações e entradas manuais, com sua origem.
DomíniosCriados com return path e configurações de rastreamento, na região de envio do Ritto Mail (sa-east-1) — a região do Resend não é levada junto. Os toggles de rastreamento só vêm junto com um subdomínio de rastreamento; sem ele, o relatório os lista para você configurar no painel. Os registros DNS precisam ser adicionados de novo — veja o passo 3.
BroadcastsRascunhos e agendados entram como rascunhos. Enviados são pulados, a menos que --include-sent.

O que não vem: chaves de API (o Resend expõe apenas os nomes — o relatório as lista como pendência), registros DKIM/DNS (as chaves são por provedor) e o histórico de e-mails enviados. Audiências, descontinuadas no Resend, são puladas — segmentos as cobrem.

Flags, variáveis de ambiente, arquivos, códigos de saída e uso em CI estão na referência da CLI.

2. Aponte seu código existente para o Ritto Mail

Os SDKs oficiais do Resend respeitam RESEND_BASE_URL, então a migração são duas linhas de ambiente — nenhuma mudança de código:

RESEND_API_KEY=rm_...
RESEND_BASE_URL=https://api.ritto.email

Defina a variável no ambiente do processo (configuração da hospedagem, contêiner, node --env-file), não no código depois do import: o SDK de Node até o resend@6.12.3 a lê uma vez, quando o módulo carrega, e o construtor ignora a opção baseUrl (aceita a partir do resend@6.12.4). Se a URL não for aplicada, o pedido vai para o Resend, que responde 401 com API key is invalid para uma chave rm_.

Três detalhes que diferem do que uma integração com o Resend pode assumir:

  • Os campos de remetente e destinatário aceitam exatamente uma caixa postal cada, nas formas da RFC 5322 ada@example.com, Ada <ada@example.com> ou "Ada, Inc." <ada@example.com>. Um nome de exibição com vírgula precisa estar entre aspas; sem elas, é lido como dois endereços e o envio é rejeitado com 422. O Resend aceita a forma sem aspas.

  • PATCH /contacts/{id}/topics recebe um array JSON puro de entradas { "id": "<topic-id>", "subscription": "opt_in" | "opt_out" }, não um objeto em volta dele; GET /contacts/{id}/topics lê de volta a escolha efetiva por tópico.

  • Não existe POST /contacts/imports (CSV). Contatos em massa vão por POST /contacts/batch?on_conflict=upsert em JSON, até 1.000 por chamada, com x-batch-validation: permissive para manter as linhas válidas quando algumas falham.

Continue com o SDK do Resend que você já usa — o Ritto Mail não tem SDKs próprios. O SDK de Python lê RESEND_API_URL em vez de RESEND_BASE_URL, o de Ruby precisa da barra final (https://api.ritto.email/), e os SDKs de Java, .NET e Elixir recebem a URL base como opção do cliente; a página SDKs mostra a configuração para cada linguagem.

3. Conclua o que a CLI lista

O resumo termina com um checklist. Três itens sempre estão nele:

  • Adicione os registros DNS de cada domínio. O Ritto Mail usa um par de chaves DKIM próprio, então os registros são novos mesmo para um domínio que já envia pelo Resend. O relatório imprime uma tabela pronta para copiar com os registros por domínio (também em Domínios no painel). Os dois provedores podem ficar verificados lado a lado durante a migração.
  • Defina RESEND_BASE_URL (passo 2) em todo ambiente que envia.
  • Crie as chaves de API — uma por nome que o relatório lista (por exemplo prod, staging) em Chaves de API.

Mais dois aparecem quando se aplicam: valores de from / reply_to de templates para definir por envio, e tipos de evento de webhook que o Ritto Mail não emite. Corpos de broadcast não precisam de mudança: {{{RESEND_UNSUBSCRIBE_URL}}} é um alias suportado de {{{UNSUBSCRIBE_URL}}}.

Envie um email pela nova base URL e veja-o chegar a Entregue na página de Emails — a migração é isso.


Resend é uma marca registrada da Plus Five Five, Inc. O Ritto Mail não é afiliado nem endossado pelo Resend.

Nesta página