You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #29553 adds the minimal email-provider adapter seam (AdapterManager resolving EmailServiceWrapper's provider) discussed in #25367, with ghost-ses-email-adapter as the first intended consumer. It's currently blocked:
@acburdine on Added email provider adapter wiring #29553 (comment): "the main blocker to a standardized email adapter pattern isn't the email sending bits itself, it's the analytics/suppression bits... Ghost polls Mailgun's Events API for that analytics/suppression data, and we'd need to refactor some stuff in Ghost internally to allow for webhooks to be utilized instead in order to unblock full adapter support."
@9larsons earlier on Add email adapter pattern for pluggable email providers #28247 (comment) gave the fuller diagnosis: email-analytics-provider-mailgun.js is coupled to Mailgun's Events polling API, while every other candidate provider (SES, Postmark, SendGrid, etc.) is webhook-based. An adapter can send fine but analytics (opens/clicks/delivered/bounced) and suppression silently go dark, because the poll loop has nothing to poll and the bounce/complaint suppression list never fills — so Ghost keeps emailing dead addresses.
Both threads point at the same structural fix: ghost/core/core/server/services/email-analytics/ needs a webhook ingestion path alongside (or instead of) the polling path, so a non-Mailgun adapter has somewhere to deliver events.
Proposal
Open this as its own tracked issue, decoupled from any specific adapter PR, so the scope is:
Add a webhook ingestion entry point to email-analytics-service.js / email-analytics-service-wrapper.js that accepts normalized delivery/open/click/bounce/complaint events from an adapter, independent of email-analytics-provider-mailgun.js's poll loop.
Feed suppression (bounce/complaint) events from that path into the same suppression list Mailgun polling currently populates, so adapters don't silently leave it empty.
Document (in the adapter interface docs, not just code comments) which events an adapter is expected to push and in what shape, so AdapterManager-based adapters have a contract to implement against.
Why file this separately
#29553 is blocked specifically because this refactor doesn't exist yet, and the fix isn't scoped to that PR's diff — it's core analytics plumbing. Tracking it here gives the core team (or contributors, per @9larsons' "adapt contributions" note) a concrete, reviewable unit of work, and gives #29553 (and any future adapter PR) a real merge path instead of an open-ended "we're looking into it."
Happy to help scope or prototype the webhook ingestion path against ghost-ses-email-adapter as a concrete test case if that's useful — SES already delivers bounce/complaint/delivery events via SNS webhooks, so it's a reasonably representative first adapter to validate the contract against.
Context
PR #29553 adds the minimal email-provider adapter seam (
AdapterManagerresolvingEmailServiceWrapper's provider) discussed in #25367, with ghost-ses-email-adapter as the first intended consumer. It's currently blocked:blockedlabel — "the core team will likely take this over or adapt contributions."email-analytics-provider-mailgun.jsis coupled to Mailgun's Events polling API, while every other candidate provider (SES, Postmark, SendGrid, etc.) is webhook-based. An adapter can send fine but analytics (opens/clicks/delivered/bounced) and suppression silently go dark, because the poll loop has nothing to poll and the bounce/complaint suppression list never fills — so Ghost keeps emailing dead addresses.Both threads point at the same structural fix:
ghost/core/core/server/services/email-analytics/needs a webhook ingestion path alongside (or instead of) the polling path, so a non-Mailgun adapter has somewhere to deliver events.Proposal
Open this as its own tracked issue, decoupled from any specific adapter PR, so the scope is:
email-analytics-service.js/email-analytics-service-wrapper.jsthat accepts normalized delivery/open/click/bounce/complaint events from an adapter, independent ofemail-analytics-provider-mailgun.js's poll loop.AdapterManager-based adapters have a contract to implement against.Why file this separately
#29553 is blocked specifically because this refactor doesn't exist yet, and the fix isn't scoped to that PR's diff — it's core analytics plumbing. Tracking it here gives the core team (or contributors, per @9larsons' "adapt contributions" note) a concrete, reviewable unit of work, and gives #29553 (and any future adapter PR) a real merge path instead of an open-ended "we're looking into it."
Happy to help scope or prototype the webhook ingestion path against
ghost-ses-email-adapteras a concrete test case if that's useful — SES already delivers bounce/complaint/delivery events via SNS webhooks, so it's a reasonably representative first adapter to validate the contract against.References