Repository navigation
Retire Resend and require Amazon SES - #684
Conversation
There was a problem hiding this comment.
Caution
The cleanup sequence can disable passwordless sign-in by redeploying the old API build after removing the settings it still requires. Release the SES-only binaries before destructive configuration cleanup, or explicitly prevent old-build redeploys during the transition.
Reviewed changes Reviewed the SES-only registration, startup validation, removed transport and tests, Terraform environment/DNS cleanup, and release instructions.
- SES registration:
IEmailServicenow always resolves toSesEmailService, with nine required settings checked outside build-time OpenAPI generation. - Transport retirement: Removes the Resend implementation, options, appsettings blocks, vendor-specific tests, and obsolete suppression while retaining shared composition and SES event handling.
- Infrastructure cleanup: Removes both environments' provider variables and vendor settings plus six legacy DNS records, preserving SES resources and environment-specific routing.
- Validation: All 46 selected email/startup/SES unit tests and 34 infrastructure regression tests passed in this review.
gpt-6.1-sol | 𝕏
An old build falls back to Resend when Email__Provider is absent, and Render's Save and deploy redeploys the existing build, so the cleanup now runs only after both environments run and verify the SES-only build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes Reviewed commit 11e27c55 since the prior Pullfrog review, with the full PR diff and resolved discussion as context.
- Moved cleanup after release: Required verified SES-only releases in both environments before removing legacy email settings, service overrides, SSM credentials, or DNS records.
- Aligned operator instructions: Updated
infra/README.mdand the PR manual steps to prohibit email configuration changes and old-build deploys until both releases pass health and SES delivery verification.
The prior rollout concern is addressed. Tests were not rerun because the incremental change affects documentation only.
gpt-6.1-sol | 𝕏
|
* chore(infra): delete the GitHub staging keepalive now that the Cloudflare pinger is proven (#682) The orbit-staging-pinger Worker ran every five minutes through a full observation hour with all seven independent probes under two seconds, so the scheduled GitHub workflow is redundant. Refs thomasluizon/orbit-tickets#1009 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit c04451f) * fix: control reminder scheduler test clocks (#1018) (#683) (cherry picked from commit b2af4c8) * Retire Resend and require Amazon SES (#684) * Remove retired email transport and require SES at startup * Retire obsolete email configuration and DNS declarations * Configure SES in infrastructure startup test fixtures * docs(infra): release the SES-only build before retiring email settings An old build falls back to Resend when Email__Provider is absent, and Render's Save and deploy redeploys the existing build, so the cleanup now runs only after both environments run and verify the SES-only build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 310a552) # Conflicts: # tests/Orbit.Infrastructure.Tests/Services/ResendEmailServiceTests.cs --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>




A missing email provider setting previously selected Resend even though both APIs use SES. The API now registers only
SesEmailServiceand rejects missing or blank SES settings during startup.The change removes the provider implementation, options and four test files; replaces the registration tests in
EmailProviderConfigurationTests.cs; and updates the complete infrastructure fixtures inStartupConfigValidationTests.cs. Registration and validation stay inServiceCollectionExtensions.Infrastructure.cs, using the existing required-setting guard and build-time OpenAPI detection.appsettings.jsondrops both obsolete blocks, and the suppression allowlist drops the removed URL suppression.infra/configuration.tf,variables.tfandexample.tfvarsdrop the switch and vendor environment values and SSM data-source references.cloudflare.tfandcheck-dns-cutover.shretire the six legacy email DNS declarations. The repository and infrastructure documentation describe SES and the remaining release operations. Keeping the existing SES transport and configuration preserves message composition, retries and environment-specific event routing.Closes thomasluizon/orbit-tickets#943. Carry into
redesign/mainthrough the standing thomasluizon/orbit-tickets#746 sync after merge.Assumptions
BuildTimeDocumentGeneration.IsActiveexception because it has no infrastructure; rejected requiring live credentials for builds. Runtime registration still fails without required SES settings.redesign/main; rejected opening a second PR or merging either branch in this worker.Test evidence
dotnet test tests/Orbit.Infrastructure.Tests --filter FullyQualifiedName~EmailProviderConfigurationTestspassed all 4 existing cases with the fallback present.EmailAlwaysUsesSesWithoutProviderSettingfoundResendEmailService;MissingSesSettingFailsDuringRegistration,BlankSesCredentialsFailDuringRegistrationandMissingSesSectionFailsDuringRegistrationfound that no exception was thrown.dotnet test tests/Orbit.Infrastructure.Tests --no-build --filter 'FullyQualifiedName~EmailProviderConfigurationTests|FullyQualifiedName~SesEmailServiceTests|FullyQualifiedName~SesEventProcessorTests|FullyQualifiedName~SnsMessageVerifierTests'passed all 33 cases.dotnet test tests/Orbit.Infrastructure.Tests --filter 'FullyQualifiedName~StartupConfigValidationTests|FullyQualifiedName~EmailProviderConfigurationTests'passed all 26 cases.dotnet build Orbit.slnxcompleted with 0 errors. The finaldotnet testpassed all 7,050 tests: 32 analyzer, 640 domain, 3,763 application and 2,615 infrastructure tests, with no failures or skips.node --test infra/check-web-plan.test.mjs infra/ses-isolation.test.mjs infra/google-play-isolation.test.mjs infra/staging-pinger.test.mjspassed all 34 tests. Terraform formatting and validation, shell syntax, suppression and commit-hook checks passed. Architecture maps were regenerated and remain ignored as required.git grep -i resendcontains only ordinary send-again terms, OAuth button code and incidental identifier matches; no vendor configuration, implementation or documentation remains.Terraform plan evidence
Both saved plans were generated against the live state, not fixtures. No plan was applied.
terraform -chdir=infra plan -input=false -var-file=local.tfvars -target=render_env_group.production_api -target=render_env_group.staging_api -out=email-cleanup.tfplansucceeded. Inspecting the realterraform -chdir=infra show -json email-cleanup.tfplanresponse confirmedresource_changes[].address,type, andchange.actions, pluschange.before.env_varsandchange.after.env_varsas maps. The only non-no-op resource actions are:render_env_group.production_apiEmail__Provider,Resend__ApiKey,Resend__FromEmail,Resend__SupportEmailrender_env_group.staging_apiEmail__Provider,Resend__ApiKey,Resend__FromEmail,Resend__SupportEmailA separate
email-dns-cleanup.tfplan, targeted at the six removedcloudflare_dns_record.existinginstances, succeeded and contains exactly six deletes:resend_send_dkim_txt,resend_updates_dkim_txt,resend_send_spf_txt,resend_updates_spf_txt,send_send_mx, andsend_updates_mx. SES DNS resources remain unchanged. Plans are ignored because they contain decrypted secrets; regenerate them with the same targets and inspect the actual JSON before applying.Manual steps
release.yml), dispatched frommain: selectenvironment=production,branch=main, thenenvironment=staging,branch=redesign/main. Confirm both APIs are healthy and each delivers a sign-in code with AWS CloudWatch > Metrics >AWS/SES>SendandDeliveryfor its transactional configuration set (orbit-transactionalororbit-staging-transactional). Production can use the SES mailbox simulator. Until both releases pass, change no email setting in Render and deploy no build from before this change: an old build falls back to Resend whenEmail__Provideris absent, and Render's Save and deploy redeploys the existing build with the changed variables.production_email_providerandstaging_email_providerfrominfra/local.tfvars, regenerate and review the API group plan ininfra/README.md, then apply that saved plan. In Render > Environment Groups >orbit-production-apiandorbit-staging-api, confirmEmail__Providerand everyResend__*key are absent and all existingSes__*values are preserved.Email__ProviderandResend__*overrides, includingResend__ApiKey,Resend__FromEmail,Resend__SupportEmailand anyResend__MarketingFromEmailoverride. The running SES-only build ignores them. Confirm neither service has retired email keys overriding its linked group./orbit/production/api/Resend__ApiKeyand/orbit/staging/api/Resend__ApiKeyin AWS Systems Manager > Parameter Store inus-east-2. Confirm both exact names are absent; removing data-source references alone does not delete them.useorbit.org> DNS > Records, confirm the TXT recordsresend._domainkey.send.useorbit.organdresend._domainkey.updates.useorbit.org, and the MX/TXT pairs atsend.send.useorbit.organdsend.updates.useorbit.org, are removed. Confirm the SES DKIM CNAMEs andbounce.send.useorbit.org/bounce.updates.useorbit.orgMX/TXT records remain.After both releases pass, the owner may permanently delete the Resend account through their own account deletion action.