{"id":26269466,"url":"https://github.com/martinpetricko/filament-database-mail-docs","last_synced_at":"2026-04-12T22:36:58.825Z","repository":{"id":280967114,"uuid":"943746310","full_name":"MartinPetricko/filament-database-mail-docs","owner":"MartinPetricko","description":"Are you tired of writing email templates in Laravel, managing all translations and constantly editing them whenever something changes? Well, not anymore! Let your clients manage them in filament panel and call it a feature!","archived":false,"fork":false,"pushed_at":"2025-06-19T09:27:55.000Z","size":4704,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-19T10:36:10.739Z","etag":null,"topics":["database","filamentphp","laravel","mail"],"latest_commit_sha":null,"homepage":"https://filamentphp.com/plugins/martin-petricko-database-mail","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MartinPetricko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"MartinPetricko","custom":"https://filamentphp.com/plugins/martin-petricko-database-mail"}},"created_at":"2025-03-06T07:45:18.000Z","updated_at":"2025-06-19T09:27:59.000Z","dependencies_parsed_at":"2025-03-25T13:22:48.960Z","dependency_job_id":"b94dde4b-53c4-474c-b097-5940e1272db2","html_url":"https://github.com/MartinPetricko/filament-database-mail-docs","commit_stats":null,"previous_names":["martinpetricko/filament-database-mail-docs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MartinPetricko/filament-database-mail-docs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MartinPetricko%2Ffilament-database-mail-docs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MartinPetricko%2Ffilament-database-mail-docs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MartinPetricko%2Ffilament-database-mail-docs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MartinPetricko%2Ffilament-database-mail-docs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MartinPetricko","download_url":"https://codeload.github.com/MartinPetricko/filament-database-mail-docs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MartinPetricko%2Ffilament-database-mail-docs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274640942,"owners_count":25322847,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-11T02:00:13.660Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","filamentphp","laravel","mail"],"created_at":"2025-03-14T05:14:28.184Z","updated_at":"2026-04-12T22:36:58.818Z","avatar_url":"https://github.com/MartinPetricko.png","language":null,"funding_links":["https://github.com/sponsors/MartinPetricko","https://filamentphp.com/plugins/martin-petricko-database-mail"],"categories":[],"sub_categories":[],"readme":"## Introduction\n\nAre you tired of writing email templates in Laravel, managing all translations and constantly editing them whenever\nsomething changes? Well, not anymore! Let your clients manage them in filament panel and call it a feature!\n\nFilament Database Mail is a FilamentPHP implementation of an\nopen-source [Laravel Database Mail](https://github.com/MartinPetricko/laravel-database-mail) package that lets you\nstore email templates in your database, link them to events, and automatically send them when those events are\ndispatched. All event properties are shared to email and you can use them just like you would in\nstandard [Blade views](https://laravel.com/docs/12.x/blade).\n\nThis package prepares FilamentPHP resources for managing your email templates with an implementation\nof [Unlayer Editor](https://docs.unlayer.com/builder/latest/email-builder).\n\n\u003e **Security Notice:** This package allows php code executions as email templates are parsed\n\u003e with [Blade::render()](https://laravel.com/docs/12.x/blade#rendering-inline-blade-templates). So only administrators\n\u003e with highest level of access should be able to use this package.\n\n## Live Demo\n\nTo see the plugin in action, you can visit the [live demo](https://database-mail-demo.web-code.dev/).\n\n[![Youtube video](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/video-thumb.png)](https://youtu.be/wexzG0_KjKg?si=KghM4dWLFoPVenRf)\n\n## Features\n\n- Store email templates in database\n- Assign email templates to standard Laravel events\n- Send emails when the events are fired\n- Access all of event public properties in email templates\n- Define possible email recipients for each event\n- Define possible email attachments for each event\n- Use Unlayer editor to manage your templates\n- Use blade syntax in email templates\n- Delay emails sending for time interval after the event is dispatched\n- Load templates from locally created designs or from your Unlayer account\n- See any exceptions that occurred while sending email due to badly formatted mail templates\n- Easy to extend\n\n### Upgrading\n\n#### v3 to v4\n\nNew migration was added that needs to be published and migrated\n\n```bash\nphp artisan vendor:publish --tag=database-mail-migrations\n```\n\n```bash\nphp artisan migrate\n```\n\n#### v2 to v3\n\nIf you are upgrading from v2 to v3, you will need to import plugin styles in your custom filament theme. You can find\nmore information in the [Setting up Filament Database Mail](#setting-up-filament-database-mail) section.\n\n## Screenshots\n\n#### List of Email Templates\n\n![list](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/list.png)\n\n#### Email Detail\n\n![view](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/view.png)\n\n#### Email Creation\n\n![edit](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/edit.png)\n\n#### UI for Available Properties\n\n![merge-tags](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/merge-tags.png)\n\n#### Built-in Conditions and Loops\n\n![merge-tag-rules-detail](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/merge-tag-rules-detail.png)\n\n#### Custom Blade Syntax\n\n![custom-blade](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/custom-blade.png)\n\n#### Load Templates\n\n![load-template](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/load-template.png)\n\n#### Email Formatting Exceptions\n\n![exception](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/exception.png)\n\n#### Received Email\n\n![mail](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/mail.png)\n\n## Installation\n\n### Requirements\n\nFilament Database Mail requires `PHP ^8.2`, `Filament ^3.3` and `Laravel 11+`.\n\n### Activating Your License on AnyStack\n\nFilament Database Mail uses AnyStack to handle payment, licensing, and distribution.\n\nDuring the purchasing process, AnyStack will provide you with a license key. Once your license key is activated, you can\nproceed installing with composer below.\n\n### Installing with Composer\n\nTo Install Filament Database Mail with Composer, you'll need to add the following package repository to your\n`composer.json` file:\n\n```json\n{\n    \"repositories\": [\n        {\n            \"type\": \"composer\",\n            \"url\": \"https://filament-database-mail.composer.sh\"\n        }\n    ]\n}\n```\n\nOnce the repository has been added to the composer.json file, you can install Filament Database Mail like any other\ncomposer package using the composer require command:\n\n```bash\ncomposer require martinpetricko/filament-database-mail\n```\n\nNext, you will be prompted to provide your username and password.\n\n```bash\nLoading composer repositories with package information\nAuthentication required (filament-database-mail.composer.sh):\nUsername: [license-email]\nPassword: [license-key]\n```\n\nYour username will be your email address and the password is your license key. For example, let's say we have the\nfollowing email and license activation:\n\n- Contact email: john@gmail.com\n- License key: 8c21df8f-6273-4932-b4ba-8bcc723ef500\n\nYou will need to enter the above information as follows when prompted for your credentials:\n\n```bash\nLoading composer repositories with package information\nAuthentication required (filament-database-mail.composer.sh):\nUsername: john@gmail.com\nPassword: 8c21df8f-6273-4932-b4ba-8bcc723ef500\n```\n\n### Setting up Filament Database Mail\n\nThe plugin follows Filament's theming rules. So, to use the\nplugin [create a custom theme](https://filamentphp.com/docs/5.x/styling/overview#creating-a-custom-theme) if you haven't\nalready, and add the following line to your `theme.css` file:\n\n```css\n@import '../../../../vendor/martinpetricko/filament-database-mail/resources/css/index.css';\n```\n\nNow build your theme using:\n\n```bash\nnpm run build\n```\n\nPublish and run the migrations with:\n\n```bash\nphp artisan vendor:publish --tag=\"database-mail-migrations\"\nphp artisan migrate\n```\n\nPublish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"database-mail-config\"\n```\n\nThese are the contents of the published config file:\n\n```php\nreturn [\n    /**\n     * Register event listener for all TriggersDatabaseMail events,\n     * that sends mails associated with the event.\n     */\n    'register_event_listener' =\u003e true,\n\n    /**\n     * Period of time when mail exceptions are pruned.\n     */\n    'prune_exceptions_period' =\u003e now()-\u003esubMonth(),\n\n    /**\n     * Models that are used by Laravel Database Mail.\n     */\n    'models' =\u003e [\n        'mail_exception' =\u003e \\MartinPetricko\\LaravelDatabaseMail\\Models\\MailException::class,\n        'mail_template' =\u003e \\MartinPetricko\\LaravelDatabaseMail\\Models\\MailTemplate::class,\n    ],\n\n    /**\n     * Mailable that is used to send the mail from database.\n     */\n    'event_mail' =\u003e \\MartinPetricko\\LaravelDatabaseMail\\Mail\\EventMail::class,\n\n    /**\n     * Resolvers are used to automatically resolve properties of the event.\n     * These property definitions can be later shown to user as available\n     * variables that can be used in the mail template.\n     */\n    'resolvers' =\u003e [\n        \\MartinPetricko\\LaravelDatabaseMail\\Properties\\Resolvers\\EloquentResolver::class,\n        \\MartinPetricko\\LaravelDatabaseMail\\Properties\\Resolvers\\BooleanResolver::class,\n        \\MartinPetricko\\LaravelDatabaseMail\\Properties\\Resolvers\\StringResolver::class,\n        \\MartinPetricko\\LaravelDatabaseMail\\Properties\\Resolvers\\ListResolver::class,\n    ],\n\n    /**\n     * Register events that implement TriggersDatabaseMail interface.\n     * Events will be used to trigger the mail and this list\n     * of events can be shown to user as available events.\n     */\n    'events' =\u003e [\n        // \\App\\Events\\YourEvent::class\n    ],\n];\n```\n\nOptionally, you can publish other config file:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-database-mail-config\"\n```\n\nThese are the contents of the published config file:\n\n```php\nreturn [\n    /**\n     * Unlayer configuration\n     */\n    'unlayer' =\u003e [\n        /**\n         * https://docs.unlayer.com/builder/installation#where-to-get-the-project-id\n         */\n        'project_id' =\u003e env('UNLAYER_PROJECT_ID'),\n\n        /**\n         * https://docs.unlayer.com/api#section/Authentication/Get-your-API-Key\n         */\n        'api_key' =\u003e env('UNLAYER_API_KEY'),\n    ],\n];\n```\n\n\u003e **Note:** You can use this package without setting up Unlayer project, but option to load templates from Unlayer will\n\u003e be disabled.\n\nRegister exceptions reporting in `bootstrap/app.php`:\n\n```php\nuse Illuminate\\Foundation\\Configuration\\Exceptions;\nuse MartinPetricko\\LaravelDatabaseMail\\Exceptions\\DatabaseMailException;\nuse MartinPetricko\\LaravelDatabaseMail\\Facades\\LaravelDatabaseMail;\n\n//...\n\n-\u003ewithExceptions(function (Exceptions $exceptions) {\n    $exceptions-\u003ereport(function (DatabaseMailException $e) {\n        LaravelDatabaseMail::logException($e);\n    });\n})\n```\n\nEnable exceptions table pruning:\n\n```php\nSchedule::command('model:prune', [\n    '--model' =\u003e [\n        \\MartinPetricko\\LaravelDatabaseMail\\Models\\MailException::class,\n    ],\n])-\u003edaily();\n```\n\nRegister and configure plugin for your filament panel:\n\n```php\n-\u003eplugins([\n    \\MartinPetricko\\FilamentDatabaseMail\\FilamentDatabaseMailPlugin::make()\n        -\u003ecluster(Cluster::class)\n        -\u003enavigationLabel('Mails')\n        -\u003enavigationGroup('Settings')\n        -\u003enavigationIcon('heroicon-o-envelope')\n        -\u003enavigationSort(5),\n])\n```\n\n## Usage\n\n### Create Events\n\nAdd `TriggersDatabaseMail` interface and `CanTriggerDatabaseMail` trait to your\nstandard [laravel events](https://laravel.com/docs/master/events).\n\n```php\nnamespace App\\Events;\n\nuse App\\Models\\User;\nuse Illuminate\\Foundation\\Events\\Dispatchable;\nuse Illuminate\\Queue\\SerializesModels;\nuse MartinPetricko\\LaravelDatabaseMail\\Attachments\\Attachment;\nuse MartinPetricko\\LaravelDatabaseMail\\Events\\Concerns\\CanTriggerDatabaseMail;\nuse MartinPetricko\\LaravelDatabaseMail\\Events\\Contracts\\TriggersDatabaseMail;\nuse MartinPetricko\\LaravelDatabaseMail\\Recipients\\Recipient;\n\nclass Registered implements TriggersDatabaseMail\n{\n    use Dispatchable;\n    use SerializesModels;\n    use CanTriggerDatabaseMail;\n    \n    /**\n     * All public properties of the event will be passed \n     * to the mail template body and subject.\n     */\n    public function __construct(public User $user, public string $emailVerificationUrl, public ?User $inviter = null)\n    {\n        //\n    }\n\n    /**\n     * Name of the event that can be used in the UI.\n     */\n    public static function getName(): string\n    {\n        return 'User Registered';\n    }\n\n    /**\n     * Description of the event that can be used in the UI.\n     */\n    public static function getDescription(): ?string\n    {\n        return 'Fires when a user is registered';\n    }\n\n    /**\n     * List of possible recipients that can receive the email.\n     * MailTemplate stores recipient keys that will\n     * receive the email when event is triggered.\n     *\n     * @return Recipient\u003cRegistered\u003e[]\n     */\n    public static function getRecipients(): array\n    {\n        return [\n            'user' =\u003e new Recipient('Registered User', fn (Registered $event) =\u003e $event-\u003euser),\n            'inviter-user' =\u003e new Recipient('Inviter user', fn (Registered $event) =\u003e $event-\u003einviter),\n            'all' =\u003e new Recipient('All', fn (Registered $event) =\u003e [\n                $event-\u003euser,\n                $event-\u003einviter,\n            ]),\n        ];\n    }\n\n    /**\n     * List of possible attachments that can be attached to the email.\n     * MailTemplate stores attachment keys that will be attached \n     * to the email when the event is triggered.\n     *\n     * @return Attachment\u003cRegistered\u003e[]\n     */\n    public static function getAttachments(): array\n    {\n        return [\n            'terms-of-service' =\u003e new Attachment('Terms of Services', fn (Registered $event) =\u003e [\n                \\Illuminate\\Mail\\Attachment::fromUrl('https://my-project.com/tos')-\u003eas('tos.pdf'),\n            ]),\n        ];\n    }\n}\n```\n\n#### Event Properties\n\nPublic properties of the event will try to get parsed\ninto [Unlayer merge tags](https://docs.unlayer.com/builder/dynamic-content/merge-tags) automatically via registered\nresolvers in your `config/database-mail.php` file. However not all properties can be parsed into merge tags, so you can\ndefine your own resolvers or add properties map to the event.\n\n```php\nnamespace App\\Events;\n\nuse MartinPetricko\\LaravelDatabaseMail\\Events\\Contracts\\TriggersDatabaseMail;\nuse MartinPetricko\\LaravelDatabaseMail\\Properties\\Property;\n\nclass Registered implements TriggersDatabaseMail\n{\n    /**\n     * @param bool $isUserAdmin\n     * @param ?array{lorem: string, ipsum: string} $additionalData\n     * @param Product[] $products\n     * @param string[] $sponsorNames\n     */\n    public function __construct(\n        public bool $isUserAdmin,\n        public ?array $additionalData,\n        public array $products,\n        public array $sponsorNames,\n    ) {\n        //\n    }\n    \n    //...\n    \n    /**\n     * List of additional properties that can be used in the mail template\n     * and were not automatically resolved via registered resolvers.\n     *\n     * @return array\u003cstring, Property\u003e\n     */\n    public static function mergeProperties(): array\n    {\n        return [\n            'isUserAdmin' =\u003e new Property('isUserAdmin')\n                -\u003eboolean(),\n            'additionalData' =\u003e (new Property('additionalData'))\n                -\u003enullable()\n                -\u003eproperties([\n                    new Property('lorem'),\n                    new Property('ipsum'),\n                ]),\n            'products' =\u003e new Property('products')\n                -\u003etraversable()\n                -\u003eproperties([\n                    (new Property('name'))\n                        -\u003eaccessor('-\u003egetName()'),\n                    new Property('url')\n                        -\u003eaccessor('-\u003egetProductUrl()'),\n                ]),\n            'sponsorNames' =\u003e new Property('sponsorNames')\n                -\u003etraversable(),\n        ];\n    }\n}\n```\n\n\u003e **Note:** Properties map is only used for UI. As long as event property is public, you can use it in your mail\n\u003e template just like you would in a blade view.\n\n![is-user-admin](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/is-user-admin.png)\n\n![additional-data](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/additional-data.png)\n\n![products](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/products.png)\n\n![sponsor-names](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/sponsor-names.png)\n\n### Register Events\n\nAdd a list of events to your published `config/database-mail.php` file:\n\n```php\n'events' =\u003e [\n    \\App\\Events\\Registered::class,\n],\n```\n\n### Create Mail Template\n\n![edit](https://raw.githubusercontent.com/MartinPetricko/filament-database-mail-docs/refs/heads/main/assets/screenshots/edit.png)\n\n\u003e **Note:** Don't forget to activate the email after creating the template, as by default it is deactivated.\n\n### Dispatch Event\n\nDispatch the event as you would any other [Laravel event](https://laravel.com/docs/master/events#dispatching-events)\nwith its parameters.\n\n```php\nuse App\\Events\\Registered;\n\n// ... your business logic\n\nRegistered::dispatch($registeredUser, $registeredUserEmailVerificationUrl);\n```\n\n### Import/Export Mail Templates\n\nYou can prepare your mail templates before deploying your application to production and then import them in your\nseeders.\n\n#### Export Mail Templates\n\n```bash\nphp artisan mail:export\n```\n\n#### Import Mail Templates\n\n```bash\nphp artisan mail:import\n```\n\n#### Seeder Setup\n\n```php\nuse Illuminate\\Support\\Facades\\Artisan;\n\npublic function run(): void\n{\n    /**\n     * Import all mail templates from json files and replace localhost url with production url. \n     */\n    Artisan::call('mail:import', [\n        '--all' =\u003e true,\n        '--search' =\u003e 'http:\\/\\/localhost',\n        '--replace' =\u003e config('app.url'),\n    ]);\n}\n```\n\n## Authorization\n\nIn addition to standard policy actions, you can add methods to allow mail template activation/deactivation:\n\n```php\n/**\n * Used to activate/deactivate single mail template.\n */\npublic function activate(User $user, MailTemplate $mailTemplate): bool\n{\n    return true;\n}\n\n/**\n * Used to activate/deactivate mail templates via bulk actions.\n */\npublic function activateAny(User $user): bool\n{\n    return true;\n}\n```\n\nRegister your policy:\n\n```php\nuse App\\Policies\\MailTemplatePolicy;\nuse Illuminate\\Support\\Facades\\Gate;\nuse MartinPetricko\\LaravelDatabaseMail\\Models\\MailTemplate;\n\npublic function boot(): void\n{\n    Gate::policy(MailTemplate::class, MailTemplatePolicy::class);\n}\n```\n\n## Extensibility\n\nYou can override MailTemplateResource to your liking. For example let's\nimplement [filamentphp/spatie-laravel-translatable-plugin](https://github.com/filamentphp/spatie-laravel-translatable-plugin).\n\n#### Setup Plugin\n\nFollow [installation instructions](https://github.com/filamentphp/spatie-laravel-translatable-plugin) for\nfilamentphp/spatie-laravel-translatable-plugin.\n\n#### Prepare Your Translatable Model\n\n```php\n\u003c?php\n\nnamespace App\\Models;\n\nuse Spatie\\Translatable\\HasTranslations;\n\nclass MailTemplate extends \\MartinPetricko\\LaravelDatabaseMail\\Models\\MailTemplate\n{\n    use HasTranslations;\n\n    /** @var string[] */\n    public array $translatable = [\n        'subject',\n        'body',\n        'meta',\n    ];\n}\n```\n\nUpdate migration file `database/migrations/xxxx_xx_xx_xxxxxx_create_mail_templates_table.php`:\n\n```php\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class () extends Migration {\n    public function up(): void\n    {\n        Schema::create('mail_templates', static function (Blueprint $table) {\n            $table-\u003eid();\n            $table-\u003estring('event')-\u003eindex();\n            $table-\u003estring('name');\n            $table-\u003ejson('subject');            // Changed type to json\n            $table-\u003ejson('body');               // Changed type to json\n            $table-\u003ejson('meta')-\u003enullable();\n            $table-\u003ejson('recipients');\n            $table-\u003ejson('attachments');\n            $table-\u003estring('delay')-\u003enullable();\n            $table-\u003eboolean('is_active');\n            $table-\u003etimestamps();\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('mail_templates');\n    }\n};\n```\n\nUpdate your `config/database-mail.php` file to use your model:\n\n```php\n'models' =\u003e [\n    'mail_exception' =\u003e \\MartinPetricko\\LaravelDatabaseMail\\Models\\MailException::class,\n    'mail_template' =\u003e \\App\\Models\\MailTemplate::class,\n],\n```\n\n#### Extend MailTemplateResource\n\nCreate `app/Filament/Admin/Resources/MailTemplateResource.php` file:\n\n```php\nnamespace App\\Filament\\Admin\\Resources;\n\nuse App\\Filament\\Admin\\Resources\\MailTemplateResource\\Pages\\CreateMailTemplate;\nuse App\\Filament\\Admin\\Resources\\MailTemplateResource\\Pages\\EditMailTemplate;\nuse App\\Filament\\Admin\\Resources\\MailTemplateResource\\Pages\\ViewMailTemplate;\nuse Filament\\Resources\\Concerns\\Translatable;\n\nclass MailTemplateResource extends \\MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource\n{\n    use Translatable;\n\n    public static function getPages(): array\n    {\n        return array_merge(parent::getPages(), [\n            'create' =\u003e CreateMailTemplate::route('/create'),\n            'view' =\u003e ViewMailTemplate::route('/{record}'),\n            'edit' =\u003e EditMailTemplate::route('/{record}/edit'),\n        ]);\n    }\n}\n```\n\nCreate `app/Filament/Admin/Resources/MailTemplateResource/Pages/CreateMailTemplate.php` file:\n\n```php\nnamespace App\\Filament\\Admin\\Resources\\MailTemplateResource\\Pages;\n\nuse App\\Filament\\Admin\\Resources\\MailTemplateResource;\nuse Filament\\Actions\\LocaleSwitcher;\nuse Filament\\Resources\\Pages\\CreateRecord\\Concerns\\Translatable;\n\nclass CreateMailTemplate extends \\MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource\\Pages\\CreateMailTemplate\n{\n    use Translatable;\n\n    protected function getHeaderActions(): array\n    {\n        return array_merge(parent::getHeaderActions(), [\n            LocaleSwitcher::make(),\n        ]);\n    }\n}\n```\n\nCreate `app/Filament/Admin/Resources/MailTemplateResource/Pages/EditMailTemplate.php` file:\n\n```php\nnamespace App\\Filament\\Admin\\Resources\\MailTemplateResource\\Pages;\n\nuse App\\Filament\\Admin\\Resources\\MailTemplateResource;\nuse Filament\\Actions\\LocaleSwitcher;\nuse Filament\\Resources\\Pages\\EditRecord\\Concerns\\Translatable;\n\nclass EditMailTemplate extends \\MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource\\Pages\\EditMailTemplate\n{\n    use Translatable;\n\n    protected function getHeaderActions(): array\n    {\n        return array_merge(parent::getHeaderActions(), [\n            LocaleSwitcher::make(),\n        ]);\n    }\n}\n```\n\nCreate `app/Filament/Admin/Resources/MailTemplateResource/Pages/ViewMailTemplates.php` file:\n\n```php\nnamespace App\\Filament\\Admin\\Resources\\MailTemplateResource\\Pages;\n\nuse App\\Filament\\Admin\\Resources\\MailTemplateResource;\nuse Filament\\Actions\\LocaleSwitcher;\nuse Filament\\Resources\\Pages\\ViewRecord\\Concerns\\Translatable;\n\nclass ViewMailTemplate extends \\MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource\\Pages\\ViewMailTemplate\n{\n    use Translatable;\n\n    protected function getHeaderActions(): array\n    {\n        return array_merge(parent::getHeaderActions(), [\n            LocaleSwitcher::make(),\n        ]);\n    }\n}\n```\n\n#### Register Your MailTemplateResource to Plugin\n\n```php\n-\u003eplugins([\n    FilamentDatabaseMailPlugin::make()\n        -\u003emailTemplateResource(\\App\\Filament\\Admin\\Resources\\MailTemplateResource::class),\n])\n```\n\n\u003e **Note:** Don't forget to set your\n\u003e users [preferred locale](https://laravel.com/docs/12.x/mail#user-preferred-locales), so sent mails are in the right\n\u003e language.\n\n**Voilà!** Enjoy your translatable email templates that can be managed from filament panel.\n\n## Overriding FilamentPHP Auth Emails\n\nIf you want to create email templates for auth actions and override default FilamentPHP emails, you can do it by editing\nauth pages like this:\n\n### Register\n\nCreate `app/Filament/Admin/Pages/Auth/Register.php` page that extends `Filament\\Pages\\Auth\\Register` and override\n`sendEmailVerificationNotification` method to dispatch your custom events.\n\n```php\nnamespace App\\Filament\\Admin\\Pages\\Auth;\n\nuse App\\Events\\EmailVerificationRequested;\nuse App\\Events\\Registered;\nuse Filament\\Facades\\Filament;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Register extends \\Filament\\Pages\\Auth\\Register\n{\n    protected function sendEmailVerificationNotification(Model $user): void\n    {\n        // Dispatch our custom Registered event\n        Registered::dispatch($user);\n        \n        if (!$user instanceof MustVerifyEmail) {\n            return;\n        }\n\n        if ($user-\u003ehasVerifiedEmail()) {\n            return;\n        }\n\n        if (! method_exists($user, 'notify')) {\n            $userClass = $user::class;\n\n            throw new Exception(\"Model [{$userClass}] does not have a [notify()] method.\");\n        }\n\n        // Dispatch our custom EmailVerificationRequested event\n        EmailVerificationRequested::dispatch($user, Filament::getVerifyEmailUrl($user));\n    }\n}\n```\n\n### Email Verification Prompt\n\nCreate `app/Filament/Admin/Pages/Auth/EmailVerificationPrompt.php` page that extends `Filament\\Pages\\Auth\\EmailVerification\\EmailVerificationPrompt` and override\n`sendEmailVerificationNotification` method to dispatch your custom events.\n\n```php\nnamespace App\\Filament\\Admin\\Pages\\Auth;\n\nuse App\\Events\\EmailVerificationRequested;\nuse App\\Models\\User;\nuse Filament\\Facades\\Filament;\nuse Illuminate\\Contracts\\Auth\\MustVerifyEmail;\n\nclass EmailVerificationPrompt extends \\Filament\\Pages\\Auth\\EmailVerification\\EmailVerificationPrompt\n{\n    protected function sendEmailVerificationNotification(MustVerifyEmail $user): void\n    {\n        if ($user-\u003ehasVerifiedEmail()) {\n            return;\n        }\n\n        if (! method_exists($user, 'notify')) {\n            $userClass = $user::class;\n\n            throw new Exception(\"Model [{$userClass}] does not have a [notify()] method.\");\n        }\n\n        // Dispatch our custom EmailVerificationRequested event\n        EmailVerificationRequested::dispatch($user, Filament::getVerifyEmailUrl($user));\n    }\n}\n```\n\n### Request Password Reset\n\nCreate `app/Filament/Admin/Pages/Auth/RequestPasswordReset.php` page that extends `Filament\\Pages\\Auth\\PasswordReset\\RequestPasswordReset` and override\n`request` method to dispatch your custom events.\n\n```php\nnamespace App\\Filament\\Admin\\Pages\\Auth;\n\nuse App\\Events\\PasswordResetRequested;\nuse DanHarrin\\LivewireRateLimiting\\Exceptions\\TooManyRequestsException;\nuse Exception;\nuse Filament\\Facades\\Filament;\nuse Filament\\Notifications\\Notification;\nuse Illuminate\\Contracts\\Auth\\CanResetPassword;\nuse Illuminate\\Support\\Facades\\Password;\n\nclass RequestPasswordReset extends \\Filament\\Pages\\Auth\\PasswordReset\\RequestPasswordReset\n{\n    public function request(): void\n    {\n        try {\n            $this-\u003erateLimit(2);\n        } catch (TooManyRequestsException $exception) {\n            $this-\u003egetRateLimitedNotification($exception)?-\u003esend();\n\n            return;\n        }\n\n        $data = $this-\u003eform-\u003egetState();\n\n        $status = Password::broker(Filament::getAuthPasswordBroker())-\u003esendResetLink(\n            $data,\n            function (CanResetPassword $user, string $token): void {\n                if (! method_exists($user, 'notify')) {\n                    $userClass = $user::class;\n\n                    throw new Exception(\"Model [{$userClass}] does not have a [notify()] method.\");\n                }\n\n                // Dispatch our custom PasswordResetRequested event\n                PasswordResetRequested::dispatch($user, Filament::getResetPasswordUrl($token, $user));\n            },\n        );\n\n        if ($status !== Password::RESET_LINK_SENT) {\n            Notification::make()\n                -\u003etitle(__($status))\n                -\u003edanger()\n                -\u003esend();\n\n            return;\n        }\n\n        Notification::make()\n            -\u003etitle(__($status))\n            -\u003esuccess()\n            -\u003esend();\n\n        $this-\u003eform-\u003efill();\n    }\n}\n```\n\n### Register Custom Auth Pages\n\nAs a last step, you need to register your custom auth pages for your panel:\n\n```php\nnamespace App\\Providers\\Filament;\n\nuse App\\Filament\\Admin\\Pages\\Auth\\Register;\nuse App\\Filament\\Admin\\Pages\\Auth\\RequestPasswordReset;\nuse App\\Filament\\Admin\\Pages\\Auth\\EmailVerificationPrompt;\n\nclass AdminPanelProvider extends PanelProvider\n{\n    public function panel(Panel $panel): Panel\n    {\n        return $panel\n            -\u003eid('admin')\n            -\u003eregistration(Register::class)\n            -\u003epasswordReset(RequestPasswordReset::class)\n            -\u003eemailVerification(EmailVerificationPrompt::class)\n            // ...\n    }\n}\n```\n\n## Using without Filament Panel\n\nYou can use this plugin without [Filament Panel](https://filamentphp.com/docs/3.x/panels), with only your TALL stack using Filament [Forms](https://filamentphp.com/docs/3.x/forms) and [Tables](https://filamentphp.com/docs/3.x/tables).\n\n### Listing Mail Templates\n\n1. Follow [Installation](https://filamentphp.com/docs/3.x/tables/installation) guide for [adding a table to a Livewire component](https://filamentphp.com/docs/3.x/tables/adding-a-table-to-a-livewire-component).\n2. Create a Livewire component for listing mail templates:\n\n```shell\nphp artisan make:livewire ListMailTemplates\n```\n\n3. Setup your table listing mail templates:\n\n```php\nnamespace App\\Livewire;\n\nuse Filament\\Forms\\Concerns\\InteractsWithForms;\nuse Filament\\Forms\\Contracts\\HasForms;\nuse Filament\\Tables\\Actions;\nuse Filament\\Tables\\Concerns\\InteractsWithTable;\nuse Filament\\Tables\\Contracts\\HasTable;\nuse Filament\\Tables\\Table;\nuse Livewire\\Component;\nuse MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource;\nuse MartinPetricko\\LaravelDatabaseMail\\Models\\MailTemplate;\n\nclass ListMailTemplates extends Component implements HasForms, HasTable\n{\n    use InteractsWithForms;\n    use InteractsWithTable;\n\n    public function table(Table $table): Table\n    {\n        return $table\n            -\u003equery(MailTemplate::query())\n            -\u003ecolumns([\n                MailTemplateResource::getNameTableColumn(),\n                MailTemplateResource::getEventTableColumn(),\n                MailTemplateResource::getDelayTableColumn(),\n                MailTemplateResource::getIsActiveTableColumn()\n                    -\u003edisabled(false),\n                MailTemplateResource::getCreatedAtTableColumn(),\n                MailTemplateResource::getUpdatedAtTableColumn(),\n            ])\n            -\u003efilters([\n                MailTemplateResource::getEventTableFilter(),\n                MailTemplateResource::getIsActiveTableFilter(),\n            ])\n            -\u003eactions([\n                Actions\\EditAction::make()\n                    -\u003eurl(fn (MailTemplate $record) =\u003e route('mail_templates.edit', $record)),\n                Actions\\DeleteAction::make(),\n            ]);\n    }\n\n    public function render()\n    {\n        return view('livewire.list-mail-templates');\n    }\n}\n\n```\n\n4. Render the table in your Livewire component:\n\n```bladehtml\n\u003cdiv\u003e\n    {{ $this-\u003etable }}\n\u003c/div\u003e\n```\n\n5. [Render](https://livewire.laravel.com/docs/components#rendering-components) your Livewire component:\n\n```bladehtml\n@livewire('list-mail-templates')\n```\n\n### Creating Mail Template\n\n1. Follow [Installation](https://filamentphp.com/docs/3.x/forms/installation) guide for [adding a form to a Livewire component](https://filamentphp.com/docs/3.x/forms/adding-a-form-to-a-livewire-component).\n2. Create a Livewire component for creating mail template:\n\n```shell\nphp artisan make:livewire CreateMailTemplate\n```\n\n3. Setup your form for creating mail templates:\n\n```php\nnamespace App\\Livewire;\n\nuse Filament\\Forms\\Components;\nuse Filament\\Forms\\Concerns\\InteractsWithForms;\nuse Filament\\Forms\\Contracts\\HasForms;\nuse Filament\\Forms\\Form;\nuse Livewire\\Component;\nuse MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource;\nuse MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource\\Actions\\Forms\\LoadTemplateAction;\nuse MartinPetricko\\LaravelDatabaseMail\\Models\\MailTemplate;\n\nclass CreateMailTemplate extends Component implements HasForms\n{\n    use InteractsWithForms;\n\n    public ?array $data = [];\n\n    public function mount(): void\n    {\n        $this-\u003eform-\u003efill();\n    }\n\n    public function form(Form $form): Form\n    {\n        return $form\n            -\u003estatePath('data')\n            -\u003eschema([\n                Components\\Section::make()\n                    -\u003ecolumns([\n                        'md' =\u003e 3,\n                    ])\n                    -\u003eschema([\n                        Components\\Group::make([\n                            MailTemplateResource::getNameFormField(),\n                            MailTemplateResource::getEventFormField(),\n                            MailTemplateResource::getDelayFormField(),\n                            MailTemplateResource::getIsActiveFormField(),\n                        ]),\n                        Components\\Group::make([\n                            MailTemplateResource::getRecipientsFormField(),\n                        ]),\n                        Components\\Group::make([\n                            MailTemplateResource::getAttachmentsFormField(),\n                        ]),\n                    ]),\n                Components\\Section::make('Mail')\n                    -\u003eheaderActions([\n                        LoadTemplateAction::make()\n                            -\u003evisible(),\n                    ])\n                    -\u003eschema([\n                        MailTemplateResource::getSubjectFormField(),\n                        MailTemplateResource::getBodyFormField(),\n                    ]),\n            ]);\n    }\n\n    public function create(): void\n    {\n        MailTemplate::create($this-\u003eform-\u003egetState());\n    }\n\n    public function render()\n    {\n        return view('livewire.create-mail-template');\n    }\n}\n```\n\n4. Render the form in your Livewire component:\n\n```bladehtml\n\u003cdiv\u003e\n    \u003cform wire:submit=\"create\"\u003e\n        {{ $this-\u003eform }}\n\n        \u003cbutton type=\"submit\"\u003e\n            Submit\n        \u003c/button\u003e\n    \u003c/form\u003e\n\n    \u003cx-filament-actions::modals /\u003e\n\u003c/div\u003e\n\n```\n\n5. [Render](https://livewire.laravel.com/docs/components#rendering-components) your Livewire component:\n\n```bladehtml\n@livewire('create-mail-template')\n```\n\n### Editing Mail Template\n\n1. Follow [Installation](https://filamentphp.com/docs/3.x/forms/installation) guide for [adding a form to a Livewire component](https://filamentphp.com/docs/3.x/forms/adding-a-form-to-a-livewire-component).\n2. Create a Livewire component for editing mail template:\n\n```shell\nphp artisan make:livewire EditMailTemplate\n```\n\n3. Setup your form for editing mail templates:\n\n```php\nnamespace App\\Livewire;\n\nuse Filament\\Forms\\Components;\nuse Filament\\Forms\\Concerns\\InteractsWithForms;\nuse Filament\\Forms\\Contracts\\HasForms;\nuse Filament\\Forms\\Form;\nuse Illuminate\\View\\View;\nuse Livewire\\Component;\nuse MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource;\nuse MartinPetricko\\FilamentDatabaseMail\\Resources\\MailTemplateResource\\Actions\\Forms\\LoadTemplateAction;\nuse MartinPetricko\\LaravelDatabaseMail\\Models\\MailTemplate;\n\nclass EditMailTemplate extends Component implements HasForms\n{\n    use InteractsWithForms;\n\n    public MailTemplate $mailTemplate;\n\n    public ?array $data = [];\n\n    public function mount(MailTemplate $mailTemplate): void\n    {\n        $this-\u003emailTemplate = $mailTemplate;\n\n        $this-\u003eform-\u003efill($mailTemplate-\u003etoArray());\n    }\n\n    public function form(Form $form): Form\n    {\n        return $form\n            -\u003estatePath('data')\n            -\u003eschema([\n                Components\\Section::make()\n                    -\u003ecolumns([\n                        'md' =\u003e 3,\n                    ])\n                    -\u003eschema([\n                        Components\\Group::make([\n                            MailTemplateResource::getNameFormField(),\n                            MailTemplateResource::getEventFormField(),\n                            MailTemplateResource::getDelayFormField(),\n                            MailTemplateResource::getIsActiveFormField(),\n                        ]),\n                        Components\\Group::make([\n                            MailTemplateResource::getRecipientsFormField(),\n                        ]),\n                        Components\\Group::make([\n                            MailTemplateResource::getAttachmentsFormField(),\n                        ]),\n                    ]),\n                Components\\Section::make('Mail')\n                    -\u003eheaderActions([\n                        LoadTemplateAction::make()\n                            -\u003evisible(),\n                    ])\n                    -\u003eschema([\n                        MailTemplateResource::getSubjectFormField(),\n                        MailTemplateResource::getBodyFormField(),\n                    ]),\n            ]);\n    }\n\n    public function update(): void\n    {\n        $this-\u003emailTemplate-\u003eupdate($this-\u003eform-\u003egetState());\n    }\n\n    public function render(): View\n    {\n        return view('livewire.edit-mail-template');\n    }\n}\n```\n\n4. Render the form in your Livewire component:\n\n```bladehtml\n\u003cdiv\u003e\n    \u003cform wire:submit=\"update\"\u003e\n        {{ $this-\u003eform }}\n\n        \u003cbutton type=\"submit\"\u003e\n            Submit\n        \u003c/button\u003e\n    \u003c/form\u003e\n\n    \u003cx-filament-actions::modals /\u003e\n\u003c/div\u003e\n```\n\n5. [Render](https://livewire.laravel.com/docs/components#rendering-components) your Livewire component:\n\n```bladehtml\n@livewire('edit-mail-template', ['mailTemplate' =\u003e $mailTemplate])\n```\n\n## Changelog\n\nPlease see [CHANGELOG](https://github.com/MartinPetricko/filament-database-mail-docs/blob/main/CHANGELOG.md) for more\ninformation on what has changed recently.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](https://github.com/MartinPetricko/filament-database-mail-docs/security/policy) on\nhow to report security vulnerabilities.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinpetricko%2Ffilament-database-mail-docs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartinpetricko%2Ffilament-database-mail-docs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinpetricko%2Ffilament-database-mail-docs/lists"}