# Outreach Operations

Outreach operations handle the sending pipeline: policy validation, SMTP delivery, idempotency, suppression, and audit logging.

## Send Pipeline

Every outbound email goes through this pipeline:

```mermaid
flowchart TD
    A[Send Request] --> B[Authenticate User]
    B --> C[Resolve Lead Email from DB]
    C --> D[Policy Validation]
    D -->|Approved| E[Create Outreach Attempt Record]
    D -->|Blocked| F[Record Audit Log + Return 403]
    E --> G[Send via SMTP with TLS]
    G -->|Success| H[Increment Counters]
    G -->|Success| I[Mark Idempotency Key]
    G -->|Success| J[Update Lead Status to Contacted]
    G -->|Failure| K[Return 500 with Generic Error]
    H --> L[Return 200 with Attempt Details]
    I --> L
    J --> L
    
    style D fill:#fff3e0
    style G fill:#e3f2fd
    style F fill:#ffebee
```

!!! warning "Counter timing"
    Counters and idempotency keys are marked **only after successful SMTP delivery**, never before. This prevents false cap consumption on failed sends.

## Policy Validation

Before every send, the system validates:

| Check | Rule | On Failure |
|---|---|---|
| **Daily user cap** | Max 100 emails/user/day | Block + audit |
| **Daily domain cap** | Max 20 emails/domain/day | Block + audit |
| **Suppression list** | Recipient not suppressed | Block + audit |
| **Idempotency** | No duplicate `(sender, recipient, subject)` in 24h | Block + audit |
| **Legal basis** | EU domains → "consent", others → "legitimate_interest" | Auto-assign |

**API:** `POST /api/v1/backlink-outreach/policy/validate`

```json
{
  "recipient_email": "editor@example.com",
  "sender_email": "outreach@yourdomain.com",
  "subject": "Guest Post: AI Marketing Trends"
}
```

**Response:**

```json
{
  "allowed": true,
  "reason": "All checks passed",
  "legal_basis": "legitimate_interest",
  "daily_user_count": 23,
  "daily_user_limit": 100,
  "daily_domain_count": 5,
  "daily_domain_limit": 20,
  "region": "US"
}
```

### Region-Aware Legal Basis

The system infers the recipient's region from their email domain's TLD:

| TLDs | Region | Legal Basis |
|---|---|---|
| `.de`, `.fr`, `.it`, `.es`, `.nl`, `.pl`, `.se`, `.at`, `.be`, `.ch`, `.pt`, `.ie`, `.dk`, `.fi`, `.no`, `.cz`, `.gr`, `.hu`, `.ro`, `.bg`, `.hr`, `.sk`, `.si`, `.lt`, `.lv`, `.ee` | EU | `consent` |
| `.co.uk`, `.uk` | UK | `consent` |
| `.ca` | CA | `consent` |
| `.com.au`, `.co.nz` | AU/NZ | `consent` |
| All others | — | `legitimate_interest` |

!!! note "GDPR compliance"
    EU, UK, CA, and AU domain leads always use `consent` as the legal basis. This means you should have obtained some form of consent before reaching out. For other regions, `legitimate_interest` is applied automatically.

## Suppression List

Recipients on the suppression list are blocked from receiving emails.

### Adding to Suppression

**API:** `POST /api/v1/backlink-outreach/suppression`

```json
{
  "email": "unsubscribed@example.com",
  "reason": "User requested unsubscribe"
}
```

### Listing Suppressed Recipients

**API:** `GET /api/v1/backlink-outreach/suppression`

### Auto-Suppression

Recipients are automatically added to the suppression list when:
- They reply with "not interested" language.
- They explicitly request to be removed.
- An email to their address hard-bounces.

## Idempotency

The system prevents duplicate sends using idempotency keys derived from `(sender_email, recipient_email, subject)`.

- Keys are valid for 24 hours.
- After successful SMTP delivery, the key is marked as used.
- Attempting to send the same `(sender, recipient, subject)` within 24h returns a policy block.

## SMTP Configuration

Emails are sent via SMTP with mandatory TLS:

| Setting | Env Var | Default |
|---|---|---|
| SMTP host | `SMTP_HOST` | — (required) |
| SMTP port | `SMTP_PORT` | `587` |
| SMTP username | `SMTP_USER` | — (required) |
| SMTP password | `SMTP_PASS` | — (required) |
| TLS verification | `SMTP_VERIFY_TLS` | `true` |
| Send timeout | `SMTP_SEND_TIMEOUT` | `30` seconds |
| From email | `SMTP_FROM_EMAIL` | — (required) |

!!! warning "TLS certificate verification"
    By default, `SMTP_VERIFY_TLS=true` validates the SMTP server's TLS certificate. Set to `false` only for local development with self-signed certs. **Never disable in production.**

### SMTP Connection Flow

1. Connect to SMTP host on configured port.
2. Send `EHLO` greeting.
3. Upgrade to TLS with `STARTTLS`.
4. Send `EHLO` again (required by RFC 3207 after STARTTLS).
5. Authenticate with username/password.
6. Send the email with a configurable timeout.
7. Quit the connection cleanly.

## Audit Logging

Every policy check is recorded in the audit log:

| Field | Description |
|---|---|
| `user_id` | Authenticated user who initiated the send. |
| `lead_email` | Intended recipient. |
| `sender_email` | Sending address. |
| `subject` | Email subject line. |
| `policy_result` | `approved` or `blocked`. |
| `reason` | Human-readable explanation. |
| `legal_basis` | `consent` or `legitimate_interest`. |
| `timestamp` | When the check occurred. |

---

*Next: [Reply Inbox](reply-inbox.md) — IMAP monitoring and auto-classification.*
