I created a Notification with a mail notifiable. My problem is that I cant figure out how to set the from address.
Here's my toMail:
public function toMail($notifiable)
{
return (new MailMessage)
->from($this->email, $this->name)
->subject('Contact Form')
->line('Name: '.$this->name)
->line('Email: '.$this->email)
->line('Message: '.$this->message);
}
The from method does not work, and instead it uses the default mail config. Any ideas on why this is not working?
You need to use the from method within your mailable class' build method:
public function build()
{
return $this->from('example#example.com')
->view('emails.orders.shipped');
}
You can also have a global from email. You do that in the config/mail.php configuration file:
'from' => ['address' => 'example#example.com', 'name' => 'App Name']
this will be used if no from address is specified in the mailable class' build method
Here's a reference to the laravel documentation that explains the mail function in detail.
Related
I have an Observer set up to Listen to a Model's events in order to keep my Controller clean of Logging messages. My implementation is as follows:
First, a store method that does just what it's supposed to do. Create and save a new model from valid parameters.
# app/Http/Controllers/ExampleController.php
namespace App\Http\Controllers;
use App\Http\Requests\StoreExample;
use App\Example;
class ExampleController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
/**
* Create and save an Example from validated form parameters.
* #param App\Http\Requests\StoreExample $request
*/
public function store(StoreExample $request)
{
Example::create($request->validated());
return back();
}
}
The StoreExample Form Request isn't important. It just validates and checks a gate to authorize the action.
The Observer I have set up logs this action.
# app/Observers/ExampleObserver.php
namespace App\Observers;
use App\Example;
class ExampleObserver
{
public function created(Example $example): void
{
\Log::info(auth()->id()." (".auth()->user()->full_name.") has created Example with params:\n{$example}");
}
}
The problem I have, is the way my logs depend on the auth() object to be set. Given the auth middleware and the gate it has to check in order to store an Example, there is no way a guest user will set off this code.
However, I do like to use tinker in my local and staging environments to check the behavior of the site but that can set off an error (Well, PHP notice to be more precise) because I can create Example models without being authenticated and the logger will try to fetch the property full_name from the non-object auth()->user().
So my question is as follows: Is there a way to catch when I'm specifically using the Laravel tinker session to handle my models in the Observer class?
Okay, replying to my own question: There IS a way. It requires using a Request object. Since observers do not deal with requests on their own, I injected one in the constructor. request() can be used instead, so no DI is needed.
Why is a Request important?
Because a request object has an accessible $server attribute that has the information I want. This is the relevant information I get by returning a dd($request->server) (I'm not gonna paste the whole thing. My Request's ServerBag has over 100 attributes!)
Symfony\Component\HttpFoundation\ServerBag {#37
#parameters: array:123 [
"SERVER_NAME" => "localhost"
"SERVER_PORT" => 8000
"HTTP_HOST" => "localhost:8000"
"HTTP_USER_AGENT" => "Symfony" // Relevant
"REMOTE_ADDR" => "127.0.0.1"
"SCRIPT_NAME" => "artisan" // Relevant
"SCRIPT_FILENAME" => "artisan" // Relevant
"PHP_SELF" => "artisan" // Relevant
"PATH_TRANSLATED" => "artisan" // Relevant
"argv" => array:2 [ // Relevant
0 => "artisan"
1 => "tinker"
]
"argc" => 2
]
}
So there's all these attributes I can filter by using $request->server('attribute') (returns $request->server->attribute or null, so no risk of accessing an undefined property). I can also do $request->server->has('attribute') (returns true or false)
# app/Observers/ExampleObserver.php
namespace App\Observers;
use App\Example;
class ExampleObserver
{
/* Since we can use request(), there's no need to inject a Request into the constructor
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
*/
public function created(Example $example): void
{
\Log::info($this->getUserInfo()." has created Example with params:\n{$example}");
}
private function getUserInfo(): string
{
// My logic here.
}
}
verification email that come with laravel 5.7. How and where i need to change it? I had searched all over online, but because it is brand new feature in 5.7,So i could not find an answer. Can you help me please? Thanks in advance.
basically that class is under Illuminate\Auth\Notifications
i want to override one of the method:
class VerifyEmail extends Notification
{
// i wish i could override this method
protected function verificationUrl($notifiable)
{
return URL::temporarySignedRoute('verification.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()]);
}
}
Because your User Model uses Illuminate\Auth\MustVerifyEmail you can override the method sendEmailVerificationNotification which is the method that notifies the created user by calling the method notify and passes, as a parameter, a new instance of the Notifications\MustVerifyEmail class.
You can create a custom Notification which will be passed as parameter to $this->notify() within the sendEmailVerificationNotification method in your User Model:
public function sendEmailVerificationNotification()
{
$this->notify(new App\Notifications\CustomVerifyEmail);
}
And in your CustomVerifyEmail Notification you can define the route through which the verification will be handled and all parameters that it will take.
When a new user signs up an Illuminate\Auth\Events\Registered Event is emitted in the App\Http\Controllers\Auth\RegisterController and that event has a listener Illuminate\Auth\Listeners\SendEmailVerificationNotification which is registered in the App\Providers\EventServiceProvider:
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
]
];
This listener checks if the $user, which is passed as a parameter to new Registered($user = $this->create($request->all())) in the Laravel default authentication App\Http\Controllers\Auth\RegisterController, is an instance of Illuminate\Contracts\Auth\MustVerifyEmail which is the trait that Laravel suggest to use in the App\User Model when you want to provide default email verification and check also that $user is not already verified. If all that passes it will call the sendEmailVerificationNotification method on that user:
if ($event->user instanceof MustVerifyEmail && !$event->user->hasVerifiedEmail()) {
$event->user->sendEmailVerificationNotification();
}
In my Laravel application, i have several policies working, but one will not work.
Controller
public function store(Project $project, CreateActionRequest $request)
{
$this->authorize('store', $project);
Action::create([
'name' => $request->name,
]);
return redirect()->route('projects.show', $project->id)->withSuccess('Massnahme erfolgreich gespeichert');
}
Policy
namespace App\Policies\Project;
use App\Models\Project\Project;
use App\Models\User;
use App\Models\Project\Action;
use Illuminate\Auth\Access\HandlesAuthorization;
class ActionPolicy
{
use HandlesAuthorization;
public function store(User $user, Project $project)
{
return $user->company_id === $project->company_id;
}
}
AuthServiceProvider
protected $policies = [
'App\Models\User' => 'App\Policies\CompanyAdmin\UserPolicy',
'App\Models\Company' => 'App\Policies\CompanyAdmin\CompanyPolicy',
'App\Models\Team' => 'App\Policies\CompanyAdmin\TeamPolicy',
'App\Models\Department' => 'App\Policies\CompanyAdmin\DepartmentPolicy',
'App\Models\Location' => 'App\Policies\CompanyAdmin\LocationPolicy',
'App\Models\Division' => 'App\Policies\CompanyAdmin\DivisionPolicy',
'App\Models\Costcenter' => 'App\Policies\CompanyAdmin\CostcenterPolicy',
'App\Models\Workplace' => 'App\Policies\CompanyAdmin\WorkplacePolicy',
'App\Models\Product' => 'App\Policies\CompanyAdmin\ProductPolicy',
'App\Models\Project\Action' => 'App\Policies\Project\ActionPolicy',
'App\Models\Project\Project' => 'App\Policies\Project\ProjectPolicy',
];
CreateActionRequest
namespace App\Http\Requests\Project;
use Illuminate\Foundation\Http\FormRequest;
class CreateActionRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|min:3',
];
}
}
All policies are working except ActionPolicy and ProjectPolicy.
I added in the policy a __construct() method to check if the policy is called. But ActionPolicy and ProjectPolicy are not working.
How can i search the error? I tried with dd() but i got only allways the message: This action is unauthorized
Since you are injecting CreateActionRequest instead of Request that means you are defining your own set of rules to authorize the FormRequest which comes inside of your method. Further it means that you gotta define a few rules which the "FormRequest" has to pass in order to EVEN reach your controller, this is a nice concept that I like about Laravel since the code is not centralized, but rather spread and every layer has it's own responsibility. Now, you don't have to call any method from your CreateActionRequest nor you have to write any code regarding that class in your controller, because Laravel runs authorize method by default before allowing the Request to reach your controller, before running authorizemethod in your CreateActionRequest it runs rules method which verifies that all the given fields pass the expressions you assigned them, so the execution is something like this CreateActionRequest => rules => authorize => IF(authorized) Controller ELSE Not authorized, hope that makes sense. In order to fix your code:
1.) Remove $this->authorize('store', $project);
This will allow you to pass not authorized error in case your name passes the truth test inside of rules method inside of your CreateActionRequest. If you wish to utilize your Action Policy you will need to hook up your custom Request(CreateActionRequest) with it and this is how:
public function authorize()
{
$store = $this->route('project');
//The above line will return Project object if your mapping is correct
//If it's not it will return the value you passed to your route for {project}
return $this->user() && $this->user()->can('store', $store);
}
EDIT:
Here is the link where you can see how to properly authorize and connect policy with CreateActionRequest
Do you have all your controller methods defined with the Request object last?
public function store(Project $project, CreateActionRequest $request)
The Request object should be the first parameter in the methods signature:
public function store(CreateActionRequest $request, Project $project)
Dependency Injection & Route Parameters
If your controller method is also expecting input from a route parameter you should list your route parameters after your other dependencies.
Most Laravel authorization mechanisms have identical method signatures allowing them to work across varying classes.
I write a mailable to send email when user registers,I do it following the document(https://laravel.com/docs/5.5/mail):
first,generating a mailable:
php artisan make:mail UserRegistered
Ok,thus there is a UserRegistered.php file in the app/Mail directory,and I write the build() method like this:
public function build()
{
return $this->view('emails.activate-user')
->with([
'name' => $this->user->name,
'url' => route('activateUser',['token'=>$this->user->confirmation_token])
]);
}
The email can be sent successfully,the title of the email is User Registered,I want to customize the title ,how to do it?
You have to use subject method
public function build()
{
return $this->view('emails.activate-user')
->subject("My mail title")
->with([
'name' => $this->user->name,
'url' => route('activateUser',['token'=>$this->user->confirmation_token])
]);
}
Or update your mails class's constructor
public function __construct()
{
$this->subject('Sample title');
}
If you want to change mail title you need to change it in .env file. Same Like as given below:
You need to change it here for mail title.
And if you just want to change only subject then you can you use subject() function while sending mail to add you subject.
For Example:
public function build()
{
return $this->subject('Reset Password')
->view('emails.forgotpass');
}
and the final result will be like this where my APP_NAME is Laravel.
Result 1:
Result 2:
i can't send email with user address as FROM and Reply To
In the FormRequest :
public function persist()
{
$reservation = Resa::create(
$this->only(['nom', 'email', 'phone', 'formule', 'date_arr', 'date_ret', 'nb_adu', 'nb_enf', 'lemessage'])
);
Mail::to('contact#cotiga.fr')
->from($reservation->email, $reservation->nom)
->replyTo($reservation->email, $reservation->nom)
->send(new Reservation($reservation));
}
I have the error :
FatalThrowableError in ReservationForm.php line 48:
Call to undefined method Illuminate\Mail\PendingMail::from()
I tried full of possibility, but I can not change the field FROM and REPLYTO
Can you help me ?
Thank's
The Mail Facade does not implement the replyTo() method anymore. Instead this method has moved to the Mailable class itself. Official documentation proposes to use the build() method to setup the Mailable, however this is not always convenient (eg the replyTo field might be different each time)
However if you still want to use a similar syntax you can use:
$mailable = new myMailableClass;
$mailable->replyTo('reply#to.com');
Mail::to('email#tocom')
->send($mailable);
For a complete list of available methods on the Mailable class see the Mailable Documentation
In Laravel 5.4 Mailables, the replyTo, subject, cc, bcc and others can be set inside the mailable in the build method. This is also true for the to which can also be set on the Mail facade.
Here is a simple example of a contact form mailable using an array of attributes:
You may use the to static method directly on the Mail facade, but as an example, we're going to set it inside the mailable:
Mail::send(new ContactCompany($attributes));
Then set the replyTo inside the build method:
class ContactCompany extends Mailable
{
use Queueable, SerializesModels;
public $attributes;
/**
* Create a new message instance.
*
* #param $attributes
*/
public function __construct($attributes)
{
$this->attributes = $attributes;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$this->to($this->attributes['departmentEmail'], config('app.name'));
$this->replyTo($this->attributes['email'], $this->attributes['name']);
$this->subject(sprintf("New contact message from %s", $this->attributes['name']));
return $this->markdown('emails.contact.company');
}
}
Please, note that Mail::alwaysFrom() and Mail::alwaysReplyTo() can be used before Mail::send() to set the from and replyTo of all emails, so make sure to use them with care.
The preferred method of sending emails are now mailables and you can set from and reply to using from() or replyTo() methods.
However using plain Mail facades you should try to use alwaysFrom and alwaysReplyTo methods. However after sending such e-mail you should set again previous values to be sure no other emails will be impacted by this change.
But looking at method names it might be not the best solution so better is to look at mailables and use them to send e-mails in latest Laravel releases.
Problem resolved.
I edit app>Mail>Reservation.php
public function build()
{
// return $this->markdown('emails.reservation-email');
return $this->from($this->reservation->email)->markdown('emails.reservation-email');
}
app>Http>Request>ReservationForm.php
public function persist()
{
$reservation = Resa::create(
$this->only(['nom', 'email', 'phone', 'formule', 'date_arr', 'date_ret', 'nb_adu', 'nb_enf', 'lemessage'])
);
Mail::to('contact#cotiga.fr')->send(new Reservation($reservation));
}