SolidHooksSolidHooks
Começar
Casos de usoIngerir webhooks por e-mail

Transforme e-mails recebidos em webhook

Muitos sistemas nunca vão enviar um webhook para você. Um fornecedor manda um aviso por e-mail, um banco manda um alerta, uma ferramenta interna manda um relatório noturno. Dê a qualquer um deles um endereço do SolidHooks e o que chegar lá vira um evento armazenado com um envelope processado, roteado pelas mesmas conexões e tentado de novo no mesmo cronograma do tráfego HTTP.
Um endereço por origemDeduplicação por Message-IDMesmas novas tentativas e comprovantes
O que este guia cobre
  1. 01Criar uma origem de e-mail e encontrar o endereço dela
  2. 02O envelope que o seu destino recebe
  3. 03Rotear por remetente ou assunto
  4. 04Deduplicação, limite de tamanho e anexos
  5. 05A única regra: uma origem recebe e-mail ou HTTP, nunca os dois

Como isso se encaixa no pipeline

E-mail é um provedor de uma origem, escolhido do mesmo jeito que você escolhe GitHub ou Stripe, não um produto separado. Depois que a mensagem é processada, ela é um evento como qualquer outro, o que significa que as partes do SolidHooks que você já conhece continuam funcionando: as conexões fazem a correspondência, as entregas fazem novas tentativas, a retenção faz a expiração e o seu consumidor recebe JSON por HTTP como sempre.

Sender
any mail client
Source address
<maskId>@sdhk.events
Stored event
parsed envelope, typed
Destination
HTTP POST
Seu consumidor nunca fala SMTP. Ele recebe o mesmo POST em JSON que receberia de um provedor de webhooks.

Configuração

  1. 1

    Crie uma origem com o provedor de e-mail

    Passe provider: "email" na criação, ou faça um PATCH em uma origem existente para mudá-la. A resposta traz emailAddress, que é null em todos os outros provedores.

    curl
    curl -s "$API/v1/sources" \  -H "authorization: Bearer $SDHK_KEY" \  -H 'content-type: application/json' \  -d '{ "name": "Supplier notices", "provider": "email",       "verifierConfig": {} }' → { "id": "src_...", "maskId": "Kb3xk29ZtQm7Rv1A",    "emailAddress": "Kb3xk29ZtQm7Rv1A@sdhk.events", ... }

    Converter uma origem que já tem um verificador exige verifierType: "noop" no mesmo PATCH. Nada assina um e-mail recebido, então a API se recusa a levar a credencial armazenada adiante em vez de manter um segredo que nunca leria. O mesmo PATCH também limpa o eventTypeField da origem e quaisquer idempotencyKeys, já que ambos descreviam um formato de payload que não chega mais.

  2. 2

    Passe o endereço para o remetente

    Cole o endereço onde o outro sistema espera um destinatário. Não há etapa de verificação nem DNS para configurar do seu lado.

  3. 3

    Conecte a origem a um destino

    Igual a qualquer outra origem. O que você filtra é o remetente ou o assunto, o que o eventTypeField da origem indicar, ou email.received se você o deixou sem definir. O roteamento por remetente ou assunto é explicado abaixo.

O que o seu destino recebe

O payload armazenado é um envelope normalizado, não um blob MIME bruto, então o seu handler não precisa de um parser de e-mail. Os endereços vêm separados, os dois corpos vêm separados e os anexos chegam em base64 com seus metadados.

payload
{  "from": "billing@supplier.example",  "to": ["Kb3xk29ZtQm7Rv1A@sdhk.events"],  "cc": [],  "subject": "Invoice #42",  "messageId": "<abc123@mail.supplier.example>",  "date": "Tue, 14 Jul 2026 09:00:00 +0000",  "text": "plain-text body",  "html": "<p>html body</p>",  "spamStatus": "NotSpam",  "bounce": false,  "attachments": [    { "name": "invoice.pdf", "contentType": "application/pdf", "size": 12345, "data": "<base64>" }  ]}

from é o cabeçalho From: da mensagem reduzido a um endereço simples, então Acme Billing <billing@supplier.example> chega como billing@supplier.example. É isso que o torna utilizável como chave de filtro. O nome de exibição muda, e o Return-Path por baixo é um endereço de bounce por mensagem em tudo o que é enviado por um serviço de e-mail. Esse remetente do envelope só é usado como último recurso, quando a mensagem não tem nenhum cabeçalho From:.

O corpo bruto do evento mantém o payload original completo do provedor de e-mail, incluindo campos não listados acima, com attachments[].data reduzido a null. Os bytes dos anexos ficam só no envelope, o que evita que um PDF grande seja armazenado duas vezes.

Uma origem faz uma coisa ou outra

Em uma origem de e-mail, um POST HTTP para a URL de ingestão dela retorna 400 BAD_REQUEST com a mensagem de que a origem ingere e-mail. Isso é proposital. E-mails e webhooks chegam por caminhos diferentes e só um deles produz um envelope, então uma origem que aceitasse os dois entregaria ao seu consumidor dois formatos de payload sob um mesmo tipo de evento.

Consequência para a idempotência
idempotencyKeys é rejeitado com 400 em uma origem de e-mail. Ali, a deduplicação é pelo Message-ID, que não é um caminho que você escolhe.

Rotear por remetente ou assunto

O tipo de evento de um e-mail vem do eventTypeField da origem, a mesma configuração que uma origem HTTP usa. Aponte-o para body.from e cada mensagem é tipada com o endereço do remetente, que um filtro de conexão então corresponde como qualquer outro tipo de evento. A correspondência ignora maiúsculas e minúsculas, porque os sistemas de e-mail não preservam a caixa de um cabeçalho From:, então uma lista de permissões escrita uma vez continua correspondendo a um remetente que depois chega como Billing@Supplier.example. O reenvio roteia pelo tipo armazenado na ingestão, então os filtros se comportam de forma idêntica na segunda vez.

Há dois caminhos disponíveis e nenhum outro: body.from e body.subject. São os campos que de fato distinguem uma mensagem da outra. O painel oferece os mesmos dois, então uma origem configurada pela API continua editável na interface do painel do SolidHooks.

curl
# Type each email with its sender instead of email.receivedcurl -s -X PATCH "$API/v1/sources/src_..." \  -H "authorization: Bearer $SDHK_KEY" \  -H 'content-type: application/json' \  -d '{ "data": { "eventTypeField": "body.from" } }' # Then a connection takes only that supplier:#   "filterRules": { "eventTypes": ["billing@supplier.example"] }
Sem definir, você recebe um único tipo
Sem eventTypeField, todo e-mail aceito é tipado como email.received. Ele continua filtrável, só não separável por remetente. O mesmo fallback vale por mensagem: um e-mail sem assunto em uma origem com body.subject cai em email.received em vez de ficar fora de todos os filtros.

Deduplicação e limite de tamanho

E-mail é maior e mais bagunçado que JSON de webhook, então vale conhecer as regras sobre o que é mantido antes que um anexo de 20MB chegue às 3h da manhã. Nada é rejeitado por ser grande demais. É cortado para caber, e o limite em que precisa caber chega no máximo a 4.096 KB.

deduplicaçãoPor Message-ID. Uma repetição retorna duplicate: true e não armazena nada.
limiteO maxPayloadSizeKb da origem, compartilhado entre corpos e anexos. Entre 1 e 4.096 KB, com padrão de 256.
texto primeiroO texto simples é contabilizado primeiro e cortado se ele sozinho estourar o limite.
html depoisDescartado por inteiro para null se texto mais html ainda estourarem o limite, nunca cortado em parte. Os dois casos definem bodyTruncated: true.
anexosOs metadados são mantidos, data vira null e truncated: true é definido. Os bytes nunca são cortados em parte. O que é contabilizado é o base64, então reserve cerca de um terço a mais que o tamanho do arquivo.
rotaçãorotate-mask muda o endereço, porque ele é derivado do maskId.

Práticas que valem a pena

  • Defina eventTypeField como body.from antes de precisar. Filtros escritos para email.received precisam ser reescritos quando um segundo remetente aparece no mesmo endereço.
  • Aumente maxPayloadSizeKb antes de precisar se o remetente anexa PDFs. O teto é 4.096 KB, e o base64 custa cerca de um terço a mais que o próprio arquivo. Descobrir o limite por uma flag truncated é um jeito pior de aprender.
  • Leia spamStatus e bounce no seu handler. Eles estão no envelope porque o e-mail chega de remetentes que você não controla.
  • Trate o endereço como uma credencial. Qualquer pessoa que o tenha pode criar eventos nessa origem, então faça a rotação se ele acabar em algum lugar público.

Perguntas

Dê um webhook aos sistemas que só mandam e-mail

Escolha e-mail como provedor, distribua o endereço e trate o resultado como qualquer outro evento.