Skip to content

Collect gift email delivery outcomes - #29852

Open
kevinansfield wants to merge 1 commit into
agent/ber-3851-delivery-lifecyclefrom
agent/ber-3851-delivery-outcomes
Open

Collect gift email delivery outcomes#29852
kevinansfield wants to merge 1 commit into
agent/ber-3851-delivery-lifecyclefrom
agent/ber-3851-delivery-outcomes

Conversation

@kevinansfield

Copy link
Copy Markdown
Member

Summary

  • reuse the Mailgun analytics collection path for accepted gift emails
  • retain only the latest delivered or failure outcome by provider timestamp
  • keep provider telemetry diagnostic-only so it never resends a gift
  • schedule collection only while giftSubCustomization is enabled

Stack

5 of 6. Stacked on #29851; feature-gated checkout activation is the final PR.

Issue: https://linear.app/ghost/issue/BER-3851/establish-immediate-email-delivery-for-gift-subscriptions

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c5eaa6f5-23f8-4ba9-b928-dc04702d6bf9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@kevinansfield
kevinansfield marked this pull request as ready for review August 10, 2026 15:11
@kevinansfield
kevinansfield force-pushed the agent/ber-3851-delivery-outcomes branch from 04758b8 to ae1f5fb Compare August 10, 2026 15:12

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04758b8fac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +121 to +122
if (labs.isSet('giftSubCustomization')) {
gifts.init({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Initialize gift analytics before runtime flag changes

When giftSubCustomization is disabled during boot and later enabled through the Labs UI, this conditional permanently skips gifts.init() for the process lifetime. Accepted deliveries then call scheduleRecurringGiftDeliveriesJob(true) and register the worker, but no subscriber exists for StartGiftEmailAnalyticsJobEvent, so every run is a no-op and delivery outcomes remain unknown until Ghost restarts. Initialize the wrapper unconditionally and gate only job scheduling/processing, or initialize it when the flag changes.

Useful? React with 👍 / 👎.

const updated = await transacting('gifts')
.where({email_provider_message_id: providerMessageId})
.where((builder) => {
builder.whereNull('delivery_outcome_at').orWhere('delivery_outcome_at', '<', timestamp);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve timestamp precision when ordering outcomes

On MySQL-backed sites, when two Mailgun outcomes for the same message occur within one second and an older event is later replayed, delivery_outcome_at loses the provider timestamp's milliseconds because Ghost's dateTime column has whole-second precision. For example, after storing an outcome from 12:00:00.900 as 12:00:00, a replay of an older 12:00:00.100 event satisfies this < timestamp predicate and overwrites the newer result, contrary to the newest-outcome contract. Store comparable provider precision or use an ordering value that survives persistence.

Useful? React with 👍 / 👎.

Comment on lines +122 to +124
gifts.init({
event: StartGiftEmailAnalyticsJobEvent,
mailgunTags: ['gift-delivery'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fetch from the transactional Mailgun account

When gift mail is sent through Ghost's transactional mail.transport=Mailgun configuration but newsletter Mailgun is absent or uses a different account/domain, this wrapper cannot find the resulting events. GiftEmailService sends with GhostMailer, which reads config.mail.options, while EmailAnalyticsServiceWrapper constructs MailgunClient, whose only credential sources are bulkEmail.mailgun and the mailgun_* newsletter settings. The recurring job therefore either reports Mailgun as unconfigured or searches the wrong domain, leaving every accepted gift's outcome unknown; the gift collector needs to use the same Mailgun credentials and domain as the transport that produced its message ID.

Useful? React with 👍 / 👎.

@nx-cloud

nx-cloud Bot commented Aug 10, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit ace1b32

Command Status Duration Result
nx run ghost:test:ci:integration ✅ Succeeded 2m 33s View ↗
nx run ghost:test:integration ✅ Succeeded 2m 47s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 26s View ↗
nx run ghost:test:legacy ✅ Succeeded 2m 29s View ↗
nx run ghost-monorepo:lint:boundaries ✅ Succeeded 22s View ↗
nx run-many -t lint -p ghost,ghost-monorepo ✅ Succeeded 20s View ↗
nx run-many -t test:unit -p ghost ✅ Succeeded 34s View ↗
nx run @tryghost/admin:build ✅ Succeeded 4s View ↗
nx run-many --target=build --projects=tag:publi... ✅ Succeeded <1s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-08-11 16:57:22 UTC

@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 59.06433% with 70 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.39%. Comparing base (ec484c7) to head (ace1b32).

Files with missing lines Patch % Lines
...core/core/server/services/email-analytics/index.ts 29.72% 26 Missing ⚠️
...il-analytics/jobs/email-analytics-job-scheduler.ts 20.68% 23 Missing ⚠️
ghost/core/core/boot.js 0.00% 9 Missing ⚠️
...es/email-analytics/jobs/gift-fetch-latest/index.js 0.00% 7 Missing ⚠️
...core/server/services/email-analytics/jobs/index.js 70.00% 3 Missing ⚠️
...ics/events/start-gift-email-analytics-job-event.ts 90.90% 1 Missing ⚠️
...-analytics/gift-email-analytics-batch-processor.ts 98.48% 1 Missing ⚠️
Additional details and impacted files
@@                          Coverage Diff                          @@
##           agent/ber-3851-delivery-lifecycle   #29852      +/-   ##
=====================================================================
+ Coverage                              75.37%   75.39%   +0.01%     
=====================================================================
  Files                                   1614     1617       +3     
  Lines                                 141889   142057     +168     
  Branches                               17583    17596      +13     
=====================================================================
+ Hits                                  106949   107104     +155     
- Misses                                 33888    33901      +13     
  Partials                                1052     1052              
Flag Coverage Δ
e2e-tests 77.51% <59.06%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kevinansfield
kevinansfield force-pushed the agent/ber-3851-delivery-outcomes branch from ae1f5fb to 636cd8f Compare August 10, 2026 17:30
@kevinansfield
kevinansfield force-pushed the agent/ber-3851-delivery-outcomes branch from 636cd8f to cb5d7cd Compare August 11, 2026 08:43
@kevinansfield
kevinansfield force-pushed the agent/ber-3851-delivery-outcomes branch from 23de72d to a162118 Compare August 11, 2026 12:04
@kevinansfield
kevinansfield force-pushed the agent/ber-3851-delivery-outcomes branch from a162118 to 37823f5 Compare August 11, 2026 12:09
ref https://linear.app/ghost/issue/BER-3851/establish-immediate-email-delivery-for-gift-subscriptions
Mailgun telemetry is useful for diagnosis after acceptance, but it must remain separate from the durable sent fact and never trigger another delivery.
@kevinansfield
kevinansfield force-pushed the agent/ber-3851-delivery-outcomes branch from 37823f5 to ace1b32 Compare August 11, 2026 16:44
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.

1 participant