Files
ALwrity/docs-site/docs/features/backlink-outreach/reply-inbox.md

113 lines
4.5 KiB
Markdown

# Reply Inbox
The reply inbox monitors your outreach mailbox via IMAP, automatically classifies replies, and deduplicates incoming messages.
## How It Works
```mermaid
flowchart TD
A[Poll IMAP Inbox] --> B[Search for New Messages]
B --> C[Fetch Message Headers + Body]
C --> D{Already Processed?}
D -->|Yes| E[Skip Duplicate]
D -->|No| F[Find Matching Attempt]
F --> G[Classify Reply]
G --> H[Store Reply Record]
H --> I[Update Lead Status if Interested]
style A fill:#e3f2fd
style G fill:#e8f5e8
style E fill:#ffebee
```
## IMAP Configuration
| Setting | Env Var | Default |
|---|---|---|
| IMAP host | `IMAP_HOST` | — (required) |
| IMAP port | `IMAP_PORT` | `993` |
| IMAP username | `IMAP_USER` | — (required) |
| IMAP password | `IMAP_PASS` | — (required) |
| Fetch limit | `IMAP_FETCH_LIMIT` | `50` |
!!! tip "Fetch limit"
`IMAP_FETCH_LIMIT` controls how many messages are processed per poll cycle. Increase for high-volume mailboxes, decrease to reduce IMAP load. Default is 50.
## Polling for Replies
**API:** `POST /api/v1/backlink-outreach/replies/poll`
The reply monitor:
1. Connects to IMAP over SSL.
2. Sanitizes the `sent_from_email` before searching (prevents IMAP injection).
3. Searches for messages sent to your outreach address.
4. Fetches up to `IMAP_FETCH_LIMIT` recent messages.
5. For each message, checks if it's already been processed (deduplication).
6. Matches the reply to an existing outreach attempt (Message-ID first, sender email fallback).
7. Classifies the reply and stores it.
### Reply Matching
Replies are matched to outreach attempts using a two-stage strategy:
1. **Message-ID matching (primary)**: Each sent email includes a unique `Message-ID` header. When the recipient replies, their email client includes the original `Message-ID` in `In-Reply-To` and `References` headers. The system extracts these and looks up `find_attempt_by_message_id(in_reply_to)` to find the exact outreach attempt.
2. **Sender email fallback**: If no Message-ID match is found (e.g., the reply client stripped headers), the system falls back to `find_attempt_by_from_email(from_email)` to find the most recent attempt sent to that address.
3. **Unmatched replies**: If neither strategy produces a match, the reply is still stored but not linked to an attempt.
### Deduplication
The system checks `reply_exists(from_email, subject)` before storing a new reply. This prevents duplicate entries when the same message appears in multiple IMAP folders or is fetched in overlapping poll cycles.
## Auto-Classification
Replies are automatically classified based on content analysis:
| Classification | Signals |
|---|---|
| **Interested** | "sounds good", "tell me more", "interested", "let's do it", "I'd love to" |
| **Not interested** | "not interested", "no thanks", "unsubscribe", "remove me", "stop sending" |
| **Out of office** | "out of office", "auto-reply", "automated response", "on vacation" |
| **Replied** | General reply that doesn't match other categories |
!!! note "Manual override"
Auto-classification is a best-effort guess. You can manually reclassify any reply in the UI by clicking the classification tag and selecting a different one.
### Auto-Suppression on "Not Interested"
When a reply is classified as "not interested", the sender's email is **automatically added to the suppression list** to prevent future outreach.
## Reply Inbox UI
The inbox shows:
- **From**: Sender name and email.
- **Subject**: Email subject line.
- **Classification tag**: Color-coded auto-classification badge.
- **Date**: When the reply was received.
- **Linked attempt**: The outreach attempt this reply matches (if any).
- **Lead status**: Current status of the associated lead.
### Actions
| Action | Description |
|---|---|
| **View** | Read the full reply body. |
| **Reclassify** | Change the auto-classification. |
| **Update lead status** | Move the lead to "replied" or "placed". |
| **Compose follow-up** | Open the email composer pre-filled with a follow-up draft. |
## Monitoring Best Practices
1. **Poll regularly**: Set up a scheduled job to call the poll endpoint every 5-15 minutes.
2. **Review unclassified**: Check "Replied" (generic) classifications and manually tag them.
3. **Act on interested leads quickly**: Respond within 24 hours for best conversion.
4. **Check out-of-office dates**: Schedule follow-ups for after the return date.
5. **Review suppression entries**: Periodically audit the suppression list for accidental additions.
---
*Next: [Analytics](analytics.md) — campaign performance tracking and exports.*