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.
Summary
Functions
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.
{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.
Resolves the decrypted AWS credentials for one aws_ses integration as
%{access_key: ..., secret_key: ..., region: ...}.
Functions
@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"]
{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"}]
@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"}}