Transforme e-mails recebidos em webhook
- 01Criar uma origem de e-mail e encontrar o endereço dela
- 02O envelope que o seu destino recebe
- 03Rotear por remetente ou assunto
- 04Deduplicação, limite de tamanho e anexos
- 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.
Configuração
- 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 trazemailAddress, que énullem todos os outros provedores.curlcurl -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 oeventTypeFieldda origem e quaisqueridempotencyKeys, já que ambos descreviam um formato de payload que não chega mais. - 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
Conecte a origem a um destino
Igual a qualquer outra origem. O que você filtra é o remetente ou o assunto, o que o
eventTypeFieldda origem indicar, ouemail.receivedse 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.
{ "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.
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.
# 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"] }
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.
Message-ID. Uma repetição retorna duplicate: true e não armazena nada.maxPayloadSizeKb da origem, compartilhado entre corpos e anexos. Entre 1 e 4.096 KB, com padrão de 256.null se texto mais html ainda estourarem o limite, nunca cortado em parte. Os dois casos definem bodyTruncated: true.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.rotate-mask muda o endereço, porque ele é derivado do maskId.Práticas que valem a pena
- Defina
eventTypeFieldcomobody.fromantes de precisar. Filtros escritos paraemail.receivedprecisam ser reescritos quando um segundo remetente aparece no mesmo endereço. - Aumente
maxPayloadSizeKbantes 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 flagtruncatedé um jeito pior de aprender. - Leia
spamStatusebounceno 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.