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

Rate limiting and spam protection for the email system.

Provides multiple layers of protection against abuse, spam, and suspicious email patterns:

- **Per-recipient limits** - Prevent spam to individual email addresses
- **Per-sender limits** - Control email volume from specific senders
- **Global system limits** - Overall system protection
- **User-specific limits** - Temporary reduced limits for flagged users
- **Automatic blocklists** - Dynamic blocking of suspicious patterns
- **Pattern detection** - ML-style spam pattern recognition
- **User monitoring** - Event tracking for suspicious behavior

## Settings Integration

All rate limiting settings are stored in phoenix_kit_settings:

- `email_rate_limit_per_recipient` - Max emails per recipient per hour (default: 100)
- `email_rate_limit_global` - Global max emails per hour (default: 10_000)
- `email_blocklist_enabled` - Enable automatic blocklisting (default: true)

User-specific settings (stored as JSON):
- `user_rate_limits_<user_uuid>` - Temporary reduced limits for specific users
- `user_monitoring_<user_uuid>` - Event tracking log for user behavior

## Usage Examples

    # Check if sending is allowed
    case PhoenixKit.Modules.Emails.RateLimiter.check_limits(email) do
      :ok ->
        # Send email

      {:blocked, :recipient_limit} ->
        # Handle recipient rate limit

      {:blocked, :global_limit} ->
        # Handle global rate limit

      {:blocked, :blocklist} ->
        # Handle blocklisted recipient
    end

    # Flag suspicious user activity
    PhoenixKit.Modules.Emails.RateLimiter.flag_suspicious_activity(user_uuid, "high_bounce_rate")
    # => :flagged (user gets reduced limits for 24 hours)

    # Check user's current limit status
    status = PhoenixKit.Modules.Emails.RateLimiter.get_user_limit_status(user_uuid)
    # => %{has_custom_limits: true, active_recipient_limit: 10, ...}

    # Clear user's custom limits
    PhoenixKit.Modules.Emails.RateLimiter.clear_user_rate_limits(user_uuid)
    # => :ok

    # Add suspicious email to blocklist
    PhoenixKit.Modules.Emails.RateLimiter.add_to_blocklist(
      "spam@example.com",
      "suspicious_pattern",
      expires_at: DateTime.add(UtilsDate.utc_now(), 86_400)
    )

    # Check current rate limit status
    status = PhoenixKit.Modules.Emails.RateLimiter.get_rate_limit_status()
    # => %{recipient_count: 45, global_count: 2341, blocked_count: 12}

## Rate Limiting Strategy

Uses a sliding window approach with Redis-like atomic operations in PostgreSQL:

1. **Sliding Window**: Tracks counts over rolling time periods
2. **Efficient Storage**: Uses single table with automatic cleanup
3. **Atomic Operations**: Prevents race conditions with database locks
4. **Memory Efficient**: Automatically expires old tracking data
5. **User-Specific Limits**: JSON settings for temporary user restrictions

## User Behavior Management

- **Reduced Limits**: Automatically reduce limits for users with high bounce rates
- **Email Blocking**: Block user emails for serious violations (spam complaints)
- **Activity Monitoring**: Track suspicious patterns for future analysis
- **Automatic Expiration**: Limits and blocks expire after configured periods
- **Manual Override**: Admin can clear user restrictions via API

## Automatic Blocklist Features

- **Pattern Detection**: Identifies bulk spam patterns
- **Bounce Rate Monitoring**: Blocks high-bounce senders
- **Complaint Rate Monitoring**: Blocks high-complaint addresses
- **Frequency Analysis**: Detects unusual sending patterns
- **Temporary Blocks**: Automatic expiration of blocks
- **User Integration**: Links blocked emails to user accounts

## Integration Points

Integrates with:
- `PhoenixKit.Modules.Emails` - Main tracking system
- `PhoenixKit.Modules.Emails.EmailInterceptor` - Pre-send filtering
- `PhoenixKit.Settings` - Configuration management
- `PhoenixKit.Users.Auth` - User-based limits and email blocking

# `add_to_blocklist`

Add email address to blocklist.

## Options

- `:reason` - Reason for blocking (string)
- `:expires_at` - When block expires (DateTime, nil for permanent)
- `:user_uuid` - User UUID that triggered the block

## Examples

    # Temporary block for 24 hours
    RateLimiter.add_to_blocklist(
      "spam@example.com",
      "bulk_spam_pattern",
      expires_at: DateTime.add(UtilsDate.utc_now(), 86_400)
    )

    # Permanent block
    RateLimiter.add_to_blocklist("malicious@example.com", "manual_block")

# `check_blocklist`

Check if email address is blocklisted.

## Examples

    iex> RateLimiter.check_blocklist("user@example.com")
    :ok

    iex> RateLimiter.check_blocklist("spam@blocked.com")
    {:blocked, :blocklist}

# `check_global_limit`

Check global system-wide rate limits.

## Examples

    iex> RateLimiter.check_global_limit()
    :ok

# `check_limits`

Check all rate limits for an outgoing email.

Returns `:ok` if email can be sent, or `{:blocked, reason}` if blocked.

## Examples

    iex> RateLimiter.check_limits(%{to: "user@example.com", from: "app@mysite.com"})
    :ok

    iex> RateLimiter.check_limits(%{to: "blocked@spam.com"})
    {:blocked, :blocklist}

# `check_recipient_limit`

Check if recipient email address is within rate limits.

## Examples

    iex> RateLimiter.check_recipient_limit("user@example.com")
    :ok

    iex> RateLimiter.check_recipient_limit("high-volume@example.com")  
    {:blocked, :recipient_limit}

# `check_sender_limit`

Check if sender email address is within rate limits.

## Examples

    iex> RateLimiter.check_sender_limit("app@mysite.com")
    :ok

# `check_user_limits`

Checks if a user has custom rate limits applied.

Returns user's custom limits if they exist and haven't expired,
otherwise returns nil.

## Examples

    iex> RateLimiter.check_user_limits("018e3c4a-1234-5678-abcd-ef1234567890")
    %{
      "recipient_limit" => 10,
      "sender_limit" => 50,
      "reason" => "high_bounce_rate",
      "applied_at" => "2025-01-15T12:00:00Z",
      "expires_at" => "2025-01-16T12:00:00Z"
    }

    iex> RateLimiter.check_user_limits("018e3c4a-5678-1234-abcd-ef1234567890")
    nil

# `clear_user_rate_limits`

Clears custom rate limits for a specific user.

Removes any reduced limits or custom restrictions applied to the user,
returning them to default system limits.

## Examples

    iex> RateLimiter.clear_user_rate_limits(123)
    :ok

## Returns

- `:ok` - Limits cleared successfully

# `count_blocklist`

Count blocked emails with optional filtering.

## Examples

    iex> RateLimiter.count_blocklist()
    42

    iex> RateLimiter.count_blocklist(%{reason: "bounce_limit"})
    15

# `detect_spam_patterns`

Analyze email for suspicious spam patterns.

Returns a list of detected patterns or empty list if clean.

## Examples

    iex> RateLimiter.detect_spam_patterns(email_log)
    []

    iex> RateLimiter.detect_spam_patterns(suspicious_email_log)
    ["high_frequency", "bulk_template"]

# `flag_suspicious_activity`

Flag suspicious activity for a user.

Automatically triggers blocklist or rate limit adjustments based on activity patterns.

## Examples

    iex> RateLimiter.flag_suspicious_activity("018e3c4a-1234-5678-abcd-ef1234567890", "high_bounce_rate")
    :flagged

    iex> RateLimiter.flag_suspicious_activity("018e3c4a-5678-1234-abcd-ef1234567890", "complaint_spam")
    :blocked

# `get_blocklist_stats`

Get blocklist statistics.

Returns a map with statistics about blocked emails.

## Examples

    iex> RateLimiter.get_blocklist_stats()
    %{
      total_blocks: 42,
      active_blocks: 38,
      expired_today: 4,
      by_reason: %{"manual_block" => 10, "bounce_limit" => 28, ...}
    }

# `get_rate_limit_status`

Get current rate limit status across all dimensions.

## Examples

    iex> RateLimiter.get_rate_limit_status()
    %{
      global: %{count: 1250, limit: 10_000, percentage: 12.5},
      recipients: %{active_limits: 5, total_emails: 892},
      senders: %{active_limits: 2, total_emails: 1250},
      blocklist: %{active_blocks: 15, expired_today: 3}
    }

# `get_user_limit_status`

Gets comprehensive rate limit status for a specific user.

Returns a map with user's current limits, monitoring status,
and any active restrictions.

## Examples

    iex> RateLimiter.get_user_limit_status("018e3c4a-1234-5678-abcd-ef1234567890")
    %{
      user_uuid: "018e3c4a-1234-5678-abcd-ef1234567890",
      has_custom_limits: true,
      custom_limits: %{"recipient_limit" => 10, "sender_limit" => 50},
      monitoring: %{"event_count" => 5, "last_event_at" => "..."},
      is_blocked: false,
      default_recipient_limit: 100,
      default_sender_limit: 1000
    }

    iex> RateLimiter.get_user_limit_status("018e3c4a-5678-1234-abcd-ef1234567890")
    %{
      user_uuid: "018e3c4a-5678-1234-abcd-ef1234567890",
      has_custom_limits: false,
      custom_limits: nil,
      monitoring: nil,
      is_blocked: false,
      default_recipient_limit: 100,
      default_sender_limit: 1000
    }

# `get_user_monitoring_events`

Gets monitoring events for a specific user.

Returns the monitoring log with all tracked events for the user,
or nil if no monitoring exists.

## Examples

    iex> RateLimiter.get_user_monitoring_events(123)
    %{
      "events" => [
        %{"event_type" => "bulk_sending", "timestamp" => "...", "metadata" => %{...}},
        %{"event_type" => "high_bounce_rate", "timestamp" => "...", "metadata" => %{...}}
      ],
      "event_count" => 2,
      "first_event_at" => "2025-01-15T12:00:00Z",
      "last_event_at" => "2025-01-15T18:00:00Z"
    }

    iex> RateLimiter.get_user_monitoring_events(999)
    nil

# `is_blocked?`

Check if email address is currently blocked.

## Examples

    iex> RateLimiter.is_blocked?("user@example.com")
    false

    iex> RateLimiter.is_blocked?("blocked@spam.com")
    true

# `list_blocklist`

List all blocked emails with optional filtering.

## Options

- `:search` - Search term for email address
- `:reason` - Filter by block reason
- `:include_expired` - Include expired blocks (default: false)
- `:limit` - Limit number of results
- `:offset` - Offset for pagination
- `:order_by` - Order field (:email, :inserted_at, :expires_at)
- `:order_dir` - Order direction (:asc, :desc)

## Examples

    iex> RateLimiter.list_blocklist()
    [%EmailBlocklist{}, ...]

    iex> RateLimiter.list_blocklist(%{reason: "manual_block", limit: 10})
    [%EmailBlocklist{}, ...]

# `remove_from_blocklist`

Remove email address from blocklist.

## Examples

    iex> RateLimiter.remove_from_blocklist("user@example.com")
    :ok

---

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