# briteverify-email-validator

## Overview
An AWS Lambda handler (invoked on a schedule) that manages bulk email validation through BriteVerify and stores results in Snowflake. It does two things on each run:

- **Process existing validation lists** - Checks unprocessed list IDs in Snowflake, fetches completed results from BriteVerify, and stores them.
- **Create a new validation list** - Pulls unverified emails from Snowflake, creates a new list in BriteVerify, and records the list state.

## Getting Started

### Requirements
Minimum requirements and recommended tooling:

- Python: 3.13
- UV (astral `uv` tool) for environment and task running (see `pyproject.toml` `tool.uv` configuration)
- Docker and Docker Compose (used for CI targets)
- Make (for provided Makefile targets)

Developer tooling (used in CI / recommended):

- `pytest` (unit tests)
- `ruff` and `pyright` (linting / type checks)

### Installation
```bash
# Install uv (if not installed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install project dependencies
make env
```

### Configuration
For local development, copy the example configuration:

```bash
cp .env.example .env
```

Then update `.env` with your settings. Key variables (see [app/config.py](app/config.py) and [.env.example](.env.example)):

- `ENVIRONMENT` - Environment (dev, qa, prod)
- `BRITEVERIFY_API_KEY` - BriteVerify API key
- `VALIDATION_START_DATE` - Only emails with `first_event_at` on or after this ISO date are eligible for validation (default: `2026-04-01`)
- `SNOWFLAKE_ACCOUNT`, `SNOWFLAKE_DATABASE`, `SNOWFLAKE_SCHEMA`, `SNOWFLAKE_WAREHOUSE`, `SNOWFLAKE_ROLE`, `SNOWFLAKE_USER` - Snowflake connection settings
- `SNOWFLAKE_PRIVATE_KEY_PATH`, `SNOWFLAKE_KEY_PASSPHRASE` - Snowflake authentication
- `SENTRY_DSN` - Sentry error tracking (required for QA/PROD)
- `APP_DEBUG` - Debug mode (default: false)

## Testing

### Unit tests
Run the project's unit tests with:

```bash
make test
```

## Linting and formatting
Run the linter with:

```bash
make lint
```

Run the code formatter with:

```bash
make fmt
```

## Project Structure

- `app/` - Main application code
  - `main.py` - Lambda handler entry point
  - `handler.py` - Core workflow (process lists, create new list)
  - `config.py` - Configuration and settings
  - `container.py` - Dependency injection setup
  - `adapters/briteverify/` - BriteVerify bulk API client and models
  - `adapters/db/` - Database access and repositories
  - `sql/` - SQL templates used by repositories
- `tests/` - Test suite
  - `unit/` - Unit tests

## Processing Flow

1. Fetch unprocessed list IDs from Snowflake.
2. For each list:
   - If complete, fetch results and store them in Snowflake.
   - If not complete, update the list state and skip.
3. Fetch unverified emails created on or after `VALIDATION_START_DATE`, up to the available BriteVerify credits and configured list limit.
4. Create a new BriteVerify list and store it in Snowflake.
