0
votes

I'm attempting to modify the template for e-mails on an older website I did, running Laravel 5.4

I do eventually plan to update to at least Laravel 5.5, and possibly Laravel 5.7 - but I don't want to do that right now unless strictly necessary (it would involve some significant re-writes to some of my controllers and a lot of extra testing)

I ran:

php artisan vendor:publish --tag=laravel-mail

This created files in resources/views/vendor/mail

I then edited these files and tried sending a message. No change.

I then edited the files in vendor/laravel/framework/src/Illuminate/Mail/resources/views/ and sent a message - the new template showed up.

So despite the existence of the resources/views/vendor/mail folder, Laravel is still reading from the vendor/ folder after running php artisan vendor:publish. How do I fix this? What am I doing wrong?

Update

Some additional info, in case it helps. Here's my mail template (resources/views/mail/email-a-friend.blade.php):

@component('mail::message')

Your friend, {{ $senderName }}, has sent you information about a property they feel you might be interested in.


This property is listed by {{ config('app.name') }}. To view this property and more like it, please click the link below.


@if($agent->id !== $property->agent->id)
[{{ url($property->url()) }}?agent={{ $agent->first_name }}-{{ $agent->last_name }}]({{ url($property->url()) }}?agent={{ $agent->first_name }}-{{ $agent->last_name }})
@else
[{{ url($property->url()) }}]({{ url($property->url()) }})
@endif
@if($text != "")


They also sent this message:


@component('mail::panel')
{{ $text }}
@endcomponent
@endif
@endcomponent

Here's the controller that queues up the e-mail (app/http/Controllers/AjaxController.php - just the relevant function):

public function emailAFriend(Request $request)
{
    $property = \App\Models\Property\Property::find($request->input('property-id'));
    $agent = $property->agent;
    if ($request->input('agent-id') !== $agent->id) {
        $agent = \App\User::find($request->input('agent-id'));
    }

    Mail::to($request->input('send-to'))
        ->queue(new \App\Mail\EmailAFriend($property, $agent, $request->input('name'), $request->input('reply-to'), $request->input('text')));

    return Response::json("success", 200);
}

Here's the Mailable (app/Mail/EmailAFriend.php):

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

use App\Models\Property\Property;
use App\User;

class EmailAFriend extends Mailable
{
    use Queueable, SerializesModels;

    public $subject = "Someone sent you a property!";

    public $property;
    public $agent;
    public $senderName;
    public $senderEmail;
    public $text;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(Property $property, User $agent, $name, $email, $text)
    {
        $this->subject = "$name sent you information about a property";

        $this->property = $property;
        $this->agent = $agent;
        $this->senderName = $name;
        $this->senderEmail = $email;
        $this->text = $text;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->markdown('emails.email-a-friend')
                    ->replyTo($this->senderEmail, $this->senderName)
                    ->attachData(
                        $this->property->generatePdf(['agent' => $this->agent])->inline(),
                        "{$this->property->details->lot_size} acres in {$this->property->location->county} county.pdf",
                        [
                            'mime' => 'application/pdf'
                        ]
                    );
    }
}

For testing purposes I'm using the sync QueueDriver, so this sends immediately upon the AJAX request being made. In production I use the database QueueDriver.

Update 2

The components:

resources/views/vendor/mail/html/message.blade.php:

@component('mail::layout')
    {{-- Header --}}
    @slot('header')
        @component('mail::header', ['url' => config('app.url')])
            <img src="{{ url('/img/layout/logo.png') }}" alt="{{ config('app.name') }}" />
        @endcomponent
    @endslot

    {{-- Body --}}
    {{ $slot }}

    {{-- Subcopy --}}
    @if (isset($subcopy))
        @slot('subcopy')
            @component('mail::subcopy')
                {{ $subcopy }}
            @endcomponent
        @endslot
    @endif

    {{-- Footer --}}
    @slot('footer')
        @component('mail::footer')
            &copy; {{ date('Y') }} {{ config('app.name') }}. All rights reserved.
        @endcomponent
    @endslot
@endcomponent

resources/views/vendor/mail/markdown/message.blade.php:

@component('mail::layout')
    {{-- Header --}}
    @slot('header')
        @component('mail::header', ['url' => config('app.url')])
            ![{{ config('app.name') }}]({{ url('/img/layout/logo.png') }})
        @endcomponent
    @endslot

    {{-- Body --}}
    {{ $slot }}

    {{-- Subcopy --}}
    @if (isset($subcopy))
        @slot('subcopy')
            @component('mail::subcopy')
                {{ $subcopy }}
            @endcomponent
        @endslot
    @endif

    {{-- Footer --}}
    @slot('footer')
        @component('mail::footer')
            © {{ date('Y') }} {{ config('app.name') }}. All rights reserved.
        @endcomponent
    @endslot
@endcomponent

The difference between these two and the default components (vendor/laravel/framework/src/Illuminate/Mail/resources/views/html/message.blade.php and the markdown equivalent) is in the header:

{{ config('app.name') }}
replaced with:
<img src="{{ url('/img/layout/logo.png') }}" alt="{{ config('app.name') }}" />

I was attempting to replace the company name with their logo. When I go into vendor/laravel/framework/src/Illuminate/Mail/resources/views/markdown/message.blade.php and edit this file directly, I do see the logo in the resulting e-mail. So despite the existence of the published component, it's still reading from the vendor/ directory (and editing the vendor/ directory is no good, because then the change won't persist in production)

1
I woul start with very basic check to empty view cache, can you try php artisan view:clear?Mihir Bhende
Also when you say you customized the components, did you update both markdown and html?Mihir Bhende
@MihirBhende Was hoping this would be the simple fix that did it, but no such luck. It's still reading from the vendor directory instead of the resources/views/vendor directory. And yes, I did customize both the HTML and markdown components. I'll append those to my post.stevendesu
Do you have any modifications in config/mail.php?Mihir Bhende
@MihirBhende I've made no changes to config/mail.php. In fact, most of config/mail.php is ignored as I'm using .env to overwrite MAIL_DRIVER, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTION, MAIL_FROM_ADDRESS, and MAIL_FROM_NAME.stevendesu

1 Answers

1
votes

So after digging through the Laravel source for over an hour, I finally figured this out.

  1. The Markdown renderer loads components from its componentPaths variable
  2. The componentPaths variable gets set by loadComponentFrom()
  3. loadComponentsFrom is called in the constructor of the Markdown renderer and passed $options['paths']

Knowing this I started looking into "Laravel markdown options paths" and found the following: https://stackoverflow.com/a/44264874/436976

I updated config/mail.php and added the recommended lines and it worked perfectly! I feel like vendor:publish should have done this for me, or there should have at least been some mention of this step in the official Laravel documentation, but fortunately I figured this out in under a day - so that's always nice

Note (Further Research)

It turns out this was mentioned in the official Laravel documentation, just not where I expected.

My website was originally a Laravel 5.1 site that was upgraded to 5.2, then to 5.3, and then ultimately to 5.4 before it went live (I never updated to 5.5 because once the site was live I wanted to minimize changes to the underlying framework)

With each Laravel upgrade I kept rolling forward the old files from the config/ directory and I apparently did a poor job of following the upgrade guides, because they are pretty clear:

https://laravel.com/docs/5.4/upgrade

New Configuration Options

In order to provide support for Laravel 5.4's new Markdown mail components, you should add the following block of configuration to the bottom of your mail configuration file:

'markdown' => [
    'theme' => 'default',
    'paths' => [
        resource_path('views/vendor/mail'),
    ],
],

Had I updated my configuration file as directed, I would never have had these issues.