Document Version: 1.0 Last Updated: 2026-02-05 Target Release: Production v2.0
- Overview
- Business Requirements
- Category Management
- Email Preprocessing
- PII Detection (GDPR)
- CSV Export Formats
- Configuration Guide
- Migration from v1.x
- Validation Checklist
- Troubleshooting
This document describes the enhanced classification system designed for Client ClassyMail compatibility, implementing professional-grade email processing with:
- Category Definitions & Exclusions: Professional taxonomy with "what it IS" vs "what it ISN'T"
- Technical Slugs: Stable identifiers for CSV export (independent of display names)
- Email Preprocessing: LLM-based intelligent extraction (subject, conversation, signatures)
- PII Detection: GDPR-compliant personal information extraction
- Dual CSV Formats: Minimal (client compatible) and Enriched (full audit trail)
Endpoint: GET /api/emails
Response Format:
{
"items": [
{
"id": "uuid-12345",
"classification": {
"detected_intents": [
{"intent": "Billing inquiry", "confidence": 0.95},
{"intent": "Account management", "confidence": 0.85}
]
},
"processing_time_ms": 1234,
"pii_detected": true,
"pii_data": {
"names": ["John Doe"],
"emails": ["john.doe@example.com"],
"phones": ["+1 555-123-4567"]
}
}
]
}- Use concrete keywords in descriptions (for example: "lightning, overvoltage, short-circuit" instead of "electrical problems").
- Make exclusions explicit with edge cases (for example: "Does not include X, Y, Z").
- Test ambiguous cases and refine exclusions when categories overlap.
- Validate with all 3 strategies:
- Standard for speed
- Reasoning for accuracy checks
- Vision for documents with photos
Client ClassyMail requires CSV export with:
- Primary Format:
ID;INTENTIONS(semicolon delimiter, UTF-8 BOM) - Intentions Format: Technical slugs separated by commas (e.g.,
billing_inquiry,account_statement) - Optional Enriched Format: Additional columns for audit and quality control
Each category now includes four fields:
| Field | Type | Purpose | Example |
|---|---|---|---|
name |
String | Display name (UI) | "Billing inquiry" |
slug |
String | Technical ID (CSV) | "billing_inquiry" |
description |
String | What it IS (definition) | "Documents related to billing or account inquiries" |
exclusions |
String | What it ISN'T (boundaries) | "Does not apply to professional certificates or vehicles" |
Rules:
- Lowercase only
- Underscores for spaces
- Alphanumeric characters + underscore only
- No accents (é→e, è→e, à→a)
Auto-Generation: If slug is not provided, it's automatically generated from the name:
slug = name.lower().replace(" ", "_").replace("é", "e").replace("è", "e").replace("à", "a")
slug = "".join(ch for ch in slug if ch.isalnum() or ch == "_")Categories are presented to the LLM in this format (no emojis):
1. Billing inquiry
DEFINITION: Documents related to billing or account inquiries
EXCLUSIONS: Does not apply to professional certificates or vehicles
2. Account management
DEFINITION: Bank statements and financial transactions
EXCLUSIONS: Does not apply to invoices or contracts
Navigate to Settings → Classification Tab:
-
Click on existing category to expand accordion
-
Edit fields:
- Name (Display): User-facing label
- Slug (Technical ID): CSV identifier
- Definition (What it IS): LLM classification criteria
- Exclusions (What it ISN'T): Negative examples
-
Click Save Changes to System to commit
Email preprocessing uses GPT-4.1-mini to intelligently extract relevant content before classification:
- Subject Extraction: Identifies email subject from markdown
- Conversation Extraction: Removes history, signatures, boilerplate
- Content Assembly: Combines subject + last conversation
Navigate to Settings → Processing Tab → Email Preprocessing:
| Toggle | Description | Default | Cost Impact |
|---|---|---|---|
| Enable Preprocessing | Master switch | ✓ Enabled | +€0.001/email |
| Include Email Subject | Extract subject line | ✓ Enabled | None |
| Extract Last Conversation | Remove history/signatures | ✓ Enabled | +€0.001/email |
| Detect PII | Extract personal information | ✗ Disabled | +€0.002/email |
Original Email (5000 chars)
↓
[1. Extract Subject]
↓
Subject: "Re: Claim #12345"
↓
[2. LLM Extraction: Remove History/Signatures]
↓
Clean Content (1200 chars)
↓
[3. Combine]
↓
Final Input: "Subject: Re: Claim #12345\n\nHello, I would like to..."
↓
[Classification]
Preprocessing Service: classymail/services/email_preprocessing.py
LLM Prompt for Conversation Extraction:
Extract ONLY the last meaningful conversation from an email thread.
REMOVE:
- All quoted replies (lines starting with '>', 'On ... wrote:', etc.)
- Email signatures (contact info, disclaimers, legal notices)
- Automatic reply tags and boilerplate text
- Thread history and previous messages
KEEP:
- The actual message content from the most recent sender
- Any attachments mentions relevant to this message
Response Format:
{
"preprocessing_metadata": {
"preprocessing_enabled": true,
"subject_included": true,
"conversation_extracted": true,
"original_length": 5000,
"processed_length": 1200,
"subject": "Re: Claim #12345"
}
}Extract Personal Identifiable Information for GDPR compliance audits.
| Category | Examples | Use Case |
|---|---|---|
| names | "John Doe", "Jane Smith" | Identity verification |
| emails | "john.doe@example.com" | Contact masking |
| phones | "+1 555-123-4567" | Anonymization |
| addresses | "123 Main Street, New York, NY 10001" | Data localization |
| contract_ids | "POL-2024-001234", "CLAIM-5678" | Reference extraction |
| dates | "1985-03-15", "2024-01-20" | Timeline analysis |
| other | SSN, passport numbers | Sensitive data flag |
Model: GPT-4.1-mini (JSON mode) Cost: ~€0.002 per email Latency: +200-500ms
Response Format:
{
"names": ["John Doe", "Jane Smith"],
"emails": ["john.doe@example.com"],
"phones": ["+1 555-123-4567"],
"addresses": ["123 Main Street, New York, NY 10001"],
"contract_ids": ["POL-2024-001234"],
"dates": ["1985-03-15"],
"other": []
}class EmailRecord(BaseModel):
pii_detected: bool # True if any PII found
pii_data: dict # Full structured extraction
preprocessing_metadata: dict # Processing detailsUsage: Production exports for client systems
Columns: ID;INTENTIONS
Example:
ID;INTENTIONS
uuid-12345;billing_inquiry,account_statement
uuid-67890;unclassified
uuid-11111;dommages_electriquesCharacteristics:
- Semicolon delimiter (
;) - UTF-8 BOM encoding (Excel compatible)
- Technical slugs (stable identifiers)
- Comma-separated multi-category
Usage: Quality control, GDPR audits, model debugging
Columns:
ID;INTENTIONS;CONFIDENCES;MODEL;JUSTIFICATION;EXCLUSION_REASON;PROCESSING_TIME_MS;PII_DETECTED;PII_TYPES;PII_COUNT
Example:
ID;INTENTIONS;CONFIDENCES;MODEL;JUSTIFICATION;EXCLUSION_REASON;PROCESSING_TIME_MS;PII_DETECTED;PII_TYPES;PII_COUNT
uuid-12345;billing_inquiry;0.95;phi4;Mentions "home insurance";;1234;True;names,emails,phones;5
uuid-67890;unclassified;;;;"No clear category";2100;False;;0Column Descriptions:
| Column | Type | Description |
|---|---|---|
ID |
String | Unique email identifier |
INTENTIONS |
String | Comma-separated category slugs |
CONFIDENCES |
String | Comma-separated confidence scores (0.0-1.0) |
MODEL |
String | Classification model used |
JUSTIFICATION |
String | LLM reasoning (pipe-separated if multiple) |
EXCLUSION_REASON |
String | Why no category was assigned |
PROCESSING_TIME_MS |
Integer | Total processing duration |
PII_DETECTED |
Boolean | Personal information found |
PII_TYPES |
String | Comma-separated PII categories detected |
PII_COUNT |
Integer | Total number of PII items extracted |
Endpoint: GET /api/emails/export/csv
Parameters:
?status=all # all | REVIEW_REQUIRED | PROCESSED | ERROR
&format=enriched # minimal | enriched
Response Headers:
Content-Type: text/csv; charset=utf-8
Content-Disposition: attachment; filename=emails_export_enriched_20260205_143000.csv
{
"email_preprocessing": {
"enabled": true,
"include_subject": true,
"extract_last_conversation": true,
"detect_pii": false
}
}- Use Case: Standard production workflow
- Cost: ~€0.002/email
- Benefits: Clean input, better classification accuracy
{
"email_preprocessing": {
"enabled": true,
"include_subject": true,
"extract_last_conversation": true,
"detect_pii": true
}
}- Use Case: GDPR compliance audits
- Cost: ~€0.004/email
- Benefits: Full PII extraction + preprocessing
{
"email_preprocessing": {
"enabled": false,
"include_subject": false,
"extract_last_conversation": false,
"detect_pii": false
}
}- Use Case: Testing, comparison with v1.x
- Cost: €0/email (no preprocessing overhead)
- Benefits: Direct classification on raw OCR output
Old (v1.x):
{"name": "Billing inquiry", "description": ""}New (v2.0):
{
"name": "Billing inquiry",
"slug": "billing_inquiry",
"description": "Documents related to billing or account inquiries...",
"exclusions": "Does not apply to professional certificates..."
}Migration: Automatic! The system auto-generates slugs from names for old categories.
Old: Category names in plain text New: Technical slugs (stable identifiers)
Impact: Client systems must update parsing logic to use slugs.
The system maintains backward compatibility through:
- API: Unchanged response structure (new fields are optional)
- Settings: Old categories are auto-migrated on first load
- CSV: Slugs auto-generated if missing
-
Category Configuration
- All categories have slugs defined
- Definitions and exclusions are populated
- Prompt format verified (no emojis, professional structure)
-
Email Preprocessing
- Toggle configuration tested
- Subject extraction validated
- Conversation extraction accuracy checked
- Cost monitoring enabled
-
PII Detection (if enabled)
- Sample emails tested
- All PII types extracted correctly
- Performance impact acceptable (<1s overhead)
-
CSV Export
- Minimal format tested (ID;INTENTIONS)
- Enriched format validated (all 10 columns)
- UTF-8 BOM encoding verified (Excel compatible)
- Slug mapping correct
-
Integration Testing
- End-to-end flow: Upload → Process → Export
- Client ClassyMail system can parse CSV
- GDPR audit reports generated successfully
Cause: Old categories without slugs Solution: Edit each category in Settings and save (triggers auto-migration)
Symptoms: Full email content in classification Check:
- Settings → Processing → Email Preprocessing enabled
- Check logs for LLM preprocessing errors
- Verify GPT-4.1-mini deployment exists
Possible Causes:
- PII detection toggle disabled
- Email genuinely contains no PII
- LLM endpoint unavailable
Debug:
# Check preprocessing metadata in response
GET /api/emails/{id}
# Look for:
"preprocessing_metadata": {
"preprocessing_enabled": true,
"conversation_extracted": true
},
"pii_detected": false,
"pii_data": nullCause: Slug mapping mismatch Solution:
- Verify category slugs in Settings
- Re-export with updated slugs
- Check category name→slug mapping
For technical support or questions about this integration:
- Documentation: docs/
- Architecture: docs/ARCHITECTURE.md
- API Reference:
GET /api/docs(OpenAPI)
End of Document