finity-labs/fin-mail
FinMail adds an email template manager and composer to Filament. Create dynamic, translatable templates with token/merge-tag replacement, CTA blocks, and versioning. Send from any resource via a reusable action, with full email logging and status tracking.
{% if %} conditionals now work at any depth, with {% else %} supported on every level. Previously the first {% endif %} closed the outermost {% if %}, so any nested conditional produced broken output. Conditionals are now parsed in a single pass with a frame stack, and malformed markup (a stray {% else %}/{% endif %} or an unclosed {% if %}) stays visible in the output instead of silently losing content (thanks @Pycckoe, whose fork flagged the limitation)Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.13.0...v1.13.1
->emailTemplateResource(MyResource::class), ->emailThemeResource(...), ->sentEmailResource(...) (#22)policyNamespace() policy mapping now registers policies whenever the classes exist, with or without Shield installed. Settings pages can be gated by defining Gate abilities named after the page class (page_ManageGeneralSettings, …); pages without a defined ability stay open as before (#21)TemplateMail::withoutLogo() sends without the branding logo, and overrideBranding([...]) overrides any branding key (logo, colors, footer links, …) for a single email while the rest falls through to the saved settings (#8)Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.12.0...v1.13.0
auth_emails.store_rendered_body config option (default false). When enabled, the password reset and verification overrides store their rendered body in the Sent Emails log like any other email, for teams that want a full audit trail of exactly what was sent. Left off, the signed reset/verification URLs stay out of the databaseTemplateMail gained overridePreheader() and the compose path uses it. Tokens in the overridden preheader are replaced like in the bodyTypeError when the configured editor stores the body as a TipTap document array (e.g. the Tiptap editor). The preview already converted the document to HTML; the send path now does the same, using the template's theme colors for custom blocksTemplateMail whose log entry is first created after queue serialization (e.g. dispatch-time log insert failed, or the mailable was re-dispatched from a stored job) no longer renders in the worker's app localeuser-verify-email or user-password-reset is missing, deactivated, or errors during lookup, the notification falls back to Laravel's default mail instead of throwing — deactivating a template can no longer take down password reset app-widekey and category protection server-side. The fields were only disabled() in the form but still dehydrated, so a crafted request could rewrite a locked system template's key — which the auth email overrides depend ondeleting hook, so every delete path behaves the same — including on SQLite databases without foreign key enforcement (enforcing databases were already covered by the FK's nullOnDelete)sandbox="allow-same-origin"), matching the template preview. Stored bodies can contain recipient-influenced content, and the unsandboxed frames allowed scripts to run inside the admin panelinvoice-copy, invoice-copy-2, …) instead of a -copy-<timestamp> suffix that could collide when two replications happened in the same secondSentEmailResender serviceFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.11.4...v1.12.0
Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.11.3...v1.11.4
fin-mail:cleanup command now registers reliably: registration uses callAfterResolving(), so it also works when the schedule was already resolved before the package booted — previously the command could silently never appear in schedule:list (#26, thanks @agencetwogether)TemplateMail, instead of re-wrapping the full stored document in the email layout — which produced a nested document with two doctypes and broken logo/footer sections (#25, thanks @agencetwogether)Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.11.2...v1.11.3
Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.11.1...v1.11.2
ComposeEmail picks the right form via trans_choice(), and 37 locales gained singular|plural variants for the notification body. Locales without grammatical plural after numerals keep their single formFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.11.0...v1.11.1
TemplateMail now creates a Sent Emails log entry on its own whenever logging is enabled in the settings, so emails sent from code show up in the log just like ones sent from the admin panel. Queued mail is logged at dispatch time with a Queued status and updated to Sent or Failed once the worker processes it. Log creation failures are reported but never block the email from going out (#23, thanks @gazohu)TemplateMail::withoutLogging() opts a single email out of loggingTemplateMail::withLogging() called without an argument now forces a log entry even when logging is disabled in the settings. Passing a SentEmail still hands over an externally created record, as before — previously a bare withLogging() call silently did nothingTemplateMail::withoutStoringRenderedBody() logs the email but keeps the rendered HTML out of the databaseFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.10.0...v1.11.0
EmailSender gained a notify constructor flag so callers batching multiple sends can suppress the per-send notification and show an aggregate one insteadFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.9.0...v1.10.0
/images/logo.png) are now resolved to absolute URLs at render time via BrandingSettings::resolvedLogo(), so they display in email clients. Absolute URLs, protocol-relative URLs, and data URIs pass through unchanged (#19, thanks @mrsafalpiya)EmailTemplate::render() gained a renderBlocks flag so blocks round-trip in the editor, and TemplateMail now expands blocks in overridden bodies (#17, thanks @mrsafalpiya)EmailTheme::resolvedDefaultColors() and EmailTemplate::resolvedThemeColors() (#18, thanks @mrsafalpiya)null or an empty string (cleared ColorPickers) no longer override the hardcoded defaults when resolving colorsFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.8.1...v1.9.0
Undefined array key "cleanup_frequency" when saving the Logging settings with Enable Schedule Cleanup turned off. The frequency field is hidden in that state, so it isn't submitted — the save mutation now casts it only when it's present and leaves the stored value untouched otherwise (#16, thanks @Wijnands)Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.8.0...v1.8.1
overrideView() method on TemplateMail renders an email with your own Blade layout instead of the package's fin-mail::email.default, while keeping database-driven templates, token replacement, theming, logging, and attachments. The custom view receives the same variables as the default one ($body, $preheader, $theme, $branding) plus anything passed via with() or extraData(). Existing emails are unaffected if you don't call it (#14, thanks @agencetwogether)Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.7.1...v1.8.0
MissingSettings exception during artisan boot when scheduled cleanup is registered before the fin-mail-logging settings have been migrated. The catch around app(LoggingSettings::class) didn't cover the lazy property access that actually triggers the load, so the exception escaped and broke package:discover and fin-mail:install in some setups (#13, thanks @devrizzz)spatie/laravel-settings is now mentioned explicitly in the README as an auto-installed dependencyFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.7.0...v1.7.1
Preview, SendTest, Compose (Email Templates) and Resend (Sent Emails) are now hidden from the UI when Filament Shield is installed and the authenticated user lacks the corresponding permission. Falls back to the previous always-visible behavior when Shield is absent, so existing installs are unaffected (#12, thanks @agencetwogether)FinMailPlugin::isShieldAvailable() helper for checking Shield presencepreview_heading translation key for the preview modal header, populated across all 58 supported localesInstallCommand now seeds preview, sendTest, compose, and resend into the Filament Shield config so shield:generate produces the matching policy methods and permissionsauthorizeIndividualRecords('delete') when Shield is activephp artisan shield:generate --panel=admin --option=policies_and_permissions to register the new permissionsFull Changelog: https://github.com/finity-labs/fin-mail/compare/v1.6.0...v1.7.0
extraData() method (and native with() support) on TemplateMail for passing variables directly to the Blade view, separate from the token replacement system. Useful for view-only data that doesn't need to flow through the token engine (#10, thanks @agencetwogether)null if not set, so existing templates are unaffected. The TemplateMail mailable also gains an overrideReplyTo() setter for runtime overrides (#9, thanks @agencetwogether)A new migration is included (add_reply_to_on_email_templates_table). Run php artisan migrate after upgrading.
fin-mail.php config instead of hardcoded defaults, fixing issues with foreign key references when table names are customized (#7, thanks @agencetwogether)FinMailPlugin::make()->customBlocks([...]). Custom blocks now render correctly in the editor, preview mode, and sent emails. ButtonBlock is always included by default. Closes #6EmailTemplate, TipTapConverter, and DefaultEditor now reads from a dynamic plugin-level registry instead of a hardcoded listdate_format and datetime_format config options with per-locale array supportSee CHANGELOG.md for full details.
php artisan fin-mail:upgrade command to migrate existing data after package updates (supports --dry-run)Str::limit(), causing a TypeError<a> tags in seeded templates were stripped by TipTap; buttons now use the native customBlock formatblocks and versioning translation keys for all 59 supported languagescomposer update finity-labs/fin-mail
php artisan fin-mail:upgrade
Full changelog: https://github.com/finity-labs/fin-mail/blob/main/CHANGELOG.md
Merge Tags — Tokens are now available directly in the editor toolbar. No more switching to the Tokens tab to remember what's available.
CTA Button Block — Insert styled call-to-action buttons from the custom blocks panel. Set the text, URL, and alignment — theme colors are applied automatically.
Inline Link Styling — Links in email body now render with the correct theme color in all email clients, including those that strip <style> blocks.
Live Theme Preview — Change a color in the theme editor and see it update instantly.
Custom Theme Auto-Setup — The install command now detects your custom Filament theme CSS and offers to register FinMail styles automatically.
Full Changelog: https://github.com/finity-labs/fin-mail/compare/v1.0.1...v1.1.0
spatie/laravel-settings migration automatically if the settings table doesn't exist yet — no more crashes on fresh installspolicyNamespace() option on the plugin, so Shield-generated policies can live anywhere (defaults to App\Policies)phpdocumentor/reflection-docblock 6.xGate::policy() instead of relying on bundled policy files. This means Shield generates the policies (as it should), and FinMail just wires them up to the right modelsHow can I help you explore Laravel packages today?