# Email Tracking Configuration

This document explains how click and open tracking works with different email service providers (ESPs).

## Overview

Email tracking allows you to monitor:
- **Open Tracking**: When recipients open your emails (via tracking pixels)
- **Click Tracking**: When recipients click links in your emails (via URL rewriting)

## How to Enable Tracking

### In Your Code

Add `track_opens` and `track_clicks` to your EmailMessage:

```python
from amsdal_mail import EmailMessage, get_connection

message = EmailMessage(
    subject='Newsletter',
    body='Check out our latest products!',
    html_body='<h1>Latest Products</h1><a href="https://example.com">Shop Now</a>',
    from_email='news@example.com',
    to=['subscriber@example.com'],
    track_opens=True,
    track_clicks=True,
)

backend = get_connection('ses')
backend.send_messages([message])
```

## Backend-Specific Configuration

### AWS SES

**Important**: SES does not support `track_opens` and `track_clicks` as API parameters. Instead, tracking is configured through **Configuration Sets**.

#### Steps to Enable Tracking in SES:

1. **Create a Configuration Set** in AWS SES Console:
   ```
   AWS Console → Amazon SES → Configuration Sets → Create Set
   ```

2. **Add Event Destination**:
   - SNS Topic (recommended for webhooks)
   - CloudWatch (for metrics)
   - Kinesis Firehose (for data streaming)
   - Kinesis Data Stream

3. **Enable Event Types**:
   - ✅ Send
   - ✅ Delivery
   - ✅ Open
   - ✅ Click
   - ✅ Bounce
   - ✅ Complaint
   - ✅ Reject

4. **Use Configuration Set in Code**:
   ```python
   from amsdal_mail import get_connection

   backend = get_connection(
       'ses',
       configuration_set='my-tracking-config-set',
   )
   ```

   Or via environment variable:
   ```bash
   AWS_SES_CONFIGURATION_SET=my-tracking-config-set
   ```

#### SES Event Delivery:

When events occur (opens, clicks, bounces, etc.), SES publishes them to your configured destination:

**Example SNS Message for Click Event**:
```json
{
  "eventType": "Click",
  "mail": {
    "messageId": "0000...",
    "timestamp": "2024-01-21T10:00:00.000Z",
    "source": "sender@example.com",
    "destination": ["recipient@example.com"]
  },
  "click": {
    "link": "https://example.com/product",
    "linkTags": {
      "campaign": "newsletter"
    },
    "userAgent": "Mozilla/5.0...",
    "ipAddress": "192.0.2.1",
    "timestamp": "2024-01-21T10:05:00.000Z"
  }
}
```

#### Configuration Set via AWS CLI:

```bash
# Create configuration set
aws sesv2 create-configuration-set \
  --configuration-set-name my-tracking-config-set

# Add SNS event destination
aws sesv2 create-configuration-set-event-destination \
  --configuration-set-name my-tracking-config-set \
  --event-destination-name tracking-events \
  --event-destination '{
    "Enabled": true,
    "MatchingEventTypes": ["SEND", "DELIVERY", "OPEN", "CLICK", "BOUNCE", "COMPLAINT"],
    "SnsDestination": {
      "TopicArn": "arn:aws:sns:us-east-1:123456789:ses-events"
    }
  }'
```

## Tracking Limitations

### Open Tracking Limitations:
- ❌ Only works for HTML emails (not plain text)
- ❌ Blocked if recipient has images disabled
- ❌ Privacy-focused clients (Apple Mail Privacy Protection) may preload images
- ❌ VPNs and proxies can obscure real open location

### Click Tracking Limitations:
- ❌ Link previews may trigger false clicks
- ❌ Security scanners may click all links
- ❌ May be blocked by privacy extensions

## Best Practices

1. **Always Use HTTPS**: Tracking pixels and rewritten URLs should use HTTPS
2. **Respect Privacy**: Include opt-out options for tracking
3. **Configuration Sets for SES**: Set up dedicated configuration sets for different email types
4. **Monitor Bounce Rates**: High bounce rates may indicate list quality issues
5. **Test Tracking**: Send test emails to verify tracking pixels are working

## Webhooks

amsdal_mail includes built-in webhook support for receiving real-time tracking events from ESPs. Events are normalized into a common format and emitted via AMSDAL EventBus.

### Enable Webhooks

```bash
AMSDAL_MAIL_WEBHOOK_ENABLED=true
AMSDAL_MAIL_WEBHOOK_BASE_PATH=/webhooks/mail  # default
```

### Handle Tracking Events

Subscribe to `EmailTrackingEvent` in your app:

```python
from amsdal_utils.events import EventBus
from amsdal_utils.events import EventListener

from amsdal_mail import EmailTrackingContext
from amsdal_mail import EmailTrackingEvent
from amsdal_mail import TrackingEventType


class BounceHandler(EventListener[EmailTrackingContext]):
    def handle(self, context, next_fn):
        if context.event_type == TrackingEventType.BOUNCED:
            print(f"Bounce: {context.recipient} - {context.reject_reason}")
        return next_fn(context)

    async def ahandle(self, context, next_fn):
        if context.event_type == TrackingEventType.BOUNCED:
            print(f"Bounce: {context.recipient} - {context.reject_reason}")
        return await next_fn(context)


# Register in your AppConfig.on_setup()
EventBus.subscribe(EmailTrackingEvent, BounceHandler)
```

### Supported Event Types

| Event Type | Description |
|------------|-------------|
| `QUEUED` | Message queued by ESP |
| `SENT` | ESP accepted for delivery |
| `DELIVERED` | Email was delivered to recipient |
| `DEFERRED` | Delivery was delayed |
| `BOUNCED` | Email bounced (hard or soft) |
| `REJECTED` | ESP rejected the message |
| `FAILED` | Send attempt failed |
| `OPENED` | Recipient opened the email |
| `CLICKED` | Recipient clicked a link |
| `COMPLAINED` | Recipient marked as spam |
| `UNSUBSCRIBED` | Recipient unsubscribed |
| `UNKNOWN` | Event type could not be determined |

### SES Webhook Setup

SES delivers events via SNS. Configure your SNS subscription to POST to:

```
https://your-domain.com/webhooks/mail/ses
```

## Resources

### AWS SES:
- [SES Configuration Sets](https://docs.aws.amazon.com/ses/latest/dg/using-configuration-sets.html)
- [SES Event Publishing](https://docs.aws.amazon.com/ses/latest/dg/monitor-using-event-publishing.html)
- [SES Event Types](https://docs.aws.amazon.com/ses/latest/dg/event-publishing-retrieving-sns-contents.html)
