Skip to content

feat(data-warehouse): add resend source#55935

Merged
Gilbert09 merged 18 commits into
masterfrom
add-resend-warehouse-source
Apr 28, 2026
Merged

feat(data-warehouse): add resend source#55935
Gilbert09 merged 18 commits into
masterfrom
add-resend-warehouse-source

Conversation

@Gilbert09
Copy link
Copy Markdown
Member

Problem

Resend (https://resend.com) is a transactional email platform. PostHog customers that send email through Resend have no first-class way to pull audiences, broadcasts, domains, emails, or contacts into the Data warehouse for analytics alongside their product data.

Changes

Adds Resend as a new Data warehouse source, shipping as beta:

  • New source ResendSource at posthog/temporal/data_imports/sources/resend/ (source.py / settings.py / resend.py split)
  • Inherits from ResumableSource/emails is cursor-paginated (limit + after, has_more) and persists its cursor after each page; /contacts fan-out persists the last completed parent audience id so interrupted backfills don't restart from the top
  • Five endpoints: audiences, broadcasts, domains, emails, contacts (fan-out from audiences with _audience_id injected onto each row). All partitioned by created_at with monthly partitioning
  • Bearer-token auth with a single api_key (password) field; validation probes GET /domains
  • get_non_retryable_errors maps 401/403 to actionable messages so bad keys fail fast instead of retry-storming
  • Enum registration across products/data_warehouse/backend/types.py, posthog/schema.py, frontend/src/queries/schema/schema-general.ts, sources/__init__.py, and generated_configs.py (the latter two are normally regenerated by pnpm run generate:source-configs / pnpm run schema:build)
  • Django migration 0048_alter_externaldatasource_source_type.py adds "Resend" to ExternalDataSource.source_type choices
  • Icon at frontend/public/services/resend.png (sourced via Logo.dev)

How did you test this code?

I am an LLM agent; I verified via unit tests only and did not test the end-to-end sync in the UI or against a real Resend account.

  • Transport tests (test_resend.py, 21 cases): validate_credentials status-code matrix, flat-endpoint single-batch behavior, /emails cursor pagination + state save, resume-from-saved-cursor, /contacts fan-out row enrichment and parent-id resumption, per-endpoint SourceResponse shape, 429 retry, 401 non-retry.
  • Source-class tests (test_resend_source.py, 10 cases): source_type, config shape and fields, get_schemas (all + filtered by names), credential validation success/failure, resumable manager binding, source_for_pipeline plumbing.
  • Ran full resend suite locally: 31 passed in 2.91s.
  • Ran ruff check / ruff format clean across all modified files.
  • Manually loaded the source via Django and confirmed ResendSource.get_source_config resolves, reports Label: Resend, Beta: True, and get_schemas returns the expected five endpoint names.

Reviewers should:

  • Run pnpm run generate:source-configs and pnpm run schema:build locally and confirm the generated-file diffs are empty (i.e. what I wrote by hand matches the generator output).
  • Exercise the source end-to-end from the Data warehouse new-source wizard with a real Resend API key on at least one endpoint (recommend audiences or domains for speed, emails for pagination coverage).

Publish to changelog?

yes — new Data warehouse source

Docs update

Need docs page at posthog.com/docs/cdp/sources/resend (referenced by docsUrl). Flagged separately.

🤖 LLM context

Authored by PostHog Code (task 9c3a0cc6-cc75-4def-9a85-fe8da4927b4f) using the implementing-warehouse-sources skill. Modeled after posthog/temporal/data_imports/sources/klaviyo/ as the reference ResumableSource. Plan was reviewed and approved by the human before implementation.

Adds Resend (https://resend.com) as a beta Data warehouse source covering
audiences, broadcasts, domains, emails (cursor-paginated), and contacts
(fan-out from audiences). Built on ResumableSource so /emails backfills can
resume mid-sync.

Generated-By: PostHog Code
Task-Id: 9c3a0cc6-cc75-4def-9a85-fe8da4927b4f
Copilot AI review requested due to automatic review settings April 23, 2026 11:37
@assign-reviewers-posthog assign-reviewers-posthog Bot requested review from a team April 23, 2026 11:37
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Comments Outside Diff (1)

  1. posthog/temporal/data_imports/sources/resend/source.py, line 418-426 (link)

    P2 Redundant double-lookup can be simplified

    INCREMENTAL_FIELDS.get(endpoint, None) is not None is evaluated twice per schema entry — once for supports_incremental and once for supports_append. A single membership test is cleaner and avoids the redundancy:

    (list(ENDPOINTS) is also unnecessary since a tuple is already iterable.)

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: posthog/temporal/data_imports/sources/resend/source.py
    Line: 418-426
    
    Comment:
    **Redundant double-lookup can be simplified**
    
    `INCREMENTAL_FIELDS.get(endpoint, None) is not None` is evaluated twice per schema entry — once for `supports_incremental` and once for `supports_append`. A single membership test is cleaner and avoids the redundancy:
    
    
    
    (`list(ENDPOINTS)` is also unnecessary since a tuple is already iterable.)
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix All With AI
This is a comment left during a code review.
Path: posthog/schema.py
Line: 2127

Comment:
**Autogenerated file manually modified**

`posthog/schema.py` is autogenerated by `pnpm run schema:build` and should not be edited by hand. The PR description acknowledges this and asks reviewers to verify the generator produces the same diff, but the file should be left to the generator rather than committed with manual edits — the generator run should be part of the PR itself.

**Rule Used:** Do not manually modify the `posthog/schema.py` fil... ([source](https://app.greptile.com/review/custom-context?memory=192de143-59d7-412f-bd71-fe5cb8f161dd))

**Learned From**
[PostHog/posthog#32620](https://github.com/PostHog/posthog/pull/32620)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: posthog/temporal/data_imports/sources/resend/resend.py
Line: 195-196

Comment:
**Use direct access for primary key fields**

`audience_id = audience.get("id")` uses defensive `.get()` for the primary-key field, silently skipping any audience that lacks an `id`. Per the codebase convention, primary keys should use direct dictionary access (`audience["id"]`) so a missing field raises a `KeyError` immediately rather than producing a silent data gap. The same applies to the cursor extraction on line 168: `items[-1].get("id")` should be `items[-1]["id"]` — if an email row has no `id`, pagination silently terminates rather than surfacing the schema mismatch.

**Rule Used:** For primary key fields or other critical required ... ([source](https://app.greptile.com/review/custom-context?memory=be55dab6-5161-4694-bfc8-99df4255406a))

**Learned From**
[PostHog/posthog#45266](https://github.com/PostHog/posthog/pull/45266#discussion_r2705381394)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: posthog/temporal/data_imports/sources/resend/source.py
Line: 418-426

Comment:
**Redundant double-lookup can be simplified**

`INCREMENTAL_FIELDS.get(endpoint, None) is not None` is evaluated twice per schema entry — once for `supports_incremental` and once for `supports_append`. A single membership test is cleaner and avoids the redundancy:

```suggestion
        schemas = [
            SourceSchema(
                name=endpoint,
                supports_incremental=endpoint in INCREMENTAL_FIELDS,
                supports_append=endpoint in INCREMENTAL_FIELDS,
                incremental_fields=INCREMENTAL_FIELDS.get(endpoint, []),
            )
            for endpoint in ENDPOINTS
        ]
```

(`list(ENDPOINTS)` is also unnecessary since a tuple is already iterable.)

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(data-warehouse): add resend source" | Re-trigger Greptile

Comment thread posthog/schema.py
Comment thread posthog/temporal/data_imports/sources/resend/resend.py
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 23, 2026

Size Change: 0 B

Total Size: 132 MB

ℹ️ View Unchanged
Filename Size Change
frontend/dist/368Hedgehogs 5.26 kB 0 B
frontend/dist/abap 14.2 kB 0 B
frontend/dist/AccountSocialConnected 2.2 kB 0 B
frontend/dist/Action 23.9 kB 0 B
frontend/dist/Actions 1.02 kB 0 B
frontend/dist/AdvancedActivityLogsScene 36.9 kB 0 B
frontend/dist/AgenticAuthorize 5.46 kB 0 B
frontend/dist/apex 3.95 kB 0 B
frontend/dist/ApprovalDetail 16.2 kB 0 B
frontend/dist/array.full.es5.js 344 kB 0 B
frontend/dist/array.full.js 437 kB 0 B
frontend/dist/array.js 189 kB 0 B
frontend/dist/AsyncMigrations 13.1 kB 0 B
frontend/dist/AuthorizationStatus 716 B 0 B
frontend/dist/azcli 846 B 0 B
frontend/dist/bat 1.84 kB 0 B
frontend/dist/BatchExportScene 60.5 kB 0 B
frontend/dist/bicep 2.55 kB 0 B
frontend/dist/Billing 493 B 0 B
frontend/dist/BillingSection 20.8 kB 0 B
frontend/dist/BoxPlot 5.04 kB 0 B
frontend/dist/browserAll-0QZMN1W2 37.4 kB 0 B
frontend/dist/ButtonPrimitives 562 B 0 B
frontend/dist/CalendarHeatMap 4.79 kB 0 B
frontend/dist/cameligo 2.18 kB 0 B
frontend/dist/changeRequestsLogic 544 B 0 B
frontend/dist/CLIAuthorize 11.4 kB 0 B
frontend/dist/CLILive 4.01 kB 0 B
frontend/dist/clojure 9.64 kB 0 B
frontend/dist/coffee 3.59 kB 0 B
frontend/dist/Cohort 24.8 kB 0 B
frontend/dist/CohortCalculationHistory 6.22 kB 0 B
frontend/dist/Cohorts 9.39 kB 0 B
frontend/dist/ConfirmOrganization 4.51 kB 0 B
frontend/dist/conversations.js 67.2 kB 0 B
frontend/dist/Coupons 720 B 0 B
frontend/dist/cpp 5.3 kB 0 B
frontend/dist/Create 829 B 0 B
frontend/dist/crisp-chat-integration.js 1.88 kB 0 B
frontend/dist/csharp 4.52 kB 0 B
frontend/dist/csp 1.42 kB 0 B
frontend/dist/css 4.51 kB 0 B
frontend/dist/cssMode 4.15 kB 0 B
frontend/dist/CustomCssScene 3.55 kB 0 B
frontend/dist/CustomerAnalyticsConfigurationScene 2.06 kB 0 B
frontend/dist/CustomerAnalyticsScene 26.5 kB 0 B
frontend/dist/CustomerJourneyBuilderScene 1.83 kB 0 B
frontend/dist/CustomerJourneyTemplatesScene 7.51 kB 0 B
frontend/dist/customizations.full.js 17.9 kB 0 B
frontend/dist/CyclotronJobInputAssignee 1.32 kB 0 B
frontend/dist/CyclotronJobInputBusinessHours 2.71 kB 0 B
frontend/dist/CyclotronJobInputTicketTags 711 B 0 B
frontend/dist/cypher 3.38 kB 0 B
frontend/dist/dart 4.25 kB 0 B
frontend/dist/Dashboard 1.14 kB 0 B
frontend/dist/Dashboards 22 kB 0 B
frontend/dist/DashboardTemplateCopyScene 5.7 kB 0 B
frontend/dist/DataManagementScene 646 B 0 B
frontend/dist/DataPipelinesNewScene 2.33 kB 0 B
frontend/dist/DataWarehouseScene 1.29 kB +50 B (+4.02%)
frontend/dist/Deactivated 1.13 kB 0 B
frontend/dist/dead-clicks-autocapture.js 13.1 kB 0 B
frontend/dist/DeadLetterQueue 5.38 kB 0 B
frontend/dist/DebugScene 20 kB 0 B
frontend/dist/decompressionWorker 2.85 kB 0 B
frontend/dist/decompressionWorker.js 2.85 kB 0 B
frontend/dist/DefinitionEdit 8.57 kB 0 B
frontend/dist/DefinitionView 23.8 kB 0 B
frontend/dist/DestinationsScene 2.71 kB 0 B
frontend/dist/dist 575 B 0 B
frontend/dist/dockerfile 1.87 kB 0 B
frontend/dist/EarlyAccessFeature 753 B 0 B
frontend/dist/EarlyAccessFeatures 2.84 kB 0 B
frontend/dist/ecl 5.33 kB 0 B
frontend/dist/EditorScene 896 B 0 B
frontend/dist/elixir 10.3 kB 0 B
frontend/dist/elk.bundled 1.44 MB 0 B
frontend/dist/EmailMFAVerify 3.01 kB 0 B
frontend/dist/EndpointScene 39 kB 0 B
frontend/dist/EndpointsScene 21.3 kB 0 B
frontend/dist/ErrorTrackingIssueFingerprintsScene 6.98 kB 0 B
frontend/dist/ErrorTrackingIssueScene 99.1 kB 0 B
frontend/dist/ErrorTrackingScene 22.6 kB 0 B
frontend/dist/EvaluationTemplates 575 B 0 B
frontend/dist/EventsScene 2.57 kB 0 B
frontend/dist/exception-autocapture.js 11.8 kB 0 B
frontend/dist/Experiment 193 kB 0 B
frontend/dist/Experiments 18.2 kB 0 B
frontend/dist/exporter 21.4 MB 0 B
frontend/dist/exporter.js 21.4 MB +136 B (0%)
frontend/dist/ExportsScene 3.98 kB 0 B
frontend/dist/FeatureFlag 129 kB 0 B
frontend/dist/FeatureFlags 606 B 0 B
frontend/dist/FeatureFlagTemplatesScene 7.03 kB 0 B
frontend/dist/FlappyHog 5.78 kB 0 B
frontend/dist/flow9 1.8 kB 0 B
frontend/dist/freemarker2 16.7 kB 0 B
frontend/dist/fsharp 2.98 kB 0 B
frontend/dist/go 2.65 kB 0 B
frontend/dist/graphql 2.26 kB 0 B
frontend/dist/Group 14.5 kB 0 B
frontend/dist/Groups 3.91 kB 0 B
frontend/dist/GroupsNew 7.34 kB 0 B
frontend/dist/handlebars 7.34 kB 0 B
frontend/dist/hcl 3.59 kB 0 B
frontend/dist/HealthCategoryDetailScene 7.23 kB 0 B
frontend/dist/HealthScene 10.6 kB 0 B
frontend/dist/HeatmapNewScene 4.61 kB 0 B
frontend/dist/HeatmapRecordingScene 4 kB 0 B
frontend/dist/HeatmapScene 6.62 kB 0 B
frontend/dist/HeatmapsScene 3.88 kB 0 B
frontend/dist/hls 394 kB 0 B
frontend/dist/HogFunctionScene 59.3 kB 0 B
frontend/dist/HogRepl 7.37 kB 0 B
frontend/dist/html 5.58 kB 0 B
frontend/dist/htmlMode 4.62 kB 0 B
frontend/dist/image-blob-reduce.esm 49.4 kB 0 B
frontend/dist/InboxScene 59.8 kB 0 B
frontend/dist/index 307 kB 0 B
frontend/dist/index.js 307 kB 0 B
frontend/dist/ini 1.1 kB 0 B
frontend/dist/InsightQuickStart 5.42 kB 0 B
frontend/dist/InsightScene 28.8 kB 0 B
frontend/dist/IntegrationsRedirect 733 B 0 B
frontend/dist/intercom-integration.js 1.93 kB 0 B
frontend/dist/InviteSignup 14.4 kB 0 B
frontend/dist/java 3.22 kB 0 B
frontend/dist/javascript 985 B 0 B
frontend/dist/jsonMode 13.9 kB 0 B
frontend/dist/julia 7.22 kB 0 B
frontend/dist/kotlin 3.4 kB 0 B
frontend/dist/lazy 159 kB 0 B
frontend/dist/LegacyPluginScene 20.7 kB 0 B
frontend/dist/LegalDocumentNewScene 59.4 kB 0 B
frontend/dist/LegalDocumentsScene 4.63 kB 0 B
frontend/dist/LemonTextAreaMarkdown 502 B 0 B
frontend/dist/less 3.9 kB 0 B
frontend/dist/lexon 2.44 kB 0 B
frontend/dist/lib 2.22 kB 0 B
frontend/dist/Link 468 B 0 B
frontend/dist/LinkScene 24.8 kB 0 B
frontend/dist/LinksScene 4.19 kB 0 B
frontend/dist/liquid 4.53 kB 0 B
frontend/dist/LiveDebugger 19.1 kB 0 B
frontend/dist/LiveEventsTable 5.22 kB 0 B
frontend/dist/LLMAnalyticsClusterScene 18.8 kB 0 B
frontend/dist/LLMAnalyticsClustersScene 51.8 kB 0 B
frontend/dist/LLMAnalyticsDatasetScene 19.7 kB 0 B
frontend/dist/LLMAnalyticsDatasetsScene 3.28 kB 0 B
frontend/dist/LLMAnalyticsEvaluation 58.8 kB 0 B
frontend/dist/LLMAnalyticsEvaluationsScene 29.8 kB 0 B
frontend/dist/LLMAnalyticsPlaygroundScene 36.8 kB 0 B
frontend/dist/LLMAnalyticsScene 118 kB 0 B
frontend/dist/LLMAnalyticsSessionScene 13.4 kB 0 B
frontend/dist/LLMAnalyticsTraceScene 129 kB 0 B
frontend/dist/LLMAnalyticsUsers 526 B 0 B
frontend/dist/LLMASessionFeedbackDisplay 4.83 kB 0 B
frontend/dist/LLMPromptScene 17.5 kB 0 B
frontend/dist/LLMPromptsScene 4.47 kB 0 B
frontend/dist/LLMSkillScene 589 B 0 B
frontend/dist/LLMSkillsScene 606 B 0 B
frontend/dist/Login 8.61 kB 0 B
frontend/dist/Login2FA 4.24 kB 0 B
frontend/dist/logs.js 38.5 kB 0 B
frontend/dist/LogsAlertDetailScene 15.6 kB 0 B
frontend/dist/LogsAlertNewScene 3.72 kB 0 B
frontend/dist/LogsScene 11.4 kB 0 B
frontend/dist/lua 2.11 kB 0 B
frontend/dist/m3 2.81 kB 0 B
frontend/dist/main 819 kB 0 B
frontend/dist/ManagedMigration 14.1 kB 0 B
frontend/dist/markdown 3.79 kB 0 B
frontend/dist/MarketingAnalyticsScene 39.8 kB 0 B
frontend/dist/MaterializedColumns 10.2 kB 0 B
frontend/dist/Max 801 B 0 B
frontend/dist/mdx 5.39 kB 0 B
frontend/dist/memlens.lib.bundle 27.8 kB 0 B
frontend/dist/MessageTemplate 16.3 kB 0 B
frontend/dist/MetricsScene 828 B 0 B
frontend/dist/mips 2.58 kB 0 B
frontend/dist/ModelsScene 13.6 kB 0 B
frontend/dist/MonacoDiffEditor 403 B 0 B
frontend/dist/monacoEditorWorker 288 kB 0 B
frontend/dist/monacoEditorWorker.js 288 kB 0 B
frontend/dist/monacoJsonWorker 419 kB 0 B
frontend/dist/monacoJsonWorker.js 419 kB 0 B
frontend/dist/monacoTsWorker 7.02 MB 0 B
frontend/dist/monacoTsWorker.js 7.02 MB 0 B
frontend/dist/MoveToPostHogCloud 4.46 kB 0 B
frontend/dist/msdax 4.91 kB 0 B
frontend/dist/mysql 11.3 kB 0 B
frontend/dist/NavTabChat 4.68 kB 0 B
frontend/dist/NewSourceScene 783 B 0 B
frontend/dist/NewTabScene 647 B 0 B
frontend/dist/NodeDetailScene 16.3 kB 0 B
frontend/dist/NotebookCanvasScene 3.23 kB 0 B
frontend/dist/NotebookPanel 5.21 kB 0 B
frontend/dist/NotebookScene 8.24 kB 0 B
frontend/dist/NotebooksScene 7.58 kB 0 B
frontend/dist/OAuthAuthorize 573 B 0 B
frontend/dist/objective-c 2.41 kB 0 B
frontend/dist/Onboarding 734 kB 0 B
frontend/dist/OnboardingCouponRedemption 1.2 kB 0 B
frontend/dist/pascal 2.99 kB 0 B
frontend/dist/pascaligo 2 kB 0 B
frontend/dist/passkeyLogic 484 B 0 B
frontend/dist/PasswordReset 4.35 kB 0 B
frontend/dist/PasswordResetComplete 2.99 kB 0 B
frontend/dist/PendingDeletion 2.21 kB 0 B
frontend/dist/perl 8.25 kB 0 B
frontend/dist/PersonScene 17.6 kB 0 B
frontend/dist/PersonsScene 4.68 kB 0 B
frontend/dist/pgsql 13.5 kB 0 B
frontend/dist/php 8.02 kB 0 B
frontend/dist/PipelineStatusScene 9.1 kB 0 B
frontend/dist/pla 1.67 kB 0 B
frontend/dist/posthog 145 kB 0 B
frontend/dist/postiats 7.86 kB 0 B
frontend/dist/powerquery 16.9 kB 0 B
frontend/dist/powershell 3.27 kB 0 B
frontend/dist/PreflightCheck 5.56 kB 0 B
frontend/dist/product-tours.js 115 kB 0 B
frontend/dist/ProductTour 274 kB 0 B
frontend/dist/ProductTours 4.68 kB 0 B
frontend/dist/ProjectHomepage 40.8 kB 0 B
frontend/dist/protobuf 9.05 kB 0 B
frontend/dist/pug 4.82 kB 0 B
frontend/dist/python 4.76 kB 0 B
frontend/dist/qsharp 3.19 kB 0 B
frontend/dist/QueryPerformance 6.99 kB 0 B
frontend/dist/r 3.12 kB 0 B
frontend/dist/razor 9.35 kB 0 B
frontend/dist/react-json-view 121 kB 0 B
frontend/dist/recorder-v2.js 111 kB 0 B
frontend/dist/recorder.js 111 kB 0 B
frontend/dist/redis 3.55 kB 0 B
frontend/dist/redshift 11.8 kB 0 B
frontend/dist/RegionMap 29.4 kB 0 B
frontend/dist/render-query 21.1 MB +136 B (0%)
frontend/dist/render-query.js 21.1 MB +136 B (0%)
frontend/dist/ResourceTransfer 9.17 kB 0 B
frontend/dist/restructuredtext 3.9 kB 0 B
frontend/dist/RevenueAnalyticsScene 25.6 kB 0 B
frontend/dist/ruby 8.5 kB 0 B
frontend/dist/rust 4.16 kB 0 B
frontend/dist/SavedInsights 664 B 0 B
frontend/dist/sb 1.82 kB 0 B
frontend/dist/scala 7.32 kB 0 B
frontend/dist/scheme 1.76 kB 0 B
frontend/dist/scss 6.41 kB 0 B
frontend/dist/SdkDoctorScene 9.4 kB 0 B
frontend/dist/SessionAttributionExplorerScene 6.62 kB 0 B
frontend/dist/SessionGroupSummariesTable 4.62 kB 0 B
frontend/dist/SessionGroupSummaryScene 17 kB 0 B
frontend/dist/SessionProfileScene 15 kB 0 B
frontend/dist/SessionRecordingDetail 1.75 kB 0 B
frontend/dist/SessionRecordingFilePlaybackScene 4.46 kB 0 B
frontend/dist/SessionRecordings 742 B 0 B
frontend/dist/SessionRecordingsKiosk 8.84 kB 0 B
frontend/dist/SessionRecordingsPlaylistScene 4.14 kB 0 B
frontend/dist/SessionRecordingsSettingsScene 1.9 kB 0 B
frontend/dist/SessionsScene 3.98 kB 0 B
frontend/dist/SettingsScene 2.98 kB 0 B
frontend/dist/SharedMetric 4.93 kB 0 B
frontend/dist/SharedMetrics 549 B 0 B
frontend/dist/shell 3.07 kB 0 B
frontend/dist/SignupContainer 25.8 kB 0 B
frontend/dist/Site 1.18 kB 0 B
frontend/dist/solidity 18.6 kB 0 B
frontend/dist/sophia 2.76 kB 0 B
frontend/dist/SourceScene 758 B 0 B
frontend/dist/SourcesScene 6.1 kB 0 B
frontend/dist/sparql 2.55 kB 0 B
frontend/dist/sql 10.3 kB 0 B
frontend/dist/SqlVariableEditScene 7.24 kB 0 B
frontend/dist/st 7.4 kB 0 B
frontend/dist/StartupProgram 21.2 kB 0 B
frontend/dist/StripeConfirmInstall 3.52 kB 0 B
frontend/dist/SubscriptionScene 13.3 kB 0 B
frontend/dist/SubscriptionsScene 4.89 kB 0 B
frontend/dist/SupportSettingsScene 1.16 kB 0 B
frontend/dist/SupportTicketScene 24.6 kB 0 B
frontend/dist/SupportTicketsScene 733 B 0 B
frontend/dist/Survey 848 B 0 B
frontend/dist/SurveyFormBuilder 1.54 kB 0 B
frontend/dist/Surveys 18.2 kB 0 B
frontend/dist/surveys.js 94.3 kB 0 B
frontend/dist/SurveyWizard 70.3 kB 0 B
frontend/dist/swift 5.26 kB 0 B
frontend/dist/SystemStatus 16.8 kB 0 B
frontend/dist/systemverilog 7.61 kB 0 B
frontend/dist/TaskDetailScene 22.3 kB 0 B
frontend/dist/TaskTracker 13.5 kB 0 B
frontend/dist/tcl 3.57 kB 0 B
frontend/dist/TextCardMarkdownEditor 11 kB 0 B
frontend/dist/toolbar 11 MB 0 B
frontend/dist/toolbar.js 11 MB +127 B (0%)
frontend/dist/ToolbarLaunch 2.52 kB 0 B
frontend/dist/tracing-headers.js 1.74 kB 0 B
frontend/dist/TracingScene 31.3 kB 0 B
frontend/dist/TransformationsScene 1.95 kB 0 B
frontend/dist/TrendsLineChart 34.9 kB 0 B
frontend/dist/tsMode 24 kB 0 B
frontend/dist/twig 5.97 kB 0 B
frontend/dist/TwoFactorReset 4.02 kB 0 B
frontend/dist/typescript 240 B 0 B
frontend/dist/typespec 2.82 kB 0 B
frontend/dist/Unsubscribe 1.65 kB 0 B
frontend/dist/UserInterview 4.53 kB 0 B
frontend/dist/UserInterviews 2.01 kB 0 B
frontend/dist/vb 5.79 kB 0 B
frontend/dist/VercelConnect 4.99 kB 0 B
frontend/dist/VercelLinkError 2.26 kB 0 B
frontend/dist/VerifyEmail 4.77 kB 0 B
frontend/dist/vimMode 211 kB 0 B
frontend/dist/VisualReviewRunScene 41.6 kB 0 B
frontend/dist/VisualReviewRunsScene 6.55 kB 0 B
frontend/dist/VisualReviewSettingsScene 10.8 kB 0 B
frontend/dist/web-vitals.js 6.39 kB 0 B
frontend/dist/WebAnalyticsScene 5.77 kB 0 B
frontend/dist/WebGLRenderer-DYjOwNoG 60.3 kB 0 B
frontend/dist/WebGPURenderer-B_wkl_Ja 36.3 kB 0 B
frontend/dist/WebScriptsScene 2.57 kB 0 B
frontend/dist/webworkerAll-puPV1rBA 324 B 0 B
frontend/dist/wgsl 7.34 kB 0 B
frontend/dist/Wizard 4.45 kB 0 B
frontend/dist/WorkflowScene 101 kB 0 B
frontend/dist/WorkflowsScene 58.3 kB 0 B
frontend/dist/WorldMap 4.77 kB 0 B
frontend/dist/xml 2.98 kB 0 B
frontend/dist/yaml 4.6 kB 0 B

compressed-size-action

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Resend (transactional email platform) Data Warehouse source, including backend source implementation + resumable sync logic, schema/enum registration across backend/shared schema/frontend, and an icon for the UI.

Changes:

  • Introduces ResendSource (resumable) with 5 endpoints (audiences, broadcasts, domains, emails, contacts) and associated settings + transport logic.
  • Registers Resend in enums/choices/schema lists and wires the source into the import sources registry.
  • Adds unit tests covering credential validation, pagination/resume, fan-out behavior, and retry behavior.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
products/data_warehouse/backend/types.py Adds RESEND to backend ExternalDataSourceType choices.
products/data_warehouse/backend/migrations/max_migration.txt Bumps recorded latest migration to 0048.
products/data_warehouse/backend/migrations/0048_alter_externaldatasource_source_type.py Adds "Resend" to ExternalDataSource.source_type Django choices.
posthog/temporal/data_imports/sources/resend/source.py Implements ResendSource registry entry, UI config, schemas, and pipeline wiring.
posthog/temporal/data_imports/sources/resend/settings.py Defines endpoint metadata and incremental field definitions.
posthog/temporal/data_imports/sources/resend/resend.py Implements HTTP fetching, retry policy, pagination, resumable state, and fan-out contacts behavior.
posthog/temporal/data_imports/sources/resend/tests/test_resend.py Transport-level tests for pagination/resume/fan-out and retry behavior.
posthog/temporal/data_imports/sources/resend/tests/test_resend_source.py Source-class tests for config, schemas, validation, and pipeline wiring.
posthog/temporal/data_imports/sources/generated_configs.py Adds ResendSourceConfig type used for parsing job inputs.
posthog/temporal/data_imports/sources/init.py Exports/imports ResendSource so it is registered with the sources package.
posthog/schema.py Adds RESEND to shared schema enum.
frontend/src/queries/schema/schema-general.ts Adds Resend to the frontend external data source type list.
frontend/public/services/resend.png Adds Resend service icon for the UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread posthog/temporal/data_imports/sources/generated_configs.py
Comment thread posthog/temporal/data_imports/sources/resend/source.py
Comment thread posthog/temporal/data_imports/sources/resend/tests/test_resend.py
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 23, 2026

Migration SQL Changes

Hey 👋, we've detected some migrations on this PR. Here's the SQL output for each migration, make sure they make sense:

products/data_warehouse/backend/migrations/0048_alter_externaldatasource_source_type.py

BEGIN;
--
-- Alter field source_type on externaldatasource
--
-- (no-op)
COMMIT;

Last updated: 2026-04-28 11:52 UTC (a5dac36)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 23, 2026

🔍 Migration Risk Analysis

We've analyzed your migrations for potential risks.

Summary: 0 Safe | 1 Needs Review | 0 Blocked

⚠️ Needs Review

May have performance impact

data_warehouse.0048_alter_externaldatasource_source_type
  └─ #1 ⚠️ AlterField
     Field alteration may cause table locks or data loss (check if changing type or constraints)
     model: externaldatasource, field: source_type, field_type: CharField

Last updated: 2026-04-28 11:52 UTC (a5dac36)

@tests-posthog
Copy link
Copy Markdown
Contributor

tests-posthog Bot commented Apr 23, 2026

⏭️ Skipped snapshot commit because branch advanced to 80136ef while workflow was testing 8d1a487.

The new commit will trigger its own snapshot update workflow.

If you expected this workflow to succeed: This can happen due to concurrent commits. To get a fresh workflow run, either:

  • Merge master into your branch, or
  • Push an empty commit: git commit --allow-empty -m 'trigger CI' && git push

- Drop the `requests.HTTPError(...)` construction in a test mock (mypy
  required a `response` kwarg) — the transport code only needs any
  exception to propagate, so use a plain `Exception`.
- Use direct key access on `mock.call_args_list[i].kwargs["params"]` so
  mypy doesn't treat the indexed value as `Any | None`.
- Simplify `get_schemas` to compute `has_incremental` once per endpoint
  instead of double-looking up `INCREMENTAL_FIELDS`, and drop the
  unnecessary `list(ENDPOINTS)` (per greptile review).

Generated-By: PostHog Code
Task-Id: 9c3a0cc6-cc75-4def-9a85-fe8da4927b4f
CI was failing the `schema.json and validators.js up to date` and
`schema.py up to date` gates because `schema.json` wasn't regenerated
when `Resend` was added to `externalDataSources` in `schema-general.ts`.
Regenerated via `pnpm run schema:build:json`; `schema.py` was already
in sync with the expected output once `schema.json` caught up.

Generated-By: PostHog Code
Task-Id: 9c3a0cc6-cc75-4def-9a85-fe8da4927b4f
Comment thread posthog/temporal/data_imports/sources/resend/resend.py Outdated
@tests-posthog
Copy link
Copy Markdown
Contributor

tests-posthog Bot commented Apr 23, 2026

Query snapshots: Backend query snapshots updated

Changes: 2 snapshots (2 modified, 0 added, 0 deleted)

What this means:

  • Query snapshots have been automatically updated to match current output
  • These changes reflect modifications to database queries or schema

Next steps:

  • Review the query changes to ensure they're intentional
  • If unexpected, investigate what caused the query to change

Review snapshot changes →

Gilbert09 and others added 3 commits April 23, 2026 14:18
Replaces the deprecated `betaSource=True` flag with
`releaseStatus="beta"` to match the new release-status field added in
#55934 (alpha/beta/ga).

Generated-By: PostHog Code
Task-Id: 9c3a0cc6-cc75-4def-9a85-fe8da4927b4f
@tests-posthog
Copy link
Copy Markdown
Contributor

tests-posthog Bot commented Apr 23, 2026

⏭️ Skipped snapshot commit because branch advanced to 6e4007c while workflow was testing afba450.

The new commit will trigger its own snapshot update workflow.

If you expected this workflow to succeed: This can happen due to concurrent commits. To get a fresh workflow run, either:

  • Merge master into your branch, or
  • Push an empty commit: git commit --allow-empty -m 'trigger CI' && git push

Gilbert09 and others added 2 commits April 23, 2026 14:50
- Register ResendSourceConfig in generated_configs.get_config_for_source
  mapping. Without this entry ResendSource.parse_config() would raise
  KeyError at runtime when the pipeline tries to resolve the config class
  for an ExternalDataSource row of type Resend.
- Drop advertised incremental / append support. Resend's list endpoints
  don't expose server-side filtering on created_at, and source_for_pipeline
  didn't forward `should_use_incremental_field` / `db_incremental_field_last_value`
  / `incremental_field` to the source iterator — so every schema was in
  practice syncing as full_refresh. Aligning the advertisement to match
  reality; incremental can be added in a follow-up if/when the API supports it.
- Fix contacts-fan-out resume logic: if the previously-completed audience
  has been deleted between syncs the old code kept `skipping=True` forever,
  silently dropping every remaining audience on every subsequent sync. Now
  we locate the resume index up front and fall back to a fresh resync with
  a warning if the audience is gone. Use direct key access for the audience
  primary key so missing ids fail loudly instead of silently.
- Patch `tenacity.nap.time.sleep` in the 429 retry test to avoid real
  exponential-backoff sleeps during the test run.

Generated-By: PostHog Code
Task-Id: 9c3a0cc6-cc75-4def-9a85-fe8da4927b4f
@tests-posthog
Copy link
Copy Markdown
Contributor

tests-posthog Bot commented Apr 23, 2026

Query snapshots: Backend query snapshots updated

Changes: 1 snapshots (1 modified, 0 added, 0 deleted)

What this means:

  • Query snapshots have been automatically updated to match current output
  • These changes reflect modifications to database queries or schema

Next steps:

  • Review the query changes to ensure they're intentional
  • If unexpected, investigate what caused the query to change

Review snapshot changes →

Gilbert09 and others added 4 commits April 23, 2026 17:37
Per codebase convention, primary-key-like fields should raise loudly when
missing rather than silently skipping. Drop the `.get("id")` + warning
fallback in the emails pagination so an item missing an `id` surfaces as
a KeyError immediately instead of producing a silent data gap.

Generated-By: PostHog Code
Task-Id: 4b2e65f0-fa0e-4492-915d-b94ef6763ce2
Comment thread posthog/temporal/data_imports/sources/resend/resend.py Outdated
…stomer_io secret

- Resend pagination now surfaces an empty-page-with-has-more=True response as
  a hard ValueError instead of silently terminating, so an API contract
  violation produces a data gap that's actually visible.
- Customer.io webhook signing key field was missing secret=True; without it
  Pydantic validation fails for SourceFieldInputConfig and breaks every
  source-registry-iterating test (and the new-source page).

Generated-By: PostHog Code
Task-Id: 8a086398-abdf-4c00-ace1-a257789c9fa4
@Gilbert09 Gilbert09 merged commit 6a72420 into master Apr 28, 2026
242 checks passed
@Gilbert09 Gilbert09 deleted the add-resend-warehouse-source branch April 28, 2026 12:53
@deployment-status-posthog
Copy link
Copy Markdown

deployment-status-posthog Bot commented Apr 28, 2026

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-04-28 13:25 UTC Run
prod-us ✅ Deployed 2026-04-28 13:45 UTC Run
prod-eu ✅ Deployed 2026-04-28 13:48 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants