fix(vacation): a resposta de ausencia passa a ser uma resposta

Chegava como conversa nova. Ia sem qualquer cabecalho de encadeamento,
por isso todos os clientes de correio a mostravam solta, sem relacao
com a mensagem que a tinha desencadeado - e quem escreveu tinha de
descobrir sozinho a qual dos seus emails aquilo respondia.

In-Reply-To nomeia a mensagem que esta a ser respondida e References
leva a cadeia inteira, que e o que permite a um cliente colocar a
resposta no sitio certo mesmo quando nunca viu as mensagens pelo meio
(RFC 5322 seccao 3.6.4). A cadeia e limitada em comprimento: uma
conversa longa faria este cabecalho crescer sem fim.

O assunto passa a ecoar o original - "Fora do escritorio: Re: Proposta
comercial" - porque e o que a pessoa le na sua lista, e porque ha
clientes que agrupam pelo assunto e nao apenas pelos cabecalhos. O
texto configurado fica como prefixo em vez de ser substituido, para
continuar a dizer o que a mensagem e. Um assunto que ja anuncia ser
resposta nao recebe um segundo "Re:".

Sem Message-ID no original nao se escreve nada: apontar para uma
mensagem inexistente faria os clientes mostrarem a resposta agarrada a
nada. Um Message-ID com quebra de linha e recusado por inteiro - viria
de um remetente remoto, e uma quebra ali terminaria o cabecalho e
deixaria o resto ser lido como mais cabecalhos.

Os cabecalhos que impedem dois respondedores automaticos de se
responderem um ao outro continuam todos la, com teste que o garante.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Opus 5 committed 2026-08-22 14:43:52 -03:00
1 parent 508cc7c944
commit 866bd21846
4 files changed
+325 -9

No files matched your search

@@ -308,11 +308,18 @@ func (uc *ProcessInboundEmailUseCase) Handle(ctx context.Context, input ProcessI
folder = decision.Folder
}
if decision.Vacation != nil {
// The message being answered travels with the reply, so it
// arrives inside that conversation instead of as a loose note
// the sender has to match up themselves.
original := headersOf(payload)
vacationReplies = append(vacationReplies, pendingVacation{
To: input.Sender,
From: input.RecipientAddresses[i],
Subject: decision.Vacation.Subject,
Body: decision.Vacation.Body,
To: input.Sender,
From: input.RecipientAddresses[i],
Subject: decision.Vacation.Subject,
Body: decision.Vacation.Body,
OriginalMessageID: firstHeader(original, "message-id"),
OriginalReferences: firstHeader(original, "references"),
OriginalSubject: firstHeader(original, "subject"),
})
}
}