# Ticket System - Email Integration ## Overview The ticket system integrates with BMC Hub's email workflow engine to automatically create tickets from incoming emails. Uses **Option B: Message-ID Threading** for robust email-to-ticket linkage. ## Architecture ``` Incoming Email → Email Classifier → Email Workflow Engine → Ticket Integration ↓ create_ticket action ↓ EmailTicketIntegration.process_email_for_ticket() ↓ ┌───────┴───────┐ ↓ ↓ New Ticket Reply to Existing (creates TKT-XXX) (links via Message-ID) ``` ## Email Threading Logic ### Message-ID Based Threading (Option B) The system uses email headers to detect if an email is part of an existing ticket thread: 1. **In-Reply-To Header**: Check if contains `TKT-YYYYMMDD-XXX` pattern 2. **References Header**: Check all message IDs in chain for ticket number 3. **Subject Line**: Check for `[TKT-YYYYMMDD-XXX]` or `Re: TKT-YYYYMMDD-XXX` If ticket number found → **Link to existing ticket** If NOT found → **Create new ticket** ### Ticket Number Format Pattern: `TKT-YYYYMMDD-XXX` - `TKT`: Prefix - `YYYYMMDD`: Date (e.g., 20251215) - `XXX`: Sequential number (001-999) Example: `TKT-20251215-001` ## Workflow Actions ### 1. `create_ticket` Creates new ticket OR links to existing ticket (smart routing). **Workflow Definition:** ```json { "name": "Support Request → Ticket", "classification_trigger": "support_request", "workflow_steps": [ { "action": "create_ticket", "params": { "customer_id": 123, "assigned_to_user_id": 5 } } ] } ``` **Parameters:** - `customer_id` (optional): BMC customer ID to link ticket to - `assigned_to_user_id` (optional): User ID to assign ticket to - `priority` (optional): Override priority detection (low/normal/high/critical) **Returns:** ```json { "ticket_id": 42, "ticket_number": "TKT-20251215-001", "created": true, "linked": false } ``` ### 2. `link_email_to_ticket` Explicitly link email to a specific ticket (manual routing). **Workflow Definition:** ```json { "action": "link_email_to_ticket", "params": { "ticket_number": "TKT-20251215-001" } } ``` **Parameters:** - `ticket_number` (required): Target ticket number **Returns:** ```json { "ticket_id": 42, "ticket_number": "TKT-20251215-001", "linked": true } ``` ## Automatic Features ### Tag Extraction Extracts `#hashtags` from email body and adds as ticket tags: ``` Email body: "We need help with #billing #urgent issue" → Ticket tags: ["billing", "urgent"] ``` - Max 10 tags per ticket - Minimum 3 characters - Converted to lowercase ### Priority Detection Automatically determines ticket priority from email content: **Critical**: kritisk, critical, down, nede, urgent, akut **High**: høj, high, vigtig, important, haster **Low**: lav, low, spørgsmål, question, info **Normal**: Everything else (default) Checks both subject line and extracted tags. ### Email Metadata Stores rich metadata in ticket: - **Description**: Formatted with sender email, received date, original body - **Custom Fields**: `email_from`, `email_message_id`, `created_from_email` - **Email Log**: Full threading data in `tticket_email_log` table ## Database Storage ### `tticket_email_log` Table Stores all email-ticket linkages for audit trail: ```sql CREATE TABLE tticket_email_log ( id SERIAL PRIMARY KEY, ticket_id INTEGER NOT NULL REFERENCES tticket_tickets(id), email_message_id TEXT NOT NULL, email_subject TEXT, email_from TEXT NOT NULL, email_received_at TIMESTAMP, is_reply BOOLEAN DEFAULT FALSE, thread_data JSONB, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` **`thread_data` JSONB structure:** ```json { "message_id": "", "in_reply_to": "", "references": " " } ``` ## Usage Examples ### Example 1: Basic Support Request **Incoming Email:** ``` From: customer@example.com Subject: Help with network issue Body: Our internet is down. Can you help? ``` **Workflow Configuration:** ```json { "name": "Support Email → Ticket", "classification_trigger": "support_request", "confidence_threshold": 0.7, "workflow_steps": [ { "action": "create_ticket", "params": { "assigned_to_user_id": 5 } } ] } ``` **Result:** - Creates ticket `TKT-20251215-001` - Priority: `normal` (no urgent keywords) - Tags: [] (no hashtags found) - Assigned to user 5 - Email logged in `tticket_email_log` ### Example 2: Email Reply to Ticket **Incoming Email:** ``` From: customer@example.com Subject: Re: TKT-20251215-001 In-Reply-To: Body: Thanks, issue is resolved now ``` **Result:** - **Detects existing ticket** via In-Reply-To header - **Adds comment** to ticket `TKT-20251215-001` - Does NOT create new ticket - Logs as reply (`is_reply=true`) ### Example 3: Tagged Urgent Request **Incoming Email:** ``` From: vip@example.com Subject: URGENT: Server down! Body: Production server is down #critical #server ``` **Result:** - Creates ticket with priority `critical` (subject keyword) - Tags: `["critical", "server"]` - Custom field: `created_from_email=true` ## API Endpoints ### Get Ticket Email Thread ```http GET /api/v1/tickets/{ticket_id}/emails ``` Returns chronological list of all emails linked to ticket. **Response:** ```json { "ticket_id": 42, "ticket_number": "TKT-20251215-001", "emails": [ { "id": 1, "email_message_id": "", "email_from": "customer@example.com", "email_subject": "Help with issue", "email_received_at": "2025-12-15T10:00:00Z", "is_reply": false, "created_at": "2025-12-15T10:01:00Z" }, { "id": 2, "email_message_id": "", "email_from": "customer@example.com", "email_subject": "Re: TKT-20251215-001", "email_received_at": "2025-12-15T11:00:00Z", "is_reply": true, "created_at": "2025-12-15T11:01:00Z" } ] } ``` ### Find Tickets by Email Address ```http GET /api/v1/tickets/by-email/{email_address} ``` Returns all tickets associated with an email address. **Response:** ```json { "email_address": "customer@example.com", "tickets": [ { "id": 42, "ticket_number": "TKT-20251215-001", "subject": "Network issue", "status": "open", "created_at": "2025-12-15T10:00:00Z" } ] } ``` ## Configuration ### Settings (`.env`) ```bash # Ticket system enabled TICKET_ENABLED=true # Email integration enabled (requires email system) TICKET_EMAIL_INTEGRATION=true # Auto-assign new tickets (requires user_id) TICKET_AUTO_ASSIGN=false TICKET_DEFAULT_ASSIGNEE_ID=5 # Default priority for new tickets TICKET_DEFAULT_PRIORITY=normal ``` ## Testing ### Test Email-to-Ticket Creation ```bash curl -X POST http://localhost:8001/api/v1/test/email-to-ticket \ -H "Content-Type: application/json" \ -d '{ "email_data": { "message_id": "", "subject": "Test ticket", "from_address": "test@example.com", "body": "This is a test #testing", "received_at": "2025-12-15T10:00:00Z" } }' ``` ### Test Email Reply Linking ```bash curl -X POST http://localhost:8001/api/v1/test/email-to-ticket \ -H "Content-Type: application/json" \ -d '{ "email_data": { "message_id": "", "subject": "Re: TKT-20251215-001", "from_address": "test@example.com", "body": "Reply to existing ticket", "received_at": "2025-12-15T11:00:00Z", "in_reply_to": "" } }' ``` ## Troubleshooting ### Tickets Not Created **Check:** 1. Email workflow engine enabled (`EMAIL_WORKFLOWS_ENABLED=true`) 2. Workflow exists for classification trigger 3. Confidence threshold met 4. Workflow action is `create_ticket` (NOT old `create_ticket` stub) **Debug:** ```sql -- Check workflow executions SELECT * FROM email_workflow_executions WHERE status = 'failed' ORDER BY created_at DESC LIMIT 10; ``` ### Email Not Linked to Ticket **Check:** 1. Ticket number format correct (`TKT-YYYYMMDD-XXX`) 2. Ticket exists in database 3. Email headers contain ticket number (In-Reply-To, References, Subject) **Debug:** ```sql -- Check email logs SELECT * FROM tticket_email_log WHERE ticket_id = 42 ORDER BY created_at DESC; ``` ### Duplicate Tickets Created **Check:** 1. Email reply headers missing ticket number 2. Subject line doesn't match pattern (e.g., `Re: Ticket 123` instead of `Re: TKT-20251215-001`) **Solution:** - Ensure outgoing ticket emails include ticket number in subject: `[TKT-20251215-001]` - Add ticket number to Message-ID: `` ## Best Practices 1. **Include Ticket Number in Replies**: Always include `[TKT-YYYYMMDD-XXX]` in subject line 2. **Use Message-ID with Ticket Number**: Format: `` 3. **Set Customer ID in Workflow**: Improves ticket organization and reporting 4. **Monitor Workflow Executions**: Check `email_workflow_executions` table regularly 5. **Review Failed Actions**: Alert on repeated workflow failures ## Security Considerations 1. **No Email Body Storage**: Only stores metadata and body in ticket description 2. **Sender Validation**: Consider implementing sender verification (SPF/DKIM) 3. **Spam Prevention**: Email classifier should filter spam before workflow execution 4. **Customer Isolation**: Ensure `customer_id` properly set to prevent data leakage ## Future Enhancements - **Attachment Handling**: Link email attachments to ticket attachments - **Email Templates**: Auto-reply with ticket number - **SLA Integration**: Start SLA timer on ticket creation from email - **Multi-Ticket Threading**: Support one email creating multiple tickets - **Smart Customer Detection**: Auto-detect customer from sender domain ## Related Documentation - [Ticket System Architecture](TICKET_SYSTEM_ARCHITECTURE.md) - [Email Workflow System](EMAIL_WORKFLOWS.md) - [Database Schema](../migrations/025_ticket_module.sql)