# `PhoenixKit.Modules.Emails.Event`
[🔗](https://github.com/BeamLabEU/phoenix_kit_emails/blob/0.4.2/lib/phoenix_kit/modules/emails/event.ex#L1)

Email event schema for managing delivery events in PhoenixKit.

This schema records events that occur after email sending, such as delivery,
bounce, complaint, open, and click events. These events are typically received
from email providers like AWS SES through webhooks.

## Schema Fields

- `email_log_uuid`: Foreign key to the associated email log
- `event_type`: Type of event (send, delivery, bounce, complaint, open, click)
- `event_data`: JSONB map containing event-specific data from the provider
- `occurred_at`: Timestamp when the event occurred
- `ip_address`: IP address of the recipient (for open/click events)
- `user_agent`: User agent string (for open/click events)
- `geo_location`: JSONB map with geographic data (country, region, city)
- `link_url`: URL that was clicked (for click events)
- `bounce_type`: Type of bounce (hard, soft, for bounce events)
- `complaint_type`: Type of complaint (abuse, auth-failure, fraud, etc.)

## Event Types

- **send**: Email was successfully sent to the provider
- **delivery**: Email was successfully delivered to recipient's inbox
- **bounce**: Email bounced (permanent or temporary failure)
- **complaint**: Recipient marked email as spam
- **open**: Recipient opened the email (AWS SES tracking)
- **click**: Recipient clicked a link in the email

## Associations

- `email_log`: Belongs to the EmailLog that this event is associated with

## Usage Examples

    # Create a delivery event
    {:ok, event} = PhoenixKit.Modules.Emails.Event.create_event(%{
      email_log_uuid: log.uuid,
      event_type: "delivery",
      event_data: %{
        timestamp: "2024-01-15T10:30:00.000Z",
        smtp_response: "250 OK"
      }
    })

    # Create an open event with managing data
    {:ok, event} = PhoenixKit.Modules.Emails.Event.create_event(%{
      email_log_uuid: log.uuid,
      event_type: "open",
      ip_address: "192.168.1.1",
      user_agent: "Mozilla/5.0...",
      geo_location: %{country: "US", region: "CA", city: "San Francisco"}
    })

    # Get all events for an email
    events = PhoenixKit.Modules.Emails.Event.for_email_log(email_log_uuid)

# `change_event`

Returns an `%Ecto.Changeset{}` for managing email event changes.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.change_event(event)
    %Ecto.Changeset{data: %PhoenixKit.Modules.Emails.Event{}}

# `changeset`

Creates a changeset for email event creation and updates.

Validates required fields and ensures data consistency.
Automatically sets occurred_at on new records if not provided.

# `create_bounce_event`

Creates a bounce event with bounce details.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_bounce_event(email_log_uuid, "hard", "No such user")
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `create_click_event`

Creates a click event with link and managing data.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_click_event(email_log_uuid, "https://example.com/link", "192.168.1.1")
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `create_complaint_event`

Creates a complaint event with complaint details.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_complaint_event(email_log_uuid, "abuse")
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `create_event`

Creates an email event.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_event(%{
      email_log_uuid: log.uuid,
      event_type: "delivery"
    })
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

    iex> PhoenixKit.Modules.Emails.Event.create_event(%{event_type: "invalid"})
    {:error, %Ecto.Changeset{}}

# `create_from_ses_webhook`

Creates a delivery event from AWS SES webhook data.

## Examples

    iex> data = %{
      "eventType" => "delivery",
      "mail" => %{"messageId" => "abc123"},
      "delivery" => %{"timestamp" => "2024-01-15T10:30:00.000Z"}
    }
    iex> PhoenixKit.Modules.Emails.Event.create_from_ses_webhook(log, data)
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `create_open_event`

Creates an open event with managing data.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_open_event(email_log_uuid, "192.168.1.1", "Mozilla/5.0...")
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `create_queued_event`

Creates a queued event when email is queued for sending.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_queued_event(email_log_uuid)
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `create_send_event`

Creates a send event when email is successfully sent to provider.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.create_send_event(email_log_uuid)
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `delete_event`

Deletes an email event.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.delete_event(event)
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

# `event_exists?`

Checks if an event already exists for a specific email log and type.

Returns true if an event of the given type already exists for the email log,
false otherwise. This is used to prevent duplicate event creation.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.event_exists?(email_log_uuid, "delivery")
    true

    iex> PhoenixKit.Modules.Emails.Event.event_exists?(email_log_uuid, "open")
    false

# `event_exists_at?`

Returns true if an event of the given type AND `occurred_at` already exists for
the email log.

Used to dedup multi-occurrence events (open/click), where the same engagement
can legitimately recur at different times — so we key on the timestamp and only
treat an at-least-once SQS redelivery of the SAME (type, occurred_at) as a
duplicate. The DB unique index on (email_log_uuid, event_type, occurred_at)
enforces this atomically; this is the cheap racy pre-check.

# `for_email_log`

Gets all events for a specific email log.

Returns events ordered by occurred_at (most recent first).

## Examples

    iex> PhoenixKit.Modules.Emails.Event.for_email_log(email_log_uuid)
    [%PhoenixKit.Modules.Emails.Event{}, ...]

# `for_email_log_by_type`

Gets events of a specific type for an email log.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.for_email_log_by_type(email_log_uuid, "open")
    [%PhoenixKit.Modules.Emails.Event{}, ...]

# `for_period_by_type`

Gets events of a specific type within a time range.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.for_period_by_type(start_date, end_date, "click")
    [%PhoenixKit.Modules.Emails.Event{}, ...]

# `get_event`

Gets a single email event by ID or UUID.

Accepts integer ID, UUID string, or string-formatted integer.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.get_event(123)
    %PhoenixKit.Modules.Emails.Event{}

    iex> PhoenixKit.Modules.Emails.Event.get_event("550e8400-e29b-41d4-a716-446655440000")
    %PhoenixKit.Modules.Emails.Event{}

    iex> PhoenixKit.Modules.Emails.Event.get_event(999)
    nil

# `get_event!`

Same as `get_event/1`, but raises `Ecto.NoResultsError` if not found.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.get_event!(123)
    %PhoenixKit.Modules.Emails.Event{}

    iex> PhoenixKit.Modules.Emails.Event.get_event!(999)
    ** (Ecto.NoResultsError)

# `get_event_stats`

Gets event statistics for a time period.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.get_event_stats(start_date, end_date)
    %{delivery: 1450, bounce: 30, open: 800, click: 200, complaint: 5}

# `get_geo_distribution`

Gets geographic distribution of events.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.get_geo_distribution("open", start_date, end_date)
    %{"US" => 500, "CA" => 200, "UK" => 150}

# `get_latest_event_by_type`

Gets the most recent event of a specific type for an email log.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.get_latest_event_by_type(email_log_uuid, "open")
    %PhoenixKit.Modules.Emails.Event{}

# `get_top_clicked_links`

Gets the most clicked links for a time period.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.get_top_clicked_links(start_date, end_date, 10)
    [%{url: "https://example.com/product", clicks: 150}, ...]

# `has_event_type?`

Checks if an event of a specific type exists for an email log.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.has_event_type?(email_log_uuid, "open")
    true

# `update_event`

Updates an email event.

## Examples

    iex> PhoenixKit.Modules.Emails.Event.update_event(event, %{event_data: %{updated: true}})
    {:ok, %PhoenixKit.Modules.Emails.Event{}}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
