point livechat verification email replies at a no-reply address

Livechat customers verify by pasting the code into chat, not by replying to the email. If the notification sender happens to be the same mailbox as a polled inbox, a stray email reply would get ingested as a new conversation. Setting Reply-To to noreply@<sender-domain> keeps those replies out of any monitored inbox. The email conversation path is unchanged and stays replyable.
This commit is contained in:
Abhinav Raut
2026-07-20 23:04:41 +05:30
parent 7760974e07
commit 1034617b63
+30 -2
View File
@@ -260,12 +260,19 @@ func (t *sendEmailVerificationTool) Execute(ctx context.Context, args string) (s
}
sendErr = t.m.convo.SendTransientEmail(t.conv.InboxID, t.conv.ID, t.conv.UUID, []string{email}, subject, body)
} else {
sendErr = t.m.notifier.Send(notifier.Message{
msg := notifier.Message{
RecipientEmails: []string{email},
Subject: t.m.i18n.T("ai.agent.verificationEmailSubject"),
Content: body,
Provider: notifier.ProviderEmail,
})
}
// Livechat verification happens in chat, not email. Point replies at a no-reply address so a
// stray email reply can't be ingested as a new conversation when the notification sender
// doubles as a polled inbox.
if noReply := t.m.noReplyAddress(); noReply != "" {
msg.Headers = map[string][]string{"Reply-To": {noReply}}
}
sendErr = t.m.notifier.Send(msg)
}
if sendErr != nil {
t.m.lo.Error("error sending verification code email", "conversation_uuid", t.conv.UUID, "error", sendErr)
@@ -275,6 +282,27 @@ func (t *sendEmailVerificationTool) Execute(ctx context.Context, args string) (s
return "A verification code has been emailed to the customer. Tell them you have sent a code to their email and ask them to reply with it.", nil
}
// noReplyAddress returns a no-reply address on the notification sender's domain, or "" if unavailable.
func (m *Manager) noReplyAddress() string {
raw, err := m.setting.Get("notification.email.email_address")
if err != nil {
return ""
}
var addr string
if err := json.Unmarshal(raw, &addr); err != nil || addr == "" {
return ""
}
parsed, err := mail.ParseAddress(addr)
if err != nil {
return ""
}
at := strings.LastIndex(parsed.Address, "@")
if at < 0 {
return ""
}
return "noreply@" + parsed.Address[at+1:]
}
// checkEmailVerificationTool verifies the code the customer entered against the pending one.
type checkEmailVerificationTool struct {
m *Manager