PhoenixKit.Modules.Emails.AwsIntegrations (phoenix_kit_emails v0.4.0)

Copy Markdown View Source

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

active_integration_uuids()

@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()

@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(integration_uuid)

@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"}}