Logotipo Hedhog

Receba novidades do Hedhog no seu e-mail

Novos lançamentos, receitas e breaking changes — sem spam.

Submódulo inbox

messages

Envia e lê registros individuais de inbox_message — enfileiramento de envios de saída pela biblioteca Queue, entrega via Resend e o payload bruto do provedor para depuração.

Caminho de origem: libraries/inbox/src/message

Arquivo do módulo: message.module.ts

Introdução

O submódulo Messages (`MessageController`, montado em `/inbox/messages`) é a superfície de leitura e composição sobre `inbox_message`, a tabela com uma linha por e-mail em que residem tanto os e-mails de entrada quanto os de saída. A listagem e a busca são sempre restritas por `InboxAccessService.listAccessibleAccountIds`, e `GET /inbox/messages/:id/raw-payload` expõe o JSON `raw_payload` armazenado da mensagem — para uma mensagem de saída, esses são os metadados do job de fila (`queueJobId`, `queueName`, `queueType`); para uma mensagem de entrada, é o corpo completo original do webhook do Resend — o que é útil para suporte/depuração sem re-disparar a entrega.

O envio é assíncrono por design. `POST /inbox/messages/send` nunca fala diretamente com o Resend: `MessageService.send` valida se o chamador tem acesso à conta de destino, normaliza o assunto (removendo prefixos `re:`/`fwd:` iniciais para fins de threading), monta uma string de prévia, resolve o `from_email`/`from_name` da conta e então — dentro de uma única transação — cria uma nova `inbox_thread` ou reutiliza uma existente (`threadId` no corpo da requisição), cria a linha de `inbox_message` com `status: queued`, distribui `to`/`cc`/`bcc`/`replyTo` em linhas de `inbox_recipient` e grava um `mail_event` do tipo `delivery_delayed`. Somente após essa transação ser commitada é que ele enfileira um job (`type: inbox.email.send`, fila `inbox-emails`, `maxAttempts: 3`) por meio de `QueueJobService`, gravando o `queueJobId` retornado de volta no `raw_payload` da mensagem. Se o próprio enfileiramento lançar uma exceção, a mensagem é imediatamente marcada como `failed` com uma mensagem sintética de resposta do sistema explicando a falha, e o endpoint responde com um 400 em vez de deixar uma mensagem presa em `queued` sem nenhum job por trás dela.

A entrega efetiva acontece fora de banda: `MessageSendWorkerService` se registra em `QueueHandlerRegistry` sob o tipo de job `inbox.email.send` e, quando a fila o invoca, chama `MessageService.processQueuedSend`, que carrega os destinatários da mensagem, chama `ResendIntegrationService.sendEmail` e, em caso de sucesso, atualiza a mensagem para `status: sent` com o `provider_message_id` atribuído pelo Resend, grava um `mail_event` do tipo `sent` e atualiza o `last_message_at` da thread. Se o worker esgotar todas as retentativas de `maxAttempts`, `MessageSendWorkerService` chama `MessageService.handleQueuedSendFailure`, que marca a mensagem original como `failed` e — de forma idempotente, protegida por uma verificação de um mail_event `queue-failed:{id}` existente — sintetiza uma mensagem de entrada de "falha de entrega" a partir de `[email protected]` de volta na mesma thread, em português, para que o remetente veja a falha da mesma forma que veria qualquer outra resposta, sem precisar de uma UI de notificações separada.

Este arquivo de controller também declara um segundo controller não relacionado — `InboxWebhookController` — documentado separadamente em Webhooks; ele compartilha a mesma infraestrutura deste módulo (`message.module.ts`), mas não tem relação de auth com os endpoints CRUD de mensagens acima.

Endpoints HTTP

4 endpoints

Lista paginada de mensagens entre as contas acessíveis ao chamador, cada uma com seus destinatários e o mail_event mais recente.

Query
page, pageSize, search, accountId?, threadId?

Obtém o detalhe completo de uma única mensagem, incluindo todos os destinatários e todo o seu histórico de mail_event.

Params
id (int)

Obtém o JSON raw_payload armazenado da mensagem — metadados do job de fila para mensagens de saída, ou o corpo original do webhook do Resend para mensagens de entrada.

Params
id (int)

Cria e enfileira uma mensagem de saída para entrega assíncrona via biblioteca Queue. Cria a thread/mensagem/destinatários de forma síncrona (status: queued); a entrega efetiva pelo Resend acontece em um job de worker em segundo plano.

Body

FieldTypeRequiredNotes
accountIdintyesSending mailbox; caller must have access
threadIdintnoReply within an existing thread; omit to start a new thread
toRecipientDto[] ({ email, name? })yesAt least 1 recipient required
ccRecipientDto[] ({ email, name? })no
bccRecipientDto[] ({ email, name? })no
replyToRecipientDto[] ({ email, name? })no
subjectstring (max 255)yes
textBodystringno
htmlBodystringno