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

Shared "which AWS SES account(s) are actually active" resolution, used by
everything that needs to reach AWS on behalf of the currently-configured
sender(s): `SQSPollingJob` (the background poll), the per-account tracking
settings in the "Amazon SES & SQS" section, and the "Delivery Event
Tracking" panel's per-account opt-out list.

"Active" means an *enabled* `PhoenixKit.Email.SendProfile` pointed at an
`"aws_ses"` integration — the same sender-aware definition
`BrevoIntegrations` uses for Brevo, and the multi-account counterpart of
the single `emails_aws_integration_uuid` setting the legacy path still
reads (see `PhoenixKit.Modules.Emails.get_aws_access_key/0`).

Deliberately a mirror of `BrevoIntegrations` rather than a shared generic:
the credential SHAPE differs (Brevo has one `api_key`, SES needs
access/secret/region as a triple), and the two providers' notions of
"reachable" have already drifted once. Keeping them parallel-but-separate
is what lets each grow its own gate without a conditional in the middle.

# `active_integration_uuids`

```elixir
@spec active_integration_uuids() :: [String.t()]
```

Every distinct `integration_uuid` referenced by an enabled `aws_ses`
SendProfile. Multiple profiles can share one integration/AWS account —
deduplicated so callers don't poll the same queue twice per cycle.

## Examples

    iex> PhoenixKit.Modules.Emails.AwsIntegrations.active_integration_uuids()
    ["019fb9ec-0000-7000-8000-000000000000"]

# `active_integrations_with_names`

```elixir
@spec active_integrations_with_names() :: [{String.t(), String.t()}]
```

`{integration_uuid, name}` pairs for every account
`active_integration_uuids/0` would poll — for the settings UI's
per-account list, which needs a human-readable name alongside the uuid it
writes to the tracking/exclusion settings.

## Examples

    iex> PhoenixKit.Modules.Emails.AwsIntegrations.active_integrations_with_names()
    [{"019fb9ec-0000-7000-8000-000000000000", "AWS SES .eu"}]

# `resolve_credentials`

```elixir
@spec resolve_credentials(String.t()) ::
  {:ok,
   %{access_key: String.t(), secret_key: String.t(), region: String.t() | nil}}
  | {:error, :missing_credentials}
```

Resolves the decrypted AWS credentials for one `aws_ses` integration as
`%{access_key: ..., secret_key: ..., region: ...}`.

`region` is `nil` when the connection was saved without one — deliberately
NOT defaulted to `"us-east-1"`. That default was built on a wrong premise:
`ex_aws_sqs` puts the QueueUrl in the request BODY and derives the host from
the CONFIGURED region, so a guessed region does not merely mislabel the
request, it sends it to the wrong endpoint and every receive fails. Callers
decide what to do with `nil`: the poller reads the region off the queue URL,
which always knows; the one-click infrastructure setup refuses, because
creating a topic, a queue, a DLQ and a configuration set in a guessed region
is a mess someone has to clean up by hand in a console.

A MISSING key or secret is a hard `{:error, :missing_credentials}` — signing
with a blank key would fail per-request, once per poll cycle, with an opaque
AWS error instead of one clear log line here.

## Examples

    iex> PhoenixKit.Modules.Emails.AwsIntegrations.resolve_credentials("uuid")
    {:ok, %{access_key: "AKIA...", secret_key: "...", region: "eu-north-1"}}

---

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