Weave Code
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

Laravel Database Mail Templates Laravel Package

spatie/laravel-database-mail-templates

Render Laravel mailables using email templates stored in your database. Map templates to mailable classes, use variables like {{ name }}, and optionally wrap HTML in a custom layout. Update subjects and content without redeploying.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-database-mail-templates
    

    Publish the migration and config:

    php artisan vendor:publish --provider="Spatie\DatabaseMailTemplatesServiceProvider"
    php artisan migrate
    
  2. Define a Template: Create a template via Tinker or a seeder:

    use Spatie\DatabaseMailTemplates\Models\MailTemplate;
    
    MailTemplate::create([
        'name' => 'Welcome Email',
        'subject' => 'Welcome to {{ app_name }}',
        'body' => '<h1>Hello {{ user_name }}!</h1><p>Welcome to our platform.</p>',
        'markdown_body' => null, // Optional
        'html_body' => null, // Optional
        'from_address' => 'welcome@example.com',
        'from_name' => 'Support Team',
        'cc' => null,
        'bcc' => null,
        'reply_to' => null,
        'template_data' => json_encode(['app_name' => 'MyApp', 'user_name' => '{{ user }}']),
    ]);
    
  3. First Use Case: Send an email dynamically:

    use Spatie\DatabaseMailTemplates\Facades\MailTemplate;
    
    $template = MailTemplate::where('name', 'Welcome Email')->first();
    $data = ['user' => 'John Doe'];
    
    MailTemplate::send($template, $data, 'user@example.com');
    

Implementation Patterns

Core Workflows

  1. Dynamic Email Templates:

    • Store reusable templates in the database with placeholders (e.g., {{ user_name }}).
    • Override placeholders at runtime:
      $template = MailTemplate::find(1);
      MailTemplate::send($template, ['user_name' => 'Alice'], 'alice@example.com');
      
  2. Multi-Format Support:

    • Use html_body or markdown_body for formatted emails:
      $template->markdown_body = 'Welcome {{ user }}!';
      $template->html_body = '<h1>Welcome {{ user }}!</h1>';
      
  3. Template Inheritance:

    • Extend base templates (e.g., a base.html stored in the DB) by merging with dynamic data:
      $baseTemplate = MailTemplate::where('name', 'Base Template')->first();
      $dynamicData = ['user' => 'Bob'];
      MailTemplate::send($baseTemplate, $dynamicData, 'bob@example.com');
      
  4. Queueing Emails:

    • Leverage Laravel’s queue system for async sending:
      MailTemplate::queue($template, $data, $recipient);
      
  5. Localization:

    • Store translated templates (e.g., subject_en, subject_es) and switch dynamically:
      app()->setLocale('es');
      $template->subject; // Returns translated subject
      

Integration Tips

  • Validation: Use Laravel’s validation to ensure template_data is valid JSON before sending:

    $template->template_data = json_encode(['valid' => true]);
    
  • Events: Trigger events for template updates or sends:

    MailTemplate::sent(function ($template, $data, $recipient) {
        // Log or analyze sent emails
    });
    
  • APIs: Expose templates via API for frontend management:

    Route::get('/templates', function () {
        return MailTemplate::all();
    });
    
  • Testing: Mock templates in tests:

    $template = MailTemplate::factory()->create();
    $this->actingAs($user)->post('/send-email', ['template_id' => $template->id]);
    

Gotchas and Tips

Pitfalls

  1. Placeholder Conflicts:

    • Avoid naming conflicts between template_data keys and Laravel’s reserved variables (e.g., {{ app }}).
    • Fix: Use unique prefixes (e.g., {{ user_data.name }}).
  2. JSON Serialization:

    • template_data must be valid JSON. Invalid data breaks rendering.
    • Fix: Validate before saving:
      $data = ['key' => 'value'];
      if (json_encode($data) === false) {
          throw new \InvalidArgumentException('Invalid template data');
      }
      
  3. Caching:

    • Templates are not cached by default. Frequent DB queries may impact performance.
    • Fix: Cache templates in memory:
      $template = Cache::remember("template_{$id}", now()->addHours(1), function () use ($id) {
          return MailTemplate::find($id);
      });
      
  4. Markdown vs. HTML:

    • Only one of markdown_body or html_body is used. Set both if supporting both formats.
    • Fix: Use MailTemplate::render() to preview:
      $rendered = $template->render(['user' => 'Alice']);
      
  5. Queue Failures:

    • Failed queued emails may silently drop. Monitor queue jobs:
      php artisan queue:work --sleep=3 --tries=3
      

Debugging

  • Log Rendered Emails: Add a listener to log rendered content:

    MailTemplate::sent(function ($template, $data, $recipient) {
        \Log::debug('Sent email to ' . $recipient, [
            'template' => $template->name,
            'data' => $data,
        ]);
    });
    
  • Template Preview: Use MailTemplate::render() to debug placeholders:

    $rendered = $template->render(['user' => 'Alice']);
    dd($rendered); // Inspect output
    

Extension Points

  1. Custom Renderers: Extend the Spatie\DatabaseMailTemplates\MailTemplate model to add custom logic:

    namespace App\Models;
    
    use Spatie\DatabaseMailTemplates\Models\MailTemplate as BaseMailTemplate;
    
    class MailTemplate extends BaseMailTemplate {
        public function render(array $data): string {
            $content = parent::render($data);
            // Add custom processing
            return str_replace('{{ custom_tag }}', 'Replaced!', $content);
        }
    }
    
  2. Dynamic Attachments: Override the send method to add attachments dynamically:

    MailTemplate::extend(function ($sender) {
        $sender->afterSend(function ($template, $data, $recipient) {
            if (isset($data['attach_file'])) {
                \Mail::send($template, $data, function ($message) use ($data) {
                    $message->attach($data['attach_file']);
                });
            }
        });
    });
    
  3. Template Versioning: Add a version column to track template changes and rollback if needed:

    $template->increment('version');
    
  4. Webhooks: Trigger external actions (e.g., Slack notifications) when templates are sent:

    MailTemplate::sent(function ($template, $data, $recipient) {
        Http::post('https://slack.com/api/chat.postMessage', [
            'text' => "Email sent to {$recipient} via template {$template->name}",
        ]);
    });
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport