Laravel 7 | Some recipients receive empty emails - laravel

I have an laravel 7 application and use smtp with google services to send my emails.
However some clients receive the emails with attachments, but no body. The content of the email is completely blank. Most mail platforms (hotmail, outlook, gmail, mail on mac) receive the complete email. It's just some mail providers receive the email without a body.
I believe this might have to do with some security measures or not supporting HTML emails.
How can I ensure that also these clients receive my emails?
I use .blade.php files to send my emails.
example of one of my email files:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class CandidateMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($message_details)
{
//
$this->message_details = $message_details;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$email = $this->view('mail/candidate')
->subject($this->message_details['subject'])
->with(['message_details' => $this->message_details]);
if ($this->message_details['attachments']) {
$email->attachFromStorage($this->message_details['attachments']);
}
return $email;
}
}
Fix for outlook (desktop).
replaced my divs with table/tr/td. Now email content is displayed to clients with outlook (desktop).

you had to build your constructor the variable $message_details does not return anything,
public $message_details = "";

Need to declare public property public $message_details here details
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class CandidateMail extends Mailable
{
use Queueable, SerializesModels;
public $message_details;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($message_details)
{
//
$this->message_details = $message_details;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$email = $this->view('mail/candidate')
->subject($this->message_details['subject'])
->with(['message_details' => $this->message_details]);
if ($this->message_details['attachments']) {
$email->attachFromStorage($this->message_details['attachments']);
}
return $email;
}
}

Related

How to add a mailing feature on laravel 8

I am taking over a project and a client wants me to add a mailing feature like a gmail with inbox, sent messages and the user can also reply to emails from outside the system and the people receiving it can also reply. I have basic knowledge on laravel but this is my first time creating a feature like this can anyone give a stepping stone. This project has a VUE.js as a front end and a laravel as an API
Step -1: Create a Mail using,
php artisan make:mail MailName
Check the file MailName.php inside App/Mail/ directory
Step - 2: Create a function to send the email with the requested data.
public function sendMail(Request $request){
$data = [
'value1'=> $request->value1,
'value2'=> $request->value2,
'value3'=> $request->value3
];
//You can add any function like storing the values into db.
if(someconditions){
\Mail::to('emailid#domainname.com')->send(new MailName($data));
return back()->with('success', 'Email has been sent successfully!');
}
else
{
return back()->with('error', 'Something went wrong!');
}
}
Step - 3: Open the App/Mail/MailName.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use Illuminate\Mail\Mailables\Address;
//You can include your model here.
class DeleteResponseMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $data;
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*
* #return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
from: new Address('fromemail#somedomain.com', 'From Email Name'),
replyTo: [
new Address('admin#yourdomain.com', 'Your email name'),
],
subject: 'Email Subject',
);
}
/**
* Get the message content definition.
*
* #return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.mail',
);
}
/**
* Get the attachments for the message.
*
* #return array
*/
public function attachments()
{
return [];
}
}
Step - 4: Create mail.blade.php under resources/views/emails
Hi $data['value1'],
We have received your application. Thanks!
Step - 5: Open your .env file and add the email configurations.
MAIL_MAILER=enteryourmailerhere (ex.smtp)
MAIL_HOST=enteryourmailhosthere (ex.smtp.gmail.com)
MAIL_PORT=entertheport (ex. 25)
MAIL_USERNAME=emailid#yourdomain.com
MAIL_PASSWORD=emailpassword
MAIL_ENCRYPTION=""
MAIL_FROM_ADDRESS="fromemail#yourdomain.com"
MAIL_FROM_NAME="${APP_NAME}"
That's all! It should work.

Laravel 7 queued email very slow with attachment but fast without

I use Laravel 7 queues / jobs to send a newsletter to multiple addresses and it works well and rather fast. But when I send a single email with attachment (22ko PDF), it takes nearly 3 - 5 minutes to get through. Any clues? I use database driver and Mailgun API.
How can I see if the slow process time is from Laravel app or Mailgun or else?
I tried to use SendEmailJob::dispatchNow($data); but it does not speed up the process.
app\Http\controllers/EmailController.php
App\EmailController
use App\Job\SendEmailJob;
public function send()
{
$data = array(
'from_name'=>from_name',
'from_email'=>'admin#domain.com',
'to_name'=>$user->firstname." ".$user->name,
'to_email'=>$user->email,
'subject'=>'This is test email',
'reply_to'=>noreply#domain.com,
'model'=>$invoice,
'locale'=>app()->getLocale(),
'user'=>$user,
'view'=>'emails.invoice',
'filefullpath'=>$fullfilepath,
);
SendEmailJob::dispatch($data);
}
App\Jobs\SendEmailJob.php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Mail\SendView;
use Mail;
class SendEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $data;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = new SendView($this->data);
$email->replyTo($this->data['reply_to']);
$email->subject($this->data['subject']);
if(isset($this->data['filefullpath']))
{
$email->attach($this->data['filefullpath']);
}
Mail::to($this->data['to_email'], $this->data['to_name'])->send($email);
}
}
App\Mail\SendView.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendView extends Mailable
{
use Queueable, SerializesModels;
protected $data;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$view = $this->data['view'];
$user = $this->data['user'];
$model = $this->data['model'];
$locale = $this->data['locale'];
$array = $this->data['array'];
return $this->view($view, compact('user', 'model','locale','array'));
}
}
Please help! Thanks.

Laravel Email Verification Template Location

I have been reading from the documentation about the new feature of laravel the email verification. Where can I locate the email template that is sent to the user? It does not show here: https://laravel.com/docs/5.7/verification#after-verifying-emails
Laravel uses this method of VerifyEmail notification class for send email:
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable);
}
return (new MailMessage)
->subject(Lang::getFromJson('Verify Email Address'))
->line(Lang::getFromJson('Please click the button below to verify your email address.'))
->action(
Lang::getFromJson('Verify Email Address'),
$this->verificationUrl($notifiable)
)
->line(Lang::getFromJson('If you did not create an account, no further action is required.'));
}
Method in source code.
If you wanna use your own Email template, you can extend Base Notification Class.
1) Create in app/Notifications/ file VerifyEmail.php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Lang;
use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;
class VerifyEmail extends VerifyEmailBase
{
// use Queueable;
// change as you want
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable);
}
return (new MailMessage)
->subject(Lang::getFromJson('Verify Email Address'))
->line(Lang::getFromJson('Please click the button below to verify your email address.'))
->action(
Lang::getFromJson('Verify Email Address'),
$this->verificationUrl($notifiable)
)
->line(Lang::getFromJson('If you did not create an account, no further action is required.'));
}
}
2) Add to User model:
use App\Notifications\VerifyEmail;
and
/**
* Send the email verification notification.
*
* #return void
*/
public function sendEmailVerificationNotification()
{
$this->notify(new VerifyEmail); // my notification
}
Also if you need blade template:
laravel will generate all of the necessary email verification views
when the make:auth command is executed. This view is placed in
resources/views/auth/verify.blade.php. You are free to customize
this view as needed for your application.
Source.
Answer in comment already. Sent by the toMail() method.
vendor\laravel\framework\src\Illuminate\Auth\Notifications\VerifyEmail::toMail();
For template structure and appearance; take a look at this locations also and you can also publish to modify the template:
\vendor\laravel\framework\src\Illuminate\Notifications\resources\views\email.blade.php
\vendor\laravel\framework\src\Illuminate\Mail\resources\views\
To publish those locations:
php artisan vendor:publish --tag=laravel-notifications
php artisan vendor:publish --tag=laravel-mail
After running this command, the mail notification templates will be located in the resources/views/vendor directory.
Colors and style are controlled by the CSS file in resources/views/vendor/mail/html/themes/default.css
Also, if you want to translate standard mail VerifyEmail (or other where use Lang::fromJson(...)), you need create new json file in resources/lang/ and name it ru.json, for example.
It may contain (resources/lang/ru.json) text below and must be valid.
{
"Verify Email Address" : "Подтверждение email адреса"
}
Actually they do not use any blade or template files. They create notifications and write code for it in notifications.
Look I do that very easy
do the following steps :
In Route File
Auth::routes(['verify' => true]);
In AppServiceProvider.php File
namespace App\Providers;
use App\Mail\EmailVerification;
use Illuminate\Support\ServiceProvider;
use View;
use URL;
use Carbon\Carbon;
use Config;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Notifications\Messages\MailMessage;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
// Override the email notification for verifying email
VerifyEmail::toMailUsing(function ($notifiable){
$verifyUrl = URL::temporarySignedRoute('verification.verify',
\Illuminate\Support\Carbon::now()->addMinutes(\Illuminate\Support\Facades
\Config::get('auth.verification.expire', 60)),
[
'id' => $notifiable->getKey(),
'hash' => sha1($notifiable->getEmailForVerification()),
]
);
return new EmailVerification($verifyUrl, $notifiable);
});
}
}
Now Create EmailVerification With Markdown
php artisan make:mail EmailVerification --markdown=emails.verify-email
Edit The EmailVerrification as you want and the blade file
class EmailVerification extends Mailable
{
use Queueable, SerializesModels;
public $verifyUrl;
protected $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($url,$user)
{
$this->verifyUrl = $url;
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$address = 'mymail#gmail.com';
$name = 'Name';
$subject = 'verify Email';
return $this->to($this->user)->subject($subject)->from($address, $name)->
markdown('emails.verify',['url' => $this->verifyUrl,'user' => $this->user]);
}
}
in the blade file change the design as you want and use verifyUrl to display the verification link and $user to display user information
thanks, happy coding :)
vendor\laravel\framework\src\Illuminate\Mail\resources\views\html
You will find the Laravel default email template in this file location.
If a notification supports being sent as an email, you should define a toMail method on the notification class. This method will receive a $notifiable entity and should return a Illuminate\Notifications\Messages\MailMessage instance. Mail messages may contain lines of text as well as a "call to action".
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
You can use the laravel e-mail builder as documented here: https://laravel.com/docs/5.8/notifications#mail-notifications. Laravel will take care of the e-mail view.

laravel job/notification failing

I am trying to set up a contact form on my site whereby when someone clicks send, then a job is run and in that job, a notification is sent to all admin users. I keep getting this error in my failed jobs table though:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Contact]. in /var/www/html/leonsegal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:412
I have been all over my code and I can't see what I have done wrong. Would anyone be able to help please?
Here is my controller:
<?php
namespace App\Http\Controllers;
use App\Contact;
use App\Jobs\SendContactJob;
class ContactController extends Controller
{
/**
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function create()
{
return view('contact');
}
public function store()
{
request()->validate([
'name' => 'required|max:255',
'email' => 'required|email|unique:contacts|max:255',
'message' => 'required|max:2000',
]);
$contact = Contact::create(
request()->only([
'name',
'email',
'message',
])
);
SendContactJob::dispatch($contact);
return back()->with('success', 'Thank you, I will be in touch as soon as I can');
}
}
my job:
<?php
namespace App\Jobs;
use App\Contact;
use App\Notifications\SendContactNotification;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Notification;
class SendContactJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $contact;
/**
* Create a new job instance.
*
* #param Contact $contact
*/
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$users = User::all()
->where('admin', 1)
->where('approved', 1);
Notification::send($users, new SendContactNotification($this->contact));
}
}
my notification:
<?php
namespace App\Notifications;
use App\Contact;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class SendContactNotification extends Notification implements ShouldQueue
{
use Queueable;
protected $contact;
/**
* Create a new notification instance.
*
* #param $contact
*/
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line($this->contact->name)
->line($this->contact->email)
->line($this->contact->message);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
The weird thing is that when I run a die dump in the handle method of the job, it never fires, but the artisan queue worker says it was processed correctly but the subsequent notification is where it is failing. I am not sure why that handle method in the job wouldn't be firing.
I have set my .env file to database queue driver.
I thought it might be that I didn't import the contact model, but you can see I have.
Any help would be appreciated.
Could be that because both the job and the notification are queued, the contact could be getting 'lost in transit' so to speak. try making the job non queueable, and only queue the notification (or the other way around). Or scrap the job altogether and just send the notification from the controller.
Did you check on your model path? Coz for newer laravel the path should be
use App\Models\Contact;

Keep PHPMailler connection alive over Laravel's queue

I want to send many emails.
Currently I write basic code use PHPMailler to send mail using queue. It works, but everytime new queue is run, it have to connect to SMTP again, so i get bad perfomance.
I find SMTPKeepAlive property on PHPMailler documentation:
$phpMailer = New PHPMailer();
$phpMailer->SMTPKeepAlive = true;
Is it imposible and how to keep $phpMailler object for next queue? So PHPMailler have not to connect again by using previous connection.
If you are using Laravel then you have to use Laravel's feature inbuilt.
Please find below documents:
https://laravel.com/docs/5.6/mail
Please find a piece of code for send mail and adding in a queue:
use App\Mail\EmailVerifyMail;
\Mail::queue(new EmailVerifyMail($users));
EmailVerifyMail.php
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class EmailVerifyMail extends Mailable
{
use Queueable, SerializesModels;
public $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$this->to($this->user)->subject(__('mail.subjects.verification_link', ['USERNAME' => $this->user->name]));
return $this->view('mails/emailVerify', ['user' => $this->user]);
}
}

Resources