# Contact form processing

Contact form submissions are stored first and processed asynchronously by:

```bash
python manage.py run_contact_submission_worker
```

The `scheduler` application role runs this worker and the newsletter scheduler in independent loops. A database lease allows only one spam-detection request at a time across scheduler replicas, while newsletter and SMTP work continue independently.

## Environment variables

Required in production:

```text
CONTACT_SPAM_DETECTION_ENABLED=true
CONTACT_SPAM_DETECTION_URL=https://spamd.innovedus.com/classify
CONTACT_SPAM_DETECTION_API_KEY=replace-me
```

Optional tuning:

```text
CONTACT_SPAM_DETECTION_TIMEOUT_SECONDS=180
CONTACT_SPAM_DETECTION_RETRY_DELAY_SECONDS=300
CONTACT_SPAM_DETECTION_MAX_ATTEMPTS=3
CONTACT_FORM_WORKER_BATCH_SIZE=20
CONTACT_FORM_WORKER_MAX_RUNTIME_SECONDS=600
CONTACT_FORM_WORKER_LEASE_SECONDS=600
CONTACT_FORM_MAIL_RETRY_DELAY_SECONDS=300
CONTACT_FORM_MAIL_MAX_ATTEMPTS=3
CONTACT_SCHEDULER_INTERVAL_SECONDS=60
NEWSLETTER_SCHEDULER_INTERVAL_SECONDS=60
```

When spam detection is disabled or its URL/key is missing, queued submissions stay in the database and no contact email is sent. A service error opens a database-backed cooldown until the configured retry time, so later scheduler runs do not repeatedly call an AI box that is restarting.

Rate limit count/window and the submitter-copy switch are managed in Wagtail under Contact Form Settings. The default is three submissions per ten minutes per IP, and submitter copies are disabled by default.

The application must only be publicly reachable through an Application Load Balancer whose `routing.http.xff_header_processing.mode` is `append` (the AWS default). The client IP is read from the rightmost valid `X-Forwarded-For` entry, with `REMOTE_ADDR` used only when that header is absent.
