03. Email Classification
Email classification determines what type of email arrived so the pipeline can route it appropriately. Classification ranges from simple spam detection to nuanced categorization like "customer complaint," "sales inquiry," or "internal question."
The classification prompt structure matters. Provide clear category definitions and request a JSON response:
CLASSIFICATION_PROMPT = """You are an email classification system. Classify the following email into exactly one category.
Categories:
- urgent: Requires response within 2 hours
- customer_complaint: Customer expressing dissatisfaction
- sales_inquiry: Potential customer asking about products/services
- support_request: Existing customer asking for help
- internal: Internal communication between team members
- newsletter: Automated newsletters, announcements
- other: Does not fit other categories
Email Subject: {subject}
Email Body:
{body}
Respond only with a JSON object:
{{"category": "category_name", "confidence": 0.0-1.0, "reasoning": "brief explanation"}}
"""
def classify_email(subject, body, model='llama3.2:3b'):
"""Classify an email using local AI."""
prompt = CLASSIFICATION_PROMPT.format(subject=subject, body=body[:2000])
response = chat(model=model, messages=[
{'role': 'user', 'content': prompt}
])
import json
result = json.loads(response['message']['content'])
return result
The 2000-character limit on body text prevents token overflow while maintaining enough context for accurate classification. Adjust based on your model's context window.
Confidence scores matter for production systems. Emails with confidence below a threshold (typically 0.7) should escalate to human review. The pipeline should track classification confidence for later review.
def route_email(email_data):
"""Route email based on classification with confidence threshold."""
classification = classify_email(
email_data['subject'],
email_data['body']
)
if classification['confidence'] < 0.7:
# Flag for human review
return {'route': 'human_review', 'reason': 'low_confidence'}
category_routes = {
'urgent': 'urgent_queue',
'customer_complaint': 'support_manager',
'sales_inquiry': 'crm_system',
'support_request': 'support_ticket',
'internal': 'internal_channel',
'newsletter': 'auto_archive',
'other': 'general_inbox'
}
return {
'route': category_routes.get(classification['category'], 'general_inbox'),
'classification': classification
}
Local verification checkpoint
Run the smallest example from this chapter in a local workspace and record the package version, runtime, data path, and observed output. If the result depends on model size, vector count, CPU/GPU backend, or available memory, note that constraint beside the exercise so the lesson remains reproducible.
Define your own email categories that match your actual inbox. Test the classifier on fifty emails and record accuracy.