# Double opt-in para um formulário de newsletter feito por você

> O Ikiform não envia e-mails de confirmação, então o double opt-in roda na sua ferramenta de e-mail: um relay adiciona cada inscrição como não confirmada e a ferramenta envia o link.

Publicado em 2026-10-25 · https://ikiform.com/pt-br/guides/newsletter-signup/double-opt-in

O Ikiform nunca envia e-mail para quem se inscreve, então o e-mail de confirmação precisa sair da ferramenta que envia a sua newsletter. Um relay recebe o webhook assinado do Ikiform e adiciona o leitor a essa ferramenta como não confirmado, a ferramenta envia um link por e-mail, e só um clique o torna assinante. Cada ferramenta liga isso de um jeito, e o relay nunca deve enviar uma segunda confirmação para quem já é assinante.

## O que muda aqui

O Ikiform não envia e-mail para quem preenche o formulário. Os e-mails de notificação vão só para você e sua equipe, então não há resposta automática, e-mail de confirmação nem double opt-in. Envie esses e-mails pela sua ferramenta de e-mail, disparados por um [webhook](https://ikiform.com/pt-br/docs/webhooks.md). Com o embed de um provedor, a confirmação é uma opção do formulário do provedor. Com o seu próprio formulário, há dois sistemas envolvidos, e a confirmação pertence ao que guarda a lista. O trabalho é garantir que cada inscrição chegue a essa ferramenta num estado que dispare a confirmação, e que não dispare quando não deve.

O double opt-in é uma máquina de estados dentro da ferramenta de e-mail. O leitor começa não confirmado, não pode receber edições e só vira assinante quando clica. A parte do Ikiform termina quando o relay responde `204`.

Diagrama: A vida de uma inscrição com double opt-in, do formulário ao assinante confirmado

1. O leitor marca a caixa de consentimento e envia seu formulário, que envia ao Ikiform.
2. O Ikiform armazena a inscrição e envia um webhook assinado ao seu relay.
3. O relay verifica a assinatura e adiciona o leitor à ferramenta de e-mail como não confirmado.
4. A ferramenta de e-mail envia ao leitor um link de confirmação.
5. Se ele clicar, a ferramenta o marca como confirmado e envia todas as edições.
6. Se ele nunca clicar, continua não confirmado e não recebe a newsletter.

Tudo depois do relay acontece na ferramenta de e-mail, incluindo o texto do e-mail de confirmação, a página que o link abre e os lembretes.

## A chave em cada ferramenta

Cada ferramenta tem sua própria ideia de não confirmado, e seu próprio jeito de transformar um novo assinante via API em um. Se errar isso, os assinantes são adicionados como já confirmados, sem e-mail nenhum:

| Ferramenta | Como uma inscrição via API recebe um e-mail de confirmação | A armadilha |
| --- | --- | --- |
| [Kit](https://ikiform.com/pt-br/guides/newsletter-signup/kit.md) | Crie o assinante com `state: "inactive"` e depois adicione-o a um formulário com o incentive email ligado. A documentação do bulk form do Kit diz que isso envia o incentive email; teste o endpoint individual com um endereço seu | Create subscriber usa `state: "active"` por padrão, e o estado não pode ser alterado depois por esse endpoint |
| [MailerLite](https://ikiform.com/pt-br/guides/newsletter-signup/mailerlite.md) | Ligue **Double opt-in for API and integrations** nas configurações de inscrição. Envie também `status: "unconfirmed"`, que o MailerLite exige antes de enviar e-mail a um assinante existente | Enviar `unconfirmed` para um endereço que já está ativo pede que ele confirme de novo |
| [beehiiv](https://ikiform.com/pt-br/guides/newsletter-signup/beehiiv.md) | Envie `double_opt_override: "on"` no create subscription, ou `"not_set"` para usar a configuração da própria publicação | `"off"` deixa o assinante ativo na hora, sem e-mail |

Teste cada uma com um endereço seu antes de confiar nela. As configurações das ferramentas mudam, e o e-mail em si é configurado na ferramenta: o assunto, o texto e a página que o link abre.

## Um relay que confirma uma vez

Um relay simples pede uma confirmação toda vez que chega um webhook. Dois casos tornam isso errado: um leitor que envia três vezes em um minuto recebe três e-mails, e um bot que inscreve o endereço de uma vítima coloca sua confirmação na caixa de entrada dela a cada tentativa. Este Cloudflare Worker pede à ferramenta no máximo uma confirmação por endereço por dia:

`src/index.ts`:

```ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { addUnconfirmed } from "./tool";

export interface Env {
  IKIFORM_WEBHOOK_SECRET: string;
  TOOL_API_KEY: string;
  SEEN: KVNamespace;
}

const DAY = 86_400;

async function digest(text: string) {
  const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
  return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}

export default {
  async fetch(request: Request, env: Env) {
    if (request.method !== "POST") return new Response(null, { status: 405 });
    const payload = await request.text();
    let event;
    try {
      event = await verifyWebhook({ payload, headers: request.headers, secret: env.IKIFORM_WEBHOOK_SECRET });
    } catch (error) {
      if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
      throw error;
    }
    if (event.type !== "submission.created" || event.data.fields.consent !== true) {
      return new Response(null, { status: 204 });
    }

    const email = String(event.data.fields.email).trim().toLowerCase();
    const key = `confirm:${await digest(email)}`;
    if (await env.SEEN.get(key)) return new Response("Confirmation already requested today", { status: 200 });

    const answer = await addUnconfirmed(env, email, event.data.fields.first_name);
    if (answer.status === 429) {
      return new Response("Rate limited", { status: 503, headers: { "retry-after": answer.headers.get("retry-after") ?? "60" } });
    }
    if (!answer.ok) return new Response(`Email tool answered ${answer.status}`, { status: 502 });

    await env.SEEN.put(key, event.id, { expirationTtl: DAY });
    return new Response(null, { status: 204 });
  },
};
```

`wrangler.jsonc`:

```json
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "newsletter-relay",
  "main": "src/index.ts",
  "compatibility_date": "2026-10-01",
  "routes": [{ "pattern": "hooks.example.com", "custom_domain": true }],
  "kv_namespaces": [{ "binding": "SEEN", "id": "<your KV namespace id>" }]
}
```

- `addUnconfirmed` em `./tool` é a chamada da ferramenta da tabela acima. Copie o corpo dela da página do Kit, MailerLite ou beehiiv.
- A chave do KV é um SHA-256 do endereço em minúsculas, então o armazenamento nunca guarda o endereço em si. Ela expira depois de um dia.
- A chave só é gravada depois que a ferramenta aceita a requisição. Se a ferramenta falhar, o Ikiform tenta de novo e a nova tentativa não é bloqueada.
- Responder `200` a uma repetição diz ao Ikiform que a entrega deu certo, então ela não é refeita, e o corpo explica o motivo no log de entregas.
- O Worker roda num domínio personalizado. O Ikiform recusa hostnames `workers.dev` como URLs de webhook. A [documentação de webhooks](https://ikiform.com/pt-br/docs/webhooks.md) lista cada regra de URL e o que cada resposta significa, e [seu próprio servidor](https://ikiform.com/blog/form-submissions-to-your-own-server.md) mostra um relay que armazena cada entrega uma única vez.

> O KV é eventualmente consistente entre locais, então duas entregas para o mesmo endereço em poucos segundos podem passar as duas. Para um e-mail de confirmação, isso é aceitável. Se você precisa de uma garantia rígida, guarde a chave num Durable Object ou num banco de dados com uma coluna única.

## O que o formulário deve dizer

Um leitor que vê "Obrigado por se inscrever" e depois não encontra nada na pasta de newsletters acha que falhou. Diga o que acontece em seguida, na página em que ele cai:

1. Configure a frase de sucesso, ou sua página de agradecimento, para dizer que há um e-mail para abrir: "Quase lá. Abra o e-mail que enviamos e confirme seu endereço."
2. Diga o nome do remetente que ele deve procurar e sugira a pasta de spam se nada chegar em alguns minutos.
3. Na ferramenta de e-mail, defina a página que o link de confirmação abre como a sua própria página "Inscrição confirmada", para a jornada terminar no seu site.

A caixa de consentimento do formulário e o e-mail de confirmação fazem trabalhos diferentes. A caixa registra que alguém disse sim na sua página. O clique prova que o endereço pertence a quem disse sim. A maioria das listas quer os dois. O [modelo de formulário de newsletter](https://ikiform.com/forms/newsletter-signup) tem a caixa obrigatória.

## Pegadinhas

- **Assinantes existentes.** Alguém já confirmado se inscreve de novo a partir de uma nova página. Não o volte para não confirmado; a [página do MailerLite](https://ikiform.com/pt-br/guides/newsletter-signup/mailerlite.md) mostra um relay que procura o endereço primeiro.
- **Pessoas que se descadastraram.** Uma inscrição nem sempre é permissão para desfazer um descadastro. O beehiiv só reativa quando você envia `reactivate_existing: true`, e o MailerLite só reinscreve com `resubscribe: true`. Envie esses valores só quando o formulário disser isso.
- **Scanners de links.** Alguns filtros de e-mail corporativos abrem os links das mensagens recebidas para verificá-los. Se uma ferramenta confirma só com o carregamento de uma página, um scanner pode confirmar um endereço em que ninguém clicou. Confira se a página de confirmação da sua ferramenta pede o clique num botão.
- **Entregabilidade.** A confirmação é o primeiro e-mail que um leitor recebe de você. Envie-a de um domínio autenticado na sua ferramenta, ou ela cai no spam e a inscrição nunca se completa.
- **Não confirmados se acumulam.** Eles ainda não são assinantes. Decida na sua ferramenta se vai enviar um lembrete, e depois deixe-os em paz.

## Confira se funciona

1. Envie o formulário com um endereço seu. A página pede para você conferir a caixa de entrada.
2. Abra a entrega em **Webhooks** no Ikiform. Ela mostra `succeeded` com o `204` do relay.
3. Abra o assinante na sua ferramenta de e-mail. Ele está não confirmado, inativo ou pendente, dependendo da ferramenta.
4. Abra o e-mail de confirmação e clique. O assinante fica ativo ou confirmado.
5. Envie o mesmo endereço de novo no mesmo dia. A entrega mostra `200` com "Confirmation already requested today", e nenhum segundo e-mail chega.
6. Inscreva um endereço que já está confirmado. Ele continua confirmado e não recebe um novo e-mail de confirmação.

## Perguntas

### O Ikiform pode enviar o e-mail de confirmação do double opt-in?

Não. O Ikiform nunca envia e-mail para quem envia um formulário. Sua ferramenta de e-mail envia a confirmação, disparada pelo webhook do Ikiform por meio de um relay ou de uma ferramenta de automação.

### Ainda preciso de uma caixa de consentimento se uso double opt-in?

Elas fazem trabalhos diferentes. A caixa registra que a pessoa concordou na sua página, com data e hora. O clique de confirmação prova que ela é dona do endereço. A maioria das listas mantém os dois.

### Por que meu assinante não recebeu e-mail de confirmação?

O mais provável é que o relay o tenha criado como já confirmado: o create subscriber do Kit usa ativo por padrão, o MailerLite precisa da opção de double opt-in por API ligada, mais um status não confirmado para assinantes existentes, e o double_opt_override do beehiiv definido como off pula o e-mail. Confira o estado do assinante na ferramenta.

### Posso usar Zapier ou Make em vez de um relay?

Sim. Aponte o webhook do Ikiform para a automação e use a ação dela para a sua ferramenta de e-mail. Confira se as opções da ação criam o assinante num estado não confirmado; você perde a proteção de uma vez por dia, a menos que adicione uma etapa de filtro.

## Mais guias

- [Formulário de inscrição em newsletter](https://ikiform.com/pt-br/guides/newsletter-signup.md): Crie um formulário de newsletter no seu próprio markup, registre o consentimento, barre inscrições de bots e passe cada assinante para Kit, MailerLite, beehiiv ou qualquer ferramenta.
- [Kit (ConvertKit)](https://ikiform.com/pt-br/guides/newsletter-signup/kit.md): Conecte seu próprio formulário de newsletter ao Kit com um relay que cria o assinante, o adiciona a um formulário do Kit para o incentive email e marca a posição com uma tag.
- [MailerLite](https://ikiform.com/pt-br/guides/newsletter-signup/mailerlite.md): Conecte seu próprio formulário de inscrição ao MailerLite: um relay adiciona novos leitores como não confirmados para o double opt-in e nunca pede a um assinante que confirme duas vezes.
- [beehiiv](https://ikiform.com/pt-br/guides/newsletter-signup/beehiiv.md): Conecte seu próprio formulário de inscrição ao beehiiv: um relay cria cada subscription com double opt-in ligado, a posição como UTM source e a página como referrer.
- [Site estático](https://ikiform.com/pt-br/guides/newsletter-signup/static-site.md): Adicione um formulário de newsletter a um site estático em Hugo, Jekyll, Eleventy ou Astro, mantenha a chave de API da ferramenta de e-mail fora da página e confirme na ferramenta.
- [Formulário de newsletter no Next.js](https://ikiform.com/pt-br/guides/newsletter-signup/nextjs.md): Um formulário de newsletter no rodapé do Next.js: uma server action com checagem de consentimento e Turnstile, enviando ao Ikiform, e um route handler que adiciona leitores ao Kit.
