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

Mailflow Laravel Package

agavesoft/mailflow

MailFlow is a Laravel/PHP package for building expressive email workflows. Define message sequences, conditions, and delivery steps with a clean API, then integrate them into your app to automate transactional or scheduled mail flow.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What this release actually is. v2.5.0 is not a single increment — it is a bundled publication of four never-tagged releases (2.2.0 Factura Facilita attachments, 2.3.0 F-009 catalog/provisioning, 2.4.0 F-011 pull sync, 2.5.0 F-010 guaranteed events/outbox). From a program perspective, treat this as a platform feature wave, not a patch. Scoping, estimation, and QA must be sized against F-008/F-009/F-010/F-011 collectively.

Architecture fit. The package is a Laravel SDK for a hosted notification/contact platform, and the new release moves it from "thin API client" to "transactional participant in the app":

  • Outbox pattern (smartmailto_outbox, smartmailto_outbox_alert_state) makes the app the system of record for intent until the server acknowledges by key. This is the correct pattern for delivery guarantees and is a genuine architectural improvement — it converts fire-and-forget API calls into auditable, retryable units of work.
  • Inbound pull endpoint (POST {prefix}/smartmailto/pull) inverts data flow: the SaaS now calls into the Laravel app via Contracts\PullResolver. This makes the app an integration surface with an externally reachable, signed, throttled route — a new attack surface and a new uptime dependency.
  • Declarative provisioning (F-009) turns templates/workflows/variables into a versioned artifact (variables/*.yaml|yml|json), enabling CI-driven configuration. This is the highest-leverage change for a TPM: configuration becomes reviewable and testable rather than click-ops.

Integration feasibility. Strong for a Laravel shop, with three concrete frictions:

  1. Not on Packagist. Installation requires a vcs repository entry pointing at https://github.com/agavesoft/notificabot-lara-pkg-sdk with "agavesoft/smartmailto": "^2.5". Consequence: CI runners need GitHub credentials, composer audit/security advisory tooling does not cover this dependency, and there is no Packagist-mediated availability guarantee. Mitigation: vendor/fork with an internal mirror and tag discipline.
  2. Hard server coupling. Each feature requires a server with F-008/F-009/F-010/F-011. Without it: smartmailto:provision 404s, the pull route does not register, outbox has nothing to talk to. SDK version and server version must be released as a coordinated pair — add this to the dependency/upgrade plan explicitly.
  3. New dependency and platform floor. symfony/yaml ^7.2|^8.0 plus illuminate/database|encryption|filesystem|mail. Symfony 7.2 implies PHP 8.2+. Confirm the minimum PHP and Laravel versions supported before committing; this may force an unrelated framework upgrade.

Technical risk (ranked).

  • outbox.connection vs. the app's transaction. Notes state outbox rows are written "en la transacción de la app (conexión outbox.connection)". A single atomic transaction across two database connections is not possible in Laravel. If outbox.connection is configured to a separate database, the advertised transactional guarantee silently degrades to best-effort. Either pin outbox.connection to the app connection, or accept and document the weaker guarantee.
  • APP_KEY rotation is now a data-loss event. Outbox payloads are encrypted with APP_KEY. Rotating the key can orphan in-flight rows mid-retry (up to 72 h). Key rotation must be gated on an empty/reconciled outbox — a new operational runbook item.
  • Auth failures retry instead of failing. 401/403 and misconfiguration are retried, never failed. A rotated API token produces up to 72 h of silent backlog before gave_up. Alerting exists, but the design intentionally trades fast failure for resilience; teams must monitor smartmailto:outbox:status and the heartbeat, not just error rates.
  • Default-off flags create false assurance. Outbox (SMARTMAILTO_OUTBOX_ENABLED=false), pull (SMARTMAILTO_PULL_ENABLED=false). This makes rollout safe but also means a team can believe it has delivery guarantees while running the legacy synchronous path. Feature-flag state must be a tracked environment fact, not an implicit assumption.
  • Emergency-send duplication. The SmartmailtoOutboxFailed → needsEmergencySend() → app sends directly (e.g., SES) → reportExternalSend() loop is the only thing preventing double delivery. reportExternalSend throws OutboxRowInFlight if the row is still in flight, and marks superseded otherwise. This race must be implemented and tested deliberately, not improvised during an incident.
  • Truncation and cursor semantics. Pull responses are capped at 5 MB and the cursor resumes "desde lo que cupo". A resolver with unstable sort order or non-monotonic (updatedAt, key) will silently skip records. This is the highest-probability correctness bug in the whole release.
  • Last-write-wins across push/pull (R-11). Attribute conflicts resolve by timestamp; app/server clock skew can produce silent data regression.
  • Attachment constraints. With outbox enabled, inline attachments >1 MB are rejected before persisting. fromDisk() regenerates a signed URL per attempt (good); fromUrl() carries a caller-supplied sha256 and an external TTL, which must outlive the 72 h retry window.
  • Release hygiene. Four releases shipped under one tag, notes for 2.2.0 truncated mid-sentence ("UploadedFi..."), and dates in 2026. No intermediate tags means no clean rollback to 2.4.0 and no bisect granularity. The F-008 attachment API surface is not fully documented.

Key questions for the vendor/team.

  1. Is outbox.connection intended to be the app connection? If not, what is the durability contract?
  2. Exact Laravel/PHP support matrix, and is a Packagist publication planned?
  3. Will 2.2.0–2.4.0 be tagged retroactively so we can pin and roll back?
  4. Does the worker use SELECT ... FOR UPDATE SKIP LOCKED or an equivalent lease? Safe to run N replicas?
  5. Expected outbox write volume per track/identify — what is the recommended index and retention budget?
  6. Is X-Smartmailto-Request single-use enforcement backed by shared cache (multi-node safe) or per-node?
  7. What is the full F-008 attachment API (notes truncated)?
  8. Who owns the alert channel — is Teams/email escalation acceptable to our on-call model?

Integration Approach

Stack fit. Good if the platform is Laravel 11/12 on PHP 8.2+ with MySQL/Postgres and a queue/scheduler already in place. The package assumes: a working scheduler (smartmailto:outbox:work, heartbeat), a cache for replay protection, Storage disks for attachments, and encryption via APP_KEY. No queue worker integration is mentioned — the outbox worker is a standalone artisan command, so it needs its own supervisor/systemd unit or scheduler entry.

Migration path (recommended sequencing).

  1. Supply chain first. Add the VCS repository, pin ^2.5, confirm PHP/Laravel compatibility, and stand up an internal mirror or fork tag so CI does not depend on live GitHub access. Do this before any feature work.
  2. Ship 2.3.0 (provisioning) with flags inert. Wire smartmailto:provision --validate into CI as the first win: it is read-only, fails loudly, and requires no runtime behavior change. This de-risks the whole adoption by proving catalogue/server connectivity early. Note validatePackage returns HTTP 200 even when invalid — CI must assert on the valid field, not the status code.
  3. Publish and review the migration. php artisan vendor:publish --tag=smartmailto-migrations, inspect indexes on smartmailto_outbox (status, send_before, updated_at, key), and decide outbox.connection explicitly. Run in staging for at least one full 72 h retry cycle before production.
  4. Enable outbox in staging with alerting wired first. Order matters: alerts.mail_to / alerts.teams_webhook_url must be live before SMARTMAILTO_OUTBOX_ENABLED=true, otherwise the first failure is invisible. Confirm outbound egress to the heartbeat endpoint at the same time.
  5. Turn on sendBefore enforcement and audit callers. With outbox on, send() requires sendBefore; track() without occurredAt silently uses commit time; identify() sends call time. Grep every call site and add the parameters deliberately — otherwise analytics timestamps drift to "when the DB committed", which is a subtle but permanent data-quality change.
  6. Implement the emergency-send runbook in code, not prose. Handle OutboxRowInFlight, call reportExternalSend with channel/reason, and add SmartmailtoFake::assertExternalSendReported() coverage. Add a drill to the on-call playbook.
  7. Enable pull last (2.4.0). It is the only feature that exposes an inbound public route. Requires: separate SMARTMAILTO_PULL_SECRET (pullsec_..., distinct from the webhook secret), route prefix decision (api default → /api/smartmailto/pull), throttle 120,1 tuning, and a PullResolver implementation with stable (updatedAt, key) ordering and correct 5 MB continuation. Test exclusively through Smartmailto::fakePull($resolver) + assertPullContract() before exposing the real route.
  8. Adopt F-008 attachments last. Constrain to fromDisk (per-attempt signed URLs) for anything that may sit in the outbox, and cap inline payloads under 1 MB by policy.

Compatibility notes. All four features are backward compatible with flags off, so a "deploy dark, enable in order" plan is viable. The only non-flag behavior change is the sendBefore requirement when outbox is enabled and the timestamp semantics that follow it. There is no deprecation of existing methods; health()-based direct sending is no longer recommended but still works.

Sequencing constraint. 2.4.0's pull cursor and identify(updatedAt:) only make sense alongside 2.5.0's outbox semantics — the bundled tag means you cannot stage 2.4.0 independently of 2.5.0 code. Plan the rollout by flag, not by version.

Operational Impact

Maintenance. The app now owns schema (two tables), a background worker, a scheduled heartbeat, and an inbound route — a materially larger operational footprint than an HTTP client. Budget ongoing ownership: index bloat review, smartmailto:outbox:prune scheduling, secret rotation for two distinct secrets, and upgrade coordination with the server's F-0xx releases. Because 2.2.0–2.4.0 were never tagged, upgrades cannot be bisected; expect vendor escalations to be slower and pin by commit SHA if you need intermediate states.

Support and on-call. The alert model is well designed for humans: first alert at 15 min, reminders at 1 h / 4 h / 12 h / 24 h / 48 h, summary at 72 h, plus a "recovered" notice; 422s fire immediately; failures group per project per template in 15-minute windows. This is genuinely good TPM-leverage — it gives you an SLA-shaped escalation ladder out of the box. Two caveats: (a) grouped alerts reduce noise but can mask breadth — track "distinct templates failing" as a secondary signal; (b) Teams/email is the only channel, so it must map to a real rotation. smartmailto:outbox:status, retry {id*} --key= --failed, and prune give support a self-service remediation toolkit — document them in the runbook with exact invocations.

Scaling. Every track, send, identify, link, and reportExternalSend writes an outbox row when enabled. For a high-event-volume product, the outbox becomes one of the busiest write tables in the database and is on the critical path of user-facing transactions (you are adding a write inside the app transaction). Validate: rows/day, index size after prune, worker throughput, and whether multiple worker replicas are safe given the 10-minute sending lease reclaim. Pull-side scaling depends entirely on the resolver: history_months: null means "all history", which is a trap for large contact tables — set it explicitly and verify the 5 MB truncation path continues correctly.

Failure modes to pre-write. (1) APP_KEY rotation orphans in-flight rows. (2) Expired/rotated API token → 72 h silent backlog, then gave_up. (3) Emergency send without reportExternalSend → duplicate messages to customers. (4) Pull cursor instability → silently missing contacts, no error. (5) Attachment signed URL TTL shorter than the retry window. (6) Outbox flag off in an environment where the team assumes guarantees. (7) Clock skew between app and server corrupting last-write-wins resolution. Each needs a detection signal and a one-line remedy.

Compliance. prune --contact= plus per-person retention boundaries (acked 7 days, closed 30 days) indicates ARCO/data-subject-request support. SmartmailtoOutboxFailed deliberately excludes personal data — good for log hygiene. Confirm the 7/30-day defaults satisfy your own retention policy before shipping; they are short and are your only lever.

Ramp-up. Estimate roughly: 0.5 day supply-chain/compatibility, 1 day provisioning-in-CI, 2–3 days outbox including migration review and emergency path, 2–3 days pull including resolver correctness and 5 MB pagination, 1 day attachments. Add a dedicated half-day for the operational runbook (alerts, key rotation, worker supervision, remediation commands) — that artifact, not the code, is what determines whether this release is a success. The SmartmailtoFake surface (assertLinked, assertExternalSendReported, fakePull/assertPullContract, assertPackageProvisioned, assertVariablePut, assertActivated) is comprehensive enough that a team can build confidence without a live server, which materially shortens the ramp.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource