Formulário de inscrição em newsletter

Formulário de inscrição em newsletter7 min de leitura

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.

Preet SutharFundador, Ikiform

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. 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.

A vida de uma inscrição com double opt-in, do formulário ao assinante confirmadoformulárioconsentimentomarcadoIkiformarmazena,assina webhookrelayadiciona nãoconfirmadoferramentade e-mailenvia o linkconfirmadorecebe todaediçãosem cliquesegue nãoconfirmado,sem ediçõesenviowebhookAPIcliqueA vida de uma inscrição com double opt-in, do formulário ao assinante confirmadoformulárioconsentimento marcadoIkiformarmazena, assinawebhookrelayadiciona nãoconfirmadoferramenta dee-mailenvia o linkconfirmadorecebe todaediçãosem cliquesegue nãoconfirmado,sem ediçõesenviowebhookAPIclique
  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:

FerramentaComo uma inscrição via API recebe um e-mail de confirmaçãoA armadilha
KitCrie 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 seuCreate subscriber usa state: "active" por padrão, e o estado não pode ser alterado depois por esse endpoint
MailerLiteLigue 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 existenteEnviar unconfirmed para um endereço que já está ativo pede que ele confirme de novo
beehiivEnvie 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
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
{
  "$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 lista cada regra de URL e o que cada resposta significa, e seu próprio servidor 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 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 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

Travou em algum passo ou quer um guia para o seu caso? Envie um e-mail para hello@ikiform.com.