LookupConversationID finds a conversation_id by matching In-Reply-To / References message IDs against stored messages. Checks both email_message_id (inbound) and provider_message_id (outbound). Uses prefix matching because SES bare IDs stored in provider_message_id (e.g. <010f...>) may lack the @reg
(ctx context.Context, agentID string, messageIDs []string)
| 2712 | // in provider_message_id (e.g. <010f...>) may lack the @region.amazonses.com suffix |
| 2713 | // that appears in the actual email headers sent to recipients. |
| 2714 | func (s *Store) LookupConversationID(ctx context.Context, agentID string, messageIDs []string) (string, error) { |
| 2715 | if len(messageIDs) == 0 { |
| 2716 | return "", fmt.Errorf("no message IDs to look up") |
| 2717 | } |
| 2718 | |
| 2719 | var conversationID string |
| 2720 | err := s.pool.QueryRow(ctx, |
| 2721 | `SELECT conversation_id FROM messages |
| 2722 | WHERE agent_id = $1 |
| 2723 | AND conversation_id <> '' |
| 2724 | AND ( |
| 2725 | email_message_id = ANY($2) |
| 2726 | OR provider_message_id = ANY($2) |
| 2727 | OR EXISTS ( |
| 2728 | SELECT 1 FROM unnest($2::text[]) AS lookup(id) |
| 2729 | WHERE lookup.id LIKE REPLACE(provider_message_id, '>', '%') |
| 2730 | AND provider_message_id <> '' |
| 2731 | ) |
| 2732 | ) |
| 2733 | ORDER BY created_at DESC LIMIT 1`, |
| 2734 | agentID, messageIDs, |
| 2735 | ).Scan(&conversationID) |
| 2736 | if err != nil { |
| 2737 | return "", err |
| 2738 | } |
| 2739 | return conversationID, nil |
| 2740 | } |
| 2741 | |
| 2742 | // --- Conversations (thin read layer over messages.conversation_id) --- |
| 2743 | // |