Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sendportal Core Laravel Package

mettle/sendportal-core

Core Laravel package powering SendPortal, a self-hosted email marketing platform. It provides models, services, and backend logic for managing subscribers, lists, campaigns, templates, and sending email through multiple providers.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit mettle/sendportal-core is the domain kernel of SendPortal, a self-hosted email marketing platform. It is not a thin utility library: it ships models, migrations, jobs, routes, views, and provider/webhook integrations for campaigns, lists, subscribers, templates, sending, and tracking. Architecture fit should therefore be judged as "embedding a marketing platform inside a Laravel estate," not "adding a Composer dependency." It fits teams that already run Laravel with queue workers and a scheduler and want first-party control of subscriber data and sending infrastructure. It is a poor fit for teams wanting a drop-in, versioned SaaS SDK.

Integration feasibility The intended path is the SendPortal application skeleton with this package as core; grafting it into an unrelated Laravel app is possible but requires reconciling auth, queue, scheduler, public webhook routes, and tracking endpoints. Every provider (SES, Postmark, Postal, SMTP) implies separate credential, DNS, and webhook plumbing. v4.0.1 is a patch over v4.0.0 and does not change the integration surface.

Technical risk This release is unusually dense with behavior changes for a patch:

  • Merge-tag churn: PR #161 (space tolerance in subscriber tag merging) was reverted by #229 inside the same release, with the effect that {{email}}, {{first_name}}, {{last_name}} are no longer replaced under the reverted behavior. Any template or content pipeline relying on the interim behavior will regress silently. This is the highest-risk item.
  • Send-status semantics: #223 fixes SMTP sends being reported successful when they fail. Correctness improves, but historical dashboards, alert thresholds, and deliverability reports will shift, and prior data may be overstated.
  • Schema migration: adding IDs to campaign statuses is a data migration on live installs; requires verification of idempotency and rollback.
  • PostalAdapter fix (#205): implies Postal sending was broken in 4.0.0. 4.0.0 should be treated as non-viable if Postal is a candidate provider.
  • Message-ID header normalization (#213): touches bounce/inbound correlation; case handling changes can affect existing matched/unmatched records.
  • Community review depth: nine first-time contributors plus an in-release revert suggests a fast but lightly gated patch train; the CI-on-fork-PRs change (#230) is a positive governance signal but does not retroactively validate this release.

Key questions

  1. Do any of our templates or downstream content processors depend on spaced merge tags or on the pre-revert parsing behavior?
  2. Which provider adapters are in scope, and does the Postal fix matter to us?
  3. What is the migration and rollback plan for the campaign-status ID change against production data volume?
  4. Will downstream reporting reconcile with corrected SMTP failure data, or do we need a cutover date and a footnote on historical metrics?
  5. What is the actual Laravel/PHP version constraint of 4.0.x versus our runtime, and is this a 3.x-to-4.x major upgrade for us?
  6. Who owns provider-specific webhook contracts (SES notification shapes, Postmark SubscriptionChange) as they evolve?

Integration Approach

Stack fit Laravel with MySQL/Postgres, Redis-backed queues, and a reliably running schedule:run are hard prerequisites — campaign dispatch is scheduler- and queue-driven, not request-driven. Provider fit spans SES (with SNS webhooks), Postmark (including the newly added SubscriptionChange event), Postal, and generic SMTP. Confirm PHP and Laravel constraints from composer.json before scoping; do not assume 4.0.x matches an older pinned runtime.

Migration path

  • From 4.0.0: low-friction but not risk-free — run the status-ID migration in a maintenance window, and audit templates for merge-tag behavior before and after.
  • From 3.x: treat as a major-version migration with its own upgrade review; this release note set describes the 4.0.0 baseline, not the 3.x delta.
  • Fresh adoption: pin ^4.0.1 explicitly. Do not allow a floating constraint that could resolve to 4.0.0.

Compatibility Inventory any local forks or overrides of PostalAdapter, HandleSesWebhook, message-ID extraction, and the merge/render pipeline — all four areas were touched. If we have patches on those files, rebase deliberately rather than fast-forwarding. Verify that custom webhook consumers tolerate the Postmark SubscriptionChange payload and any changed SES handling.

Sequencing

  1. Stand up a staging instance on 4.0.1 with a production-like dataset copy.
  2. Run the migration and validate rollback.
  3. Regression-test template rendering across the full template library, specifically spaced and unspaced merge tags.
  4. Exercise each in-scope provider end-to-end, including a forced SMTP failure to confirm it now reports as failed.
  5. Replay sample SES/Postmark webhook payloads, including SubscriptionChange and dead subscription links (expect 404, not 500).
  6. Reconcile reporting outputs against the corrected send-status semantics and set a cutover date.
  7. Promote to production behind a maintenance window; monitor send success rates and bounce correlation for the first full campaign cycle.

Operational Impact

Maintenance Expect a frequent patch cadence with occasional in-release reversions. Pin versions, stage every bump, and read the changelog for behavioral items rather than only features. Local forks are a maintenance liability here — every upstream touch to the sending or rendering path becomes a rebase.

Support Self-hosted and community-supported: no vendor SLA, no escalation path, and issue resolution depends on contributor availability. The nine first-time contributors are a healthy signal for bus factor but also mean variable familiarity with the sending pipeline, so review latency and fix durability should be watched over the next few releases.

Scaling The slow-campaign-query fix (#204) lands directly on the send path and is the most operationally valuable change in this release for large lists. The SMTP false-success fix (#223) is equally important at scale: silent drops previously masked as successes distort deliverability decisions. Scaling also depends on queue depth and worker concurrency for campaign fan-out and for inbound webhook/tracking ingestion — size those explicitly rather than inheriting defaults.

Failure modes

  • Dead subscription links now return 404 instead of 500 — correct, but changes any monitoring that alerts on 5xx rates and may under-report broken links.
  • Null content in campaign merge previously risked errors; the guard reduces blast radius but hides malformed data upstream.
  • Provider adapter regressions (Postal) can fail silently in send status; per-provider smoke tests are warranted after each bump.
  • Message-ID case mismatch can cause bounce/inbound events to attach to the wrong or no message — watch unmatched-event rates.
  • Template merge regressions are silent and user-visible in outbound email, the worst combination; automated rendering tests are the only reliable defense.

Ramp-up Requires Laravel fluency plus operational competence in queues, scheduler reliability, and ESP-specific webhook models (SNS topics for SES, Postmark webhook configuration). Budget onboarding time for the provider and webhook layer specifically; that is where new engineers are most likely to misconfigure and where failures are least visible.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator