{"id":50886063,"url":"https://github.com/hops-ops/aws-smtp-sender","last_synced_at":"2026-06-15T17:02:23.040Z","repository":{"id":359267882,"uuid":"1244128321","full_name":"hops-ops/aws-smtp-sender","owner":"hops-ops","description":"Crossplane configuration for SES-backed outbound SMTP sender credentials","archived":false,"fork":false,"pushed_at":"2026-05-21T04:51:16.000Z","size":27,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T11:28:14.739Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"KCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hops-ops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-20T01:47:29.000Z","updated_at":"2026-05-21T04:51:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hops-ops/aws-smtp-sender","commit_stats":null,"previous_names":["hops-ops/aws-smtp-sender"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/hops-ops/aws-smtp-sender","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-smtp-sender","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-smtp-sender/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-smtp-sender/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-smtp-sender/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hops-ops","download_url":"https://codeload.github.com/hops-ops/aws-smtp-sender/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-smtp-sender/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34372130,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-15T17:02:22.149Z","updated_at":"2026-06-15T17:02:23.034Z","avatar_url":"https://github.com/hops-ops.png","language":"KCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AWS SMTP Sender\n\n`aws-smtp-sender` provisions SES-backed outbound SMTP for a sender domain and publishes the SMTP password to AWS Secrets Manager.\n\n## Why SMTPSender?\n\nWithout SMTPSender:\n\n- Every app has to solve SES identity setup, DKIM tokens, IAM credentials, and SMTP password storage independently.\n- SMTP credentials are easy to leak because the IAM secret key is not the SES SMTP password.\n- DKIM setup becomes an operator runbook instead of a GitOps output.\n\nWith SMTPSender:\n\n- SES identity, IAM SMTP user, access key, and Secrets Manager publication are one declarative XR.\n- Non-secret SMTP connection data is exposed in typed status.\n- The secret value stored in AWS Secrets Manager is the SES SMTP password from the AccessKey connection secret key `attribute.ses_smtp_password_v4`.\n- Optional dedicated IP pools and SES configuration sets isolate sender reputation when the extra AWS cost is justified.\n\n## The Journey\n\n### Stage 1: Getting Started\n\nCreate one sender for a domain:\n\n```yaml\napiVersion: aws.hops.ops.com.ai/v1alpha1\nkind: SMTPSender\nmetadata:\n  name: ops\n  namespace: default\nspec:\n  domain: ops.com.ai\n  clusterName: pat-local\n  region: us-east-2\n  managementPolicies:\n    - \"*\"\n```\n\nThis creates an SESv2 `EmailIdentity`, IAM `User`, IAM `Policy`, IAM `UserPolicyAttachment`, IAM `AccessKey`, Secrets Manager `Secret`, and `SecretVersion`.\n\n### Stage 2: Growing\n\nCustomize the IAM user, ProviderConfig, tags, and secret path:\n\n```yaml\nspec:\n  domain: ops.com.ai\n  clusterName: pat-local\n  region: us-east-2\n  providerConfigRef:\n    name: aws-prod\n  iam:\n    userName: ops-smtp\n  pushCredentials:\n    path: push/pat-local/ops-smtp\n  tags:\n    Team: platform\n```\n\nMultiple `SMTPSender` resources can run in the same AWS account when they\nuse unique SES identities, IAM user names, and Secrets Manager paths. They\nshare the account and Region SES sending quota.\n\n### Stage 3: Dedicated IP Reputation (Opt-in)\n\nDedicated IP pools are disabled by default because they are cost-bearing AWS resources. Enable them only for senders that need isolated reputation, such as marketing or high-volume transactional mail:\n\n```yaml\nspec:\n  dedicatedIpPool:\n    enabled: true\n    scalingMode: MANAGED\n  configurationSet:\n    deliveryOptions:\n      tlsPolicy: REQUIRE\n      maxDeliverySeconds: 50400\n    reputationMetricsEnabled: true\n    sendingEnabled: true\n```\n\nThis creates an SESv2 `DedicatedIPPool` and a `ConfigurationSet` whose `deliveryOptions.sendingPoolName` points at the pool. SMTP consumers must send with the configuration set, for example via the `X-SES-CONFIGURATION-SET` header, for mail to use the dedicated pool.\n\n### Stage 4: Enterprise Scale\n\nSet `accountId` to scope the SES send policy ARN to a specific account and apply an IAM permissions boundary:\n\n```yaml\nspec:\n  accountId: \"034489662075\"\n  iam:\n    permissionsBoundaryArn: arn:aws:iam::034489662075:policy/platform-boundary\n```\n\nIf `accountId` is omitted, the policy uses a wildcard account segment while still scoping by region and identity domain.\n\n### Stage 5: Import Existing\n\nUse external-name fields and orphaning management policies to observe existing IAM resources without deleting them:\n\n```yaml\nspec:\n  managementPolicies:\n    - Create\n    - Observe\n    - Update\n    - LateInitialize\n  iam:\n    userExternalName: existing-smtp-user\n    policyExternalName: existing-smtp-policy\n```\n\n## Using SMTPSender\n\nConsumers combine public status fields with the password stored in AWS Secrets Manager:\n\n- `status.smtp.host`\n- `status.smtp.port`\n- `status.smtp.username`\n- `status.smtp.awsSecretsManagerPath`\n\nThe DKIM publisher reads `status.dkim.tokens` and creates three CNAME records:\n\n```text\n\u003ctoken\u003e._domainkey.\u003cdomain\u003e CNAME \u003ctoken\u003e.dkim.amazonses.com\n```\n\n## Status\n\n- `status.ready`: all enabled AWS resources are ready.\n- `status.smtp.*`: SMTP host, port, username, and AWS Secrets Manager password path.\n- `status.dkim.*`: SES verification status and DKIM tokens for DNS publication.\n- `status.iam.*`: IAM user and policy ARNs.\n- `status.ses.identityArn`: SES identity ARN.\n- `status.ses.dedicatedIpPool.*`: dedicated IP pool ARN, name, and scaling mode when enabled.\n- `status.ses.configurationSet.*`: SES configuration set ARN and name when enabled.\n- `status.secret.arn`: Secrets Manager secret ARN when credential push is enabled.\n\n## Composed Resources\n\n- `sesv2.aws.m.upbound.io/EmailIdentity`: sender domain identity and DKIM tokens.\n- `sesv2.aws.m.upbound.io/DedicatedIPPool`: optional cost-bearing dedicated IP pool when `spec.dedicatedIpPool.enabled=true`.\n- `sesv2.aws.m.upbound.io/ConfigurationSet`: optional configuration set that selects the dedicated IP pool.\n- `iam.aws.m.upbound.io/User`: SMTP IAM user.\n- `iam.aws.m.upbound.io/Policy`: `ses:SendRawEmail` permission scoped to the identity ARN.\n- `iam.aws.m.upbound.io/UserPolicyAttachment`: attaches the send policy to the SMTP user.\n- `iam.aws.m.upbound.io/AccessKey`: creates SMTP username and connection secret.\n- `secretsmanager.aws.m.upbound.io/Secret`: AWS Secrets Manager path for the SMTP password.\n- `secretsmanager.aws.m.upbound.io/SecretVersion`: writes `attribute.ses_smtp_password_v4` into the secret.\n\n## Development\n\n```bash\nmake render:all\nmake validate:all\nmake test\nmake e2e\n```\n\nThe E2E test creates a timestamped sender identity under `ops.com.ai`, waits\nfor the XR to become ready, then deletes it. This uses full lifecycle\nmanagement because SMTP senders are not singleton account resources.\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhops-ops%2Faws-smtp-sender","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhops-ops%2Faws-smtp-sender","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhops-ops%2Faws-smtp-sender/lists"}